Add device emulation for DS17x85 series of MC146818-compatible RTCs with additional features

This commit is contained in:
AJR 2019-08-14 09:10:46 -04:00
parent e9b55b8155
commit 83e63dacf4
13 changed files with 667 additions and 221 deletions

View File

@ -992,6 +992,18 @@ if (MACHINES["DS1386"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/machine/ds17x85.h,MACHINES["DS17X85"] = true
---------------------------------------------------
if (MACHINES["DS17X85"]~=null) then
files {
MAME_DIR .. "src/devices/machine/ds17x85.cpp",
MAME_DIR .. "src/devices/machine/ds17x85.h",
}
end
---------------------------------------------------
--
--@src/devices/machine/ds1994.h,MACHINES["DS1994"] = true

View File

@ -447,6 +447,7 @@ MACHINES["DS1205"] = true
MACHINES["DS1302"] = true
--MACHINES["DS1315"] = true
--MACHINES["DS1386"] = true
MACHINES["DS17X85"] = true
MACHINES["DS1994"] = true
MACHINES["DS2401"] = true
MACHINES["DS2404"] = true

View File

@ -454,6 +454,7 @@ MACHINES["DP8573"] = true
MACHINES["DS1302"] = true
MACHINES["DS1315"] = true
MACHINES["DS1386"] = true
MACHINES["DS17X85"] = true
MACHINES["DS2401"] = true
MACHINES["DS2404"] = true
MACHINES["DS75160A"] = true

View File

@ -19,7 +19,7 @@ ds12885_device::ds12885_device(const machine_config &mconfig, device_type type,
{
}
int ds12885_device::get_timer_bypass()
int ds12885_device::get_timer_bypass() const
{
if( !( m_data[REG_A] & REG_A_DV0 ) ) //DV0 must be 0 for timekeeping
{

View File

@ -17,8 +17,8 @@ public:
protected:
ds12885_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
virtual int data_size() override { return 128; }
virtual int get_timer_bypass() override;
virtual int data_size() const override { return 128; }
virtual int get_timer_bypass() const override;
};
// device type definition
@ -37,7 +37,7 @@ public:
void write_extended(offs_t offset, uint8_t data);
protected:
virtual int data_size() override { return 256; }
virtual int data_size() const override { return 256; }
};
// device type definition

View File

@ -0,0 +1,286 @@
// license:BSD-3-Clause
// copyright-holders:AJR
/**********************************************************************
Dallas DS17x85/DS17x87 Real Time Clocks with extended NVSRAM
These MC146818-compatible RTCs overlay the last 64 bytes of user
RAM (not provided by the MC146818) with a second page of registers,
including a Y2K-updated century count and registers for indirectly
accessing extended SRAM which is backed with a separate auxiliary
battery power input.
The DS1685 and DS17x85 use conventional PDIP/SO/TSOP packages,
while the DS1687 and DS17x87 integrate battery, oscillator and chip
into one of Dallas's trademark EDIPs. They are indistinguishable
from the perspective of software.
Currently unemulated features include:
- Kickstart input
- Date alarm wakeup
- Increment in progress flag
- RAM clear function (software-enabled, hardware-triggered)
- 32.768 kHz frequency option for SQW output
**********************************************************************/
#include "emu.h"
#include "ds17x85.h"
#define VERBOSE 0
#include "logmacro.h"
// device type definitions
DEFINE_DEVICE_TYPE(DS1685, ds1685_device, "ds1685", "DS1685 RTC")
DEFINE_DEVICE_TYPE(DS1687, ds1687_device, "ds1687", "DS1687 RTC")
DEFINE_DEVICE_TYPE(DS17285, ds17285_device, "ds17285", "DS17285 RTC")
DEFINE_DEVICE_TYPE(DS17287, ds17287_device, "ds17287", "DS17287 RTC")
DEFINE_DEVICE_TYPE(DS17485, ds17485_device, "ds17485", "DS17485 RTC")
DEFINE_DEVICE_TYPE(DS17487, ds17487_device, "ds17487", "DS17487 RTC")
DEFINE_DEVICE_TYPE(DS17885, ds17885_device, "ds17885", "DS17885 RTC")
DEFINE_DEVICE_TYPE(DS17887, ds17887_device, "ds17887", "DS17887 RTC")
//-------------------------------------------------
// ds17x85_device - constructor
//-------------------------------------------------
ds17x85_device::ds17x85_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 model, u32 extram_size)
: mc146818_device(mconfig, type, tag, owner, clock)
, m_model(model)
, m_extram_size(extram_size)
, m_smi_stack1(0)
{
m_century_index = REG_EXT_CENTURY;
}
//-------------------------------------------------
// ds1685_device - constructor
//-------------------------------------------------
ds1685_device::ds1685_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: ds17x85_device(mconfig, DS1685, tag, owner, clock, 0x71, 128)
{
}
//-------------------------------------------------
// ds1687_device - constructor
//-------------------------------------------------
ds1687_device::ds1687_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: ds17x85_device(mconfig, DS1687, tag, owner, clock, 0x71, 128)
{
}
//-------------------------------------------------
// ds17285_device - constructor
//-------------------------------------------------
ds17285_device::ds17285_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: ds17x85_device(mconfig, DS17285, tag, owner, clock, 0x72, 2048)
{
}
//-------------------------------------------------
// ds17287_device - constructor
//-------------------------------------------------
ds17287_device::ds17287_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: ds17x85_device(mconfig, DS17287, tag, owner, clock, 0x72, 2048)
{
}
//-------------------------------------------------
// ds17485_device - constructor
//-------------------------------------------------
ds17485_device::ds17485_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: ds17x85_device(mconfig, DS17485, tag, owner, clock, 0x74, 4096)
{
}
//-------------------------------------------------
// ds17487_device - constructor
//-------------------------------------------------
ds17487_device::ds17487_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: ds17x85_device(mconfig, DS17487, tag, owner, clock, 0x74, 4096)
{
}
//-------------------------------------------------
// ds17885_device - constructor
//-------------------------------------------------
ds17885_device::ds17885_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: ds17x85_device(mconfig, DS17885, tag, owner, clock, 0x78, 8192)
{
}
//-------------------------------------------------
// ds17887_device - constructor
//-------------------------------------------------
ds17887_device::ds17887_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: ds17x85_device(mconfig, DS17887, tag, owner, clock, 0x78, 8192)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void ds17x85_device::device_start()
{
mc146818_device::device_start();
save_item(NAME(m_smi_stack1));
}
//-------------------------------------------------
// nvram_default - called to initialize NVRAM to
// its default state
//-------------------------------------------------
void ds17x85_device::nvram_default()
{
mc146818_device::nvram_default();
if (!m_region.found())
{
// initialize read-only model number and 64-bit serial number
m_data[REG_EXT_MODEL] = m_model;
m_data[REG_EXT_SERIAL1] = 0x4d;
m_data[REG_EXT_SERIAL2] = 0x41;
m_data[REG_EXT_SERIAL3] = 0x4d;
m_data[REG_EXT_SERIAL4] = 0x45;
m_data[REG_EXT_SERIAL5] = 0x64;
m_data[REG_EXT_SERIAL6] = 0x76;
m_data[REG_EXT_SERIAL_CRC] = 0xf8;
}
}
//---------------------------------------------------------------
// get_timer_bypass - get main clock divisor based on A register
//---------------------------------------------------------------
int ds17x85_device::get_timer_bypass() const
{
int bypass;
// DV0 is used for bank switching only
switch (m_data[REG_A] & (REG_A_DV2 | REG_A_DV1))
{
case REG_A_DV1:
bypass = 7;
break;
case REG_A_DV2 | REG_A_DV1:
bypass = 22;
break;
default:
// TODO: other combinations of divider bits disable the oscillator
bypass = 22;
break;
}
return bypass;
}
//---------------------------------------------------------------
// internal_set_address - latch address on ALE
//---------------------------------------------------------------
void ds17x85_device::internal_set_address(uint8_t address)
{
// push previous address onto SMI recovery stack
m_data[REG_EXT_SMI_STACK3] = m_data[REG_EXT_SMI_STACK2];
m_data[REG_EXT_SMI_STACK2] = m_smi_stack1;
m_smi_stack1 = m_index | ((m_data[REG_A] & REG_A_DV0) ? 0x80 : 0x00);
mc146818_device::internal_set_address(address);
}
//---------------------------------------------------------------
// internal_read - read internal data
//---------------------------------------------------------------
uint8_t ds17x85_device::internal_read(offs_t offset)
{
if (offset >= 0x40 && (m_data[REG_A] & REG_A_DV0))
{
offset += 0x40;
switch (offset)
{
case REG_EXT_4A:
return m_data[offset] | REG_EXT_4A_VRT2;
case REG_EXT_RAM_DATA:
LOG("%s: Reading from extended RAM at %04X\n", machine().describe_context(),
m_data[REG_EXT_RAM_ADDRL] | offs_t(m_data[REG_EXT_RAM_ADDRH]) << 8);
offset = REG_EXT_RAM_BASE + (m_data[REG_EXT_RAM_ADDRL] | offs_t(m_data[REG_EXT_RAM_ADDRH]) << 8) % m_extram_size;
if ((m_data[REG_EXT_4A] & REG_EXT_4A_BME) && !machine().side_effects_disabled())
{
m_data[REG_EXT_RAM_ADDRL]++;
if (m_data[REG_EXT_RAM_ADDRL] == 0 && m_extram_size > 256)
m_data[REG_EXT_RAM_ADDRH]++;
}
break;
default:
break;
}
}
return mc146818_device::internal_read(offset);
}
//---------------------------------------------------------------
// internal_write - write internal data
//---------------------------------------------------------------
void ds17x85_device::internal_write(offs_t offset, uint8_t data)
{
if (!machine().side_effects_disabled())
m_data[REG_EXT_WRITE_COUNTER]++;
if (offset >= 0x40 && (m_data[REG_A] & REG_A_DV0))
{
offset += 0x40;
switch (offset)
{
case REG_EXT_RAM_DATA:
LOG("%s: Writing %02X to extended RAM at %04X\n", machine().describe_context(),
data, m_data[REG_EXT_RAM_ADDRL] | offs_t(m_data[REG_EXT_RAM_ADDRH]) << 8);
offset = REG_EXT_RAM_BASE + (m_data[REG_EXT_RAM_ADDRL] | offs_t(m_data[REG_EXT_RAM_ADDRH]) << 8) % m_extram_size;
if ((m_data[REG_EXT_4A] & REG_EXT_4A_BME) && !machine().side_effects_disabled())
{
m_data[REG_EXT_RAM_ADDRL]++;
if (m_data[REG_EXT_RAM_ADDRL] == 0 && m_extram_size > 256)
m_data[REG_EXT_RAM_ADDRH]++;
}
break;
case REG_EXT_CENTURY:
case REG_EXT_DATE_ALARM: // TODO: unimplemented
case REG_EXT_4A: // TODO: mostly unimplemented
case REG_EXT_4B: // TODO: unimplemented
case REG_EXT_RAM_ADDRL:
break;
case REG_EXT_RAM_ADDRH:
if (m_extram_size <= 256)
{
logerror("%s: RTC extended addressing uses one byte only\n", machine().describe_context());
return;
}
break;
default:
logerror("%s: Write to reserved/read-only bank 1 register %02X\n", machine().describe_context(), offset - 0x40);
return;
}
}
mc146818_device::internal_write(offset, data);
}

View File

@ -0,0 +1,192 @@
// license:BSD-3-Clause
// copyright-holders:AJR
/**********************************************************************
Dallas DS17x85/DS17x87 Real Time Clocks with extended NVSRAM
***********************************************************************
_____ _____
/PWR 1 |* \_/ | 24 Vcc
(DS17x87: N.C.) X1 2 | | 23 SQW
(DS17x87: N.C.) X2 3 | | 22 Vbaux
AD0 4 | | 21 /RCLR
AD1 5 | DS168x | 20 Vbat (DS17x87: N.C.)
AD2 6 | DS1728x | 19 /IRQ
AD3 7 | DS1748x | 18 /KS
AD4 8 | DS1788x | 17 /RD
AD5 9 | | 16 GND (DS17x87: N.C.)
AD6 10 | | 15 /WR
AD7 11 | | 14 ALE
GND 12 |_____________| 13 /CS
**********************************************************************/
#ifndef MAME_MACHINE_DS17X85_H
#define MAME_MACHINE_DS17X85_H 1
#pragma once
#include "mc146818.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> ds17x85_device
class ds17x85_device : public mc146818_device
{
protected:
enum
{
REG_EXT_MODEL = 0x40 + 0x40,
REG_EXT_SERIAL1 = 0x40 + 0x41,
REG_EXT_SERIAL2 = 0x40 + 0x42,
REG_EXT_SERIAL3 = 0x40 + 0x43,
REG_EXT_SERIAL4 = 0x40 + 0x44,
REG_EXT_SERIAL5 = 0x40 + 0x45,
REG_EXT_SERIAL6 = 0x40 + 0x46,
REG_EXT_SERIAL_CRC = 0x40 + 0x47,
REG_EXT_CENTURY = 0x40 + 0x48,
REG_EXT_DATE_ALARM = 0x40 + 0x49,
REG_EXT_4A = 0x40 + 0x4a,
REG_EXT_4B = 0x40 + 0x4b,
REG_EXT_SMI_STACK2 = 0x40 + 0x4e,
REG_EXT_SMI_STACK3 = 0x40 + 0x4f,
REG_EXT_RAM_ADDRL = 0x40 + 0x50,
REG_EXT_RAM_ADDRH = 0x40 + 0x51,
REG_EXT_RAM_DATA = 0x40 + 0x53,
REG_EXT_WRITE_COUNTER = 0x40 + 0x5e,
REG_EXT_RAM_BASE = 0x40 + 0x80
};
enum
{
REG_EXT_4A_VRT2 = 0x80,
REG_EXT_4A_INCR = 0x40,
REG_EXT_4A_BME = 0x20,
REG_EXT_4A_PAB = 0x08,
REG_EXT_4A_RF = 0x04,
REG_EXT_4A_WF = 0x02,
REG_EXT_4A_KF = 0x01
};
enum
{
REG_EXT_4B_ABE = 0x80,
REG_EXT_4B_E32k = 0x40,
REG_EXT_4B_CS = 0x20,
REG_EXT_4B_RCE = 0x10,
REG_EXT_4B_PRS = 0x08,
REG_EXT_4B_RIE = 0x04,
REG_EXT_4B_WIE = 0x02,
REG_EXT_4B_KSE = 0x01
};
ds17x85_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 model, u32 extram_size);
// device-specific overrides
virtual void device_start() override;
// device_nvram_interface overrides
virtual void nvram_default() override;
// mc146818_device overrides
virtual int data_size() const override { return REG_EXT_RAM_BASE + m_extram_size; }
virtual int data_logical_size() const override { return 128; }
virtual bool century_count_enabled() const override { return true; }
virtual int get_timer_bypass() const override;
virtual void internal_set_address(uint8_t data) override;
virtual uint8_t internal_read(offs_t offset) override;
virtual void internal_write(offs_t offset, uint8_t data) override;
private:
const u8 m_model;
const u32 m_extram_size;
u8 m_smi_stack1;
};
// ======================> ds1685_device
class ds1685_device : public ds17x85_device
{
public:
// device type constructor
ds1685_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
// ======================> ds1687_device
class ds1687_device : public ds17x85_device
{
public:
// device type constructor
ds1687_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
// ======================> ds17285_device
class ds17285_device : public ds17x85_device
{
public:
// device type constructor
ds17285_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
// ======================> ds17287_device
class ds17287_device : public ds17x85_device
{
public:
// device type constructor
ds17287_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
// ======================> ds17485_device
class ds17485_device : public ds17x85_device
{
public:
// device type constructor
ds17485_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
// ======================> ds17487_device
class ds17487_device : public ds17x85_device
{
public:
// device type constructor
ds17487_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
// ======================> ds17885_device
class ds17885_device : public ds17x85_device
{
public:
// device type constructor
ds17885_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
// ======================> ds17887_device
class ds17887_device : public ds17x85_device
{
public:
// device type constructor
ds17887_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
// device type declarations
DECLARE_DEVICE_TYPE(DS1685, ds1685_device)
DECLARE_DEVICE_TYPE(DS1687, ds1687_device)
DECLARE_DEVICE_TYPE(DS17285, ds17285_device)
DECLARE_DEVICE_TYPE(DS17287, ds17287_device)
DECLARE_DEVICE_TYPE(DS17485, ds17485_device)
DECLARE_DEVICE_TYPE(DS17487, ds17487_device)
DECLARE_DEVICE_TYPE(DS17885, ds17885_device)
DECLARE_DEVICE_TYPE(DS17887, ds17887_device)
#endif // MAME_MACHINE_DS17X85_H

View File

@ -54,12 +54,15 @@ mc146818_device::mc146818_device(const machine_config &mconfig, device_type type
void mc146818_device::device_start()
{
m_data.resize(data_size());
m_data = make_unique_clear<uint8_t[]>(data_size());
m_last_refresh = machine().time();
m_clock_timer = timer_alloc(TIMER_CLOCK);
m_periodic_timer = timer_alloc(TIMER_PERIODIC);
m_write_irq.resolve_safe();
save_pointer(NAME(m_data), data_size());
save_item(NAME(m_index));
}
@ -147,7 +150,20 @@ void mc146818_device::device_timer(emu_timer &timer, device_timer_id id, int par
{
set_month(1);
set_year((get_year() + 1) % 100);
int year = get_year() + 1;
if (year <= 99)
{
set_year(year);
}
else
{
set_year(0);
if (century_count_enabled())
{
set_century((get_century() + 1) % 100);
}
}
}
}
}
@ -181,15 +197,14 @@ void mc146818_device::device_timer(emu_timer &timer, device_timer_id id, int par
void mc146818_device::nvram_default()
{
// populate from a memory region if present
memory_region *region = memregion(DEVICE_SELF);
if (region != nullptr)
if (m_region.found())
{
uint32_t bytes = region->bytes();
uint32_t bytes = m_region->bytes();
if (bytes > data_size())
bytes = data_size();
memcpy(&m_data[0], region->base(), bytes);
memcpy(&m_data[0], m_region->base(), bytes);
}
else
{
@ -237,7 +252,7 @@ void mc146818_device::nvram_write(emu_file &file)
// to_ram - convert value to current ram format
//-------------------------------------------------
int mc146818_device::to_ram(int a)
int mc146818_device::to_ram(int a) const
{
if (!(m_data[REG_B] & REG_B_DM))
return dec_2_bcd(a);
@ -250,7 +265,7 @@ int mc146818_device::to_ram(int a)
// from_ram - convert value from current ram format
//-------------------------------------------------
int mc146818_device::from_ram(int a)
int mc146818_device::from_ram(int a) const
{
if (!(m_data[REG_B] & REG_B_DM))
return bcd_2_dec(a);
@ -259,7 +274,7 @@ int mc146818_device::from_ram(int a)
}
int mc146818_device::get_seconds()
int mc146818_device::get_seconds() const
{
return from_ram(m_data[REG_SECONDS]);
}
@ -269,7 +284,7 @@ void mc146818_device::set_seconds(int seconds)
m_data[REG_SECONDS] = to_ram(seconds);
}
int mc146818_device::get_minutes()
int mc146818_device::get_minutes() const
{
return from_ram(m_data[REG_MINUTES]);
}
@ -279,7 +294,7 @@ void mc146818_device::set_minutes(int minutes)
m_data[REG_MINUTES] = to_ram(minutes);
}
int mc146818_device::get_hours()
int mc146818_device::get_hours() const
{
if (!(m_data[REG_B] & REG_B_24_12))
{
@ -328,7 +343,7 @@ void mc146818_device::set_hours(int hours)
}
}
int mc146818_device::get_dayofweek()
int mc146818_device::get_dayofweek() const
{
return from_ram(m_data[REG_DAYOFWEEK]);
}
@ -338,7 +353,7 @@ void mc146818_device::set_dayofweek(int dayofweek)
m_data[REG_DAYOFWEEK] = to_ram(dayofweek);
}
int mc146818_device::get_dayofmonth()
int mc146818_device::get_dayofmonth() const
{
return from_ram(m_data[REG_DAYOFMONTH]);
}
@ -348,7 +363,7 @@ void mc146818_device::set_dayofmonth(int dayofmonth)
m_data[REG_DAYOFMONTH] = to_ram(dayofmonth);
}
int mc146818_device::get_month()
int mc146818_device::get_month() const
{
return from_ram(m_data[REG_MONTH]);
}
@ -358,7 +373,7 @@ void mc146818_device::set_month(int month)
m_data[REG_MONTH] = to_ram(month);
}
int mc146818_device::get_year()
int mc146818_device::get_year() const
{
return from_ram(m_data[REG_YEAR]);
}
@ -368,6 +383,18 @@ void mc146818_device::set_year(int year)
m_data[REG_YEAR] = to_ram(year);
}
int mc146818_device::get_century() const
{
assert(m_century_index != -1);
return from_ram(m_data[m_century_index]);
}
void mc146818_device::set_century(int century)
{
assert(m_century_index != -1);
m_data[m_century_index] = to_ram(century);
}
//-------------------------------------------------
@ -400,7 +427,7 @@ void mc146818_device::set_base_datetime()
set_year((current_time.year - m_epoch) % 100);
if (m_century_index >= 0)
m_data[m_century_index] = to_ram(current_time.year / 100);
set_century(current_time.year / 100);
}
@ -410,9 +437,7 @@ void mc146818_device::set_base_datetime()
void mc146818_device::update_timer()
{
int bypass;
bypass = get_timer_bypass();
int bypass = get_timer_bypass();
attotime update_period = attotime::never;
attotime update_interval = attotime::never;
@ -452,7 +477,7 @@ void mc146818_device::update_timer()
// get_timer_bypass - get main clock divisor based on A register
//---------------------------------------------------------------
int mc146818_device::get_timer_bypass()
int mc146818_device::get_timer_bypass() const
{
int bypass;
@ -520,7 +545,8 @@ uint8_t mc146818_device::read(offs_t offset)
break;
case 1:
data = read_direct(m_index);
data = internal_read(m_index);
LOG("mc146818_port_r(): offset=0x%02x data=0x%02x\n", m_index, data);
break;
}
@ -528,6 +554,54 @@ uint8_t mc146818_device::read(offs_t offset)
}
uint8_t mc146818_device::read_direct(offs_t offset)
{
offset %= data_logical_size();
if (!machine().side_effects_disabled())
internal_set_address(offset);
uint8_t data = internal_read(offset);
LOG("mc146818_port_r(): offset=0x%02x data=0x%02x\n", offset, data);
return data;
}
//-------------------------------------------------
// write - I/O handler for writing
//-------------------------------------------------
void mc146818_device::write(offs_t offset, uint8_t data)
{
switch (offset)
{
case 0:
internal_set_address(data % data_logical_size());
break;
case 1:
LOG("mc146818_port_w(): offset=0x%02x data=0x%02x\n", m_index, data);
internal_write(m_index, data);
break;
}
}
void mc146818_device::write_direct(offs_t offset, uint8_t data)
{
offset %= data_logical_size();
if (!machine().side_effects_disabled())
internal_set_address(offset);
LOG("mc146818_port_w(): offset=0x%02x data=0x%02x\n", offset, data);
internal_write(offset, data);
}
void mc146818_device::internal_set_address(uint8_t address)
{
m_index = address;
}
uint8_t mc146818_device::internal_read(offs_t offset)
{
uint8_t data = 0;
@ -546,8 +620,11 @@ uint8_t mc146818_device::read_direct(offs_t offset)
// the unused bits b0 ... b3 are always read as 0
data = m_data[REG_C] & (REG_C_IRQF | REG_C_PF | REG_C_AF | REG_C_UF);
// read 0x0c will clear all IRQ flags in register 0x0c
m_data[REG_C] &= ~(REG_C_IRQF | REG_C_PF | REG_C_AF | REG_C_UF);
update_irq();
if (!machine().side_effects_disabled())
{
m_data[REG_C] &= ~(REG_C_IRQF | REG_C_PF | REG_C_AF | REG_C_UF);
update_irq();
}
break;
case REG_D:
@ -560,33 +637,11 @@ uint8_t mc146818_device::read_direct(offs_t offset)
break;
}
LOG("mc146818_port_r(): offset=0x%02x data=0x%02x\n", offset, data);
return data;
}
//-------------------------------------------------
// write - I/O handler for writing
//-------------------------------------------------
void mc146818_device::write(offs_t offset, uint8_t data)
void mc146818_device::internal_write(offs_t offset, uint8_t data)
{
switch (offset)
{
case 0:
m_index = data % data_size();
break;
case 1:
write_direct(m_index, data);
break;
}
}
void mc146818_device::write_direct(offs_t offset, uint8_t data)
{
LOG("mc146818_port_w(): offset=0x%02x data=0x%02x\n", offset, data);
switch (offset)
{
case REG_SECONDS:

View File

@ -27,8 +27,8 @@ public:
// callbacks
auto irq() { return m_write_irq.bind(); }
// The MC146818 doesn't have century support, but when syncing the date & time at startup we can optionally store the century.
void set_century_index(int century_index) { m_century_index = century_index; }
// The MC146818 doesn't have century support (some variants do), but when syncing the date & time at startup we can optionally store the century.
void set_century_index(int century_index) { assert(!century_count_enabled()); m_century_index = century_index; }
// The MC146818 doesn't have UTC support, but when syncing the data & time at startup we can use UTC instead of local time.
void set_use_utc(bool use_utc) { m_use_utc = use_utc; }
@ -62,7 +62,13 @@ protected:
static constexpr unsigned char ALARM_DONTCARE = 0xc0;
static constexpr unsigned char HOURS_PM = 0x80;
virtual int data_size() { return 64; }
virtual int data_size() const { return 64; }
virtual int data_logical_size() const { return data_size(); }
virtual bool century_count_enabled() const { return false; }
virtual void internal_set_address(uint8_t address);
virtual uint8_t internal_read(offs_t offset);
virtual void internal_write(offs_t offset, uint8_t data);
enum
{
@ -120,33 +126,35 @@ protected:
};
// internal helpers
int to_ram(int a);
int from_ram(int a);
int to_ram(int a) const;
int from_ram(int a) const;
void set_base_datetime();
void update_irq();
void update_timer();
virtual int get_timer_bypass();
int get_seconds();
virtual int get_timer_bypass() const;
int get_seconds() const;
void set_seconds(int seconds);
int get_minutes();
int get_minutes() const;
void set_minutes(int minutes);
int get_hours();
int get_hours() const;
void set_hours(int hours);
int get_dayofweek();
int get_dayofweek() const;
void set_dayofweek(int dayofweek);
int get_dayofmonth();
int get_dayofmonth() const;
void set_dayofmonth(int dayofmonth);
int get_month();
int get_month() const;
void set_month(int month);
int get_year();
int get_year() const;
void set_year(int year);
int get_century() const;
void set_century(int year);
optional_memory_region m_region;
// internal state
uint8_t m_index;
std::vector<uint8_t> m_data;
std::unique_ptr<uint8_t[]> m_data;
attotime m_last_refresh;

View File

@ -46,7 +46,7 @@ Some debug tricks (let's test this CPU as more as possible):
#include "emu.h"
#include "cpu/mc68hc11/mc68hc11.h"
#include "machine/nvram.h"
#include "machine/ds17x85.h"
#include "sound/ay8910.h"
#include "video/mc6845.h"
#include "emupal.h"
@ -61,7 +61,10 @@ public:
: driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette") { }
m_palette(*this, "palette"),
m_eeprom(*this, "eeprom")
{
}
void hitpoker(machine_config &config);
@ -74,8 +77,6 @@ private:
std::unique_ptr<uint8_t[]> m_videoram;
std::unique_ptr<uint8_t[]> m_paletteram;
std::unique_ptr<uint8_t[]> m_colorram;
uint8_t m_eeprom_data[0x1000];
uint16_t m_eeprom_index;
DECLARE_READ8_MEMBER(hitpoker_vram_r);
DECLARE_WRITE8_MEMBER(hitpoker_vram_w);
@ -83,19 +84,14 @@ private:
DECLARE_WRITE8_MEMBER(hitpoker_cram_w);
DECLARE_READ8_MEMBER(hitpoker_paletteram_r);
DECLARE_WRITE8_MEMBER(hitpoker_paletteram_w);
DECLARE_READ8_MEMBER(rtc_r);
DECLARE_WRITE8_MEMBER(eeprom_offset_w);
DECLARE_WRITE8_MEMBER(eeprom_w);
DECLARE_READ8_MEMBER(eeprom_r);
DECLARE_READ8_MEMBER(hitpoker_pic_r);
DECLARE_WRITE8_MEMBER(hitpoker_pic_w);
DECLARE_WRITE_LINE_MEMBER(hitpoker_irq);
DECLARE_READ8_MEMBER(irq_clear_r);
virtual void video_start() override;
uint32_t screen_update_hitpoker(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
required_device<mc68hc11_cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
required_shared_ptr<uint8_t> m_eeprom;
void hitpoker_map(address_map &map);
};
@ -193,38 +189,6 @@ WRITE8_MEMBER(hitpoker_state::hitpoker_paletteram_w)
m_palette->set_pen_color(offset, pal5bit(r), pal6bit(g), pal5bit(b));
}
READ8_MEMBER(hitpoker_state::rtc_r)
{
return 0x80; //kludge it for now
}
/* tests 0x180, what EEPROM is this one??? it seems to access up to 4KB */
WRITE8_MEMBER(hitpoker_state::eeprom_offset_w)
{
if (offset == 0)
m_eeprom_index = (m_eeprom_index & 0xf00) | (data & 0xff);
else
m_eeprom_index = (m_eeprom_index & 0x0ff) | (data << 8 & 0xf00);
}
WRITE8_MEMBER(hitpoker_state::eeprom_w)
{
// is 0xbe53 the right address?
m_eeprom_data[m_eeprom_index] = data;
}
READ8_MEMBER(hitpoker_state::eeprom_r)
{
/*** hack to make it boot ***/
int ret = ((m_eeprom_index & 0x1f) == 0x1f) ? 1 : 0;
m_eeprom_index++;
return ret;
/*** ***/
// FIXME: never executed
//return m_eeprom_data[m_eeprom_index & 0xfff];
}
READ8_MEMBER(hitpoker_state::hitpoker_pic_r)
{
@ -259,33 +223,15 @@ READ8_MEMBER(hitpoker_state::test_r)
}
#endif
WRITE_LINE_MEMBER(hitpoker_state::hitpoker_irq)
{
if (state)
m_maincpu->set_input_line(MC68HC11_IRQ_LINE, ASSERT_LINE);
}
READ8_MEMBER(hitpoker_state::irq_clear_r)
{
if (!machine().side_effects_disabled())
m_maincpu->set_input_line(MC68HC11_IRQ_LINE, CLEAR_LINE);
return 0xff;
}
/* overlap empty rom addresses */
void hitpoker_state::hitpoker_map(address_map &map)
{
map(0x0000, 0xbdff).rom();
map(0x0000, 0xb5ff).rom();
map(0xbf00, 0xffff).rom();
map(0x8000, 0xb5ff).rw(FUNC(hitpoker_state::hitpoker_vram_r), FUNC(hitpoker_state::hitpoker_vram_w));
map(0xb600, 0xbdff).ram();
map(0xbe0a, 0xbe0a).portr("IN0");
map(0xbe0c, 0xbe0c).r(FUNC(hitpoker_state::irq_clear_r));
map(0xbe0d, 0xbe0d).r(FUNC(hitpoker_state::rtc_r));
map(0xbe0e, 0xbe0e).portr("IN1");
map(0xbe50, 0xbe51).w(FUNC(hitpoker_state::eeprom_offset_w));
map(0xbe53, 0xbe53).rw(FUNC(hitpoker_state::eeprom_r), FUNC(hitpoker_state::eeprom_w));
map(0xb600, 0xbdff).ram().share("eeprom");
map(0xbe00, 0xbe7f).rw("rtc", FUNC(ds17x85_device::read_direct), FUNC(ds17x85_device::write_direct));
map(0xbe80, 0xbe80).w("crtc", FUNC(mc6845_device::address_w));
map(0xbe81, 0xbe81).w("crtc", FUNC(mc6845_device::register_w));
map(0xbe90, 0xbe91).rw("aysnd", FUNC(ay8910_device::data_r), FUNC(ay8910_device::address_data_w));
@ -320,58 +266,6 @@ static INPUT_PORTS_START( hitpoker )
PORT_DIPSETTING( 0x00, "24KHz" )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_VBLANK("screen")
PORT_START("IN0")
PORT_DIPNAME( 0x01, 0x01, "IN0" )
PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_START("IN1")
PORT_DIPNAME( 0x01, 0x01, "IN1" )
PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_START("DSW1")
PORT_DIPNAME( 0x01, 0x01, "DSW1" )
PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
@ -461,7 +355,8 @@ void hitpoker_state::hitpoker(machine_config &config)
m_maincpu->out_pa_callback().set(FUNC(hitpoker_state::hitpoker_pic_w));
m_maincpu->in_pe_callback().set_constant(0);
NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
ds17x85_device &rtc(DS17487(config, "rtc", 32768));
rtc.irq().set_inputline(m_maincpu, MC68HC11_IRQ_LINE);
/* video hardware */
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
@ -475,7 +370,7 @@ void hitpoker_state::hitpoker(machine_config &config)
crtc.set_screen("screen");
crtc.set_show_border_area(false);
crtc.set_char_width(8);
crtc.out_vsync_callback().set(FUNC(hitpoker_state::hitpoker_irq));
//crtc.out_vsync_callback().set(FUNC(hitpoker_state::hitpoker_irq));
GFXDECODE(config, m_gfxdecode, m_palette, gfx_hitpoker);
PALETTE(config, m_palette).set_entries(0x800);
@ -492,15 +387,18 @@ void hitpoker_state::init_hitpoker()
{
uint8_t *ROM = memregion("maincpu")->base();
// init nvram
subdevice<nvram_device>("nvram")->set_base(m_eeprom_data, sizeof(m_eeprom_data));
ROM[0x1220] = 0x01; //patch eeprom write?
ROM[0x1221] = 0x01;
ROM[0x1222] = 0x01;
ROM[0x10c6] = 0x01;
ROM[0x10c7] = 0x01; //patch the checksum routine
// must match RTC serial number
m_eeprom[3] = 'M';
m_eeprom[2] = 'A';
m_eeprom[1] = 'M';
m_eeprom[0] = 'E';
}
ROM_START( hitpoker )

View File

@ -22,6 +22,7 @@ NOTE: The default Sgi O2 Keyboard (Model No. RT6856T, Part No. 121472-101-B,
#include "emu.h"
#include "cpu/mips/mips3.h"
#include "machine/ds17x85.h"
#include "machine/mace.h"
#include "video/crime.h"
@ -78,8 +79,12 @@ void o2_state::o2(machine_config &config)
m_maincpu->set_force_no_drc(true);
SGI_MACE(config, m_mace, m_maincpu);
m_mace->rtc_read_callback().set("rtc", FUNC(ds17x85_device::read_direct));
m_mace->rtc_write_callback().set("rtc", FUNC(ds17x85_device::write_direct));
SGI_CRIME(config, m_crime, m_maincpu);
DS1687(config, "rtc", 32768);
}
ROM_START( o2 )

View File

@ -55,9 +55,17 @@ DEFINE_DEVICE_TYPE(SGI_MACE, mace_device, "sgimace", "SGI MACE")
mace_device::mace_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, SGI_MACE, tag, owner, clock)
, m_maincpu(*this, finder_base::DUMMY_TAG)
, m_rtc_read_callback(*this)
, m_rtc_write_callback(*this)
{
}
void mace_device::device_resolve_objects()
{
m_rtc_read_callback.resolve_safe(0);
m_rtc_write_callback.resolve_safe();
}
void mace_device::device_start()
{
save_item(NAME(m_isa.m_ringbase_reset));
@ -82,15 +90,12 @@ void mace_device::device_start()
m_timer_msc = timer_alloc(TIMER_MSC);
m_timer_ust->adjust(attotime::never);
m_timer_msc->adjust(attotime::never);
save_item(NAME(m_rtc.m_unknown));
}
void mace_device::device_reset()
{
memset(&m_isa, 0, sizeof(isa_t));
memset(&m_ust_msc, 0, sizeof(ust_msc_t));
memset(&m_rtc, 0, sizeof(rtc_t));
m_timer_ust->adjust(attotime::from_nsec(960), 0, attotime::from_nsec(960));
m_timer_msc->adjust(attotime::from_msec(1), 0, attotime::from_msec(1));
@ -117,7 +122,7 @@ void mace_device::map(address_map &map)
map(0x00330000, 0x0033ffff).rw(FUNC(mace_device::i2c_r), FUNC(mace_device::i2c_w));
map(0x00340000, 0x0034ffff).rw(FUNC(mace_device::ust_msc_r), FUNC(mace_device::ust_msc_w));
map(0x00380000, 0x0039ffff).rw(FUNC(mace_device::isa_ext_r), FUNC(mace_device::isa_ext_w));
map(0x003a0000, 0x003a3fff).rw(FUNC(mace_device::rtc_r), FUNC(mace_device::rtc_w));
map(0x003a0000, 0x003a7fff).rw(FUNC(mace_device::rtc_r), FUNC(mace_device::rtc_w));
}
//**************************************************************************
@ -415,36 +420,20 @@ WRITE64_MEMBER(mace_device::isa_ext_w)
READ64_MEMBER(mace_device::rtc_r)
{
uint64_t ret = 0ULL;
switch (offset)
{
case 0x3f00/8:
ret = m_rtc.m_unknown;
LOGMASKED(LOG_READ_RTC, "%s: MACE: RTC: Unknown Read: %08x = %08x%08x & %08x%08x\n", machine().describe_context(), 0x1f3a0000 + offset*8
, (uint32_t)(ret >> 32), (uint32_t)ret, (uint32_t)(mem_mask >> 32), (uint32_t)mem_mask);
break;
default:
LOGMASKED(LOG_READ_RTC, "%s: MACE: RTC: Unknown Read: %08x = %08x%08x & %08x%08x\n", machine().describe_context()
, 0x1f3a0000 + offset*8, (uint32_t)(ret >> 32), (uint32_t)ret, (uint32_t)(mem_mask >> 32), (uint32_t)mem_mask);
break;
}
uint64_t ret = m_rtc_read_callback(offset >> 5);
LOGMASKED(LOG_READ_RTC, "%s: MACE: RTC Read: %08x (register %02x) = %08x%08x & %08x%08x\n", machine().describe_context()
, 0x1f3a0000 + offset*8, offset >> 5, (uint32_t)(ret >> 32), (uint32_t)ret, (uint32_t)(mem_mask >> 32), (uint32_t)mem_mask);
return ret;
}
WRITE64_MEMBER(mace_device::rtc_w)
{
switch (offset)
{
case 0x3f00/8:
LOGMASKED(LOG_WRITE_RTC, "%s: MACE: RTC: Unknown Write: %08x = %08x%08x & %08x%08x\n", machine().describe_context(), 0x1f3a0000 + offset*8
, (uint32_t)(data >> 32), (uint32_t)data, (uint32_t)(mem_mask >> 32), (uint32_t)mem_mask);
m_rtc.m_unknown = data;
break;
default:
LOGMASKED(LOG_WRITE_RTC, "%s: MACE: RTC: Unknown Write: %08x = %08x%08x & %08x%08x\n", machine().describe_context(), 0x1f3a0000 + offset*8
, (uint32_t)(data >> 32), (uint32_t)data, (uint32_t)(mem_mask >> 32), (uint32_t)mem_mask);
return;
}
LOGMASKED(LOG_WRITE_RTC, "%s: MACE: RTC Write: %08x (register %02x) = %08x%08x & %08x%08x\n", machine().describe_context(), 0x1f3a0000 + offset*8
, offset >> 5, (uint32_t)(data >> 32), (uint32_t)data, (uint32_t)(mem_mask >> 32), (uint32_t)mem_mask);
m_rtc_write_callback(offset >> 5, data & 0xff);
}
//**************************************************************************

View File

@ -25,9 +25,13 @@ public:
mace_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto rtc_read_callback() { return m_rtc_read_callback.bind(); }
auto rtc_write_callback() { return m_rtc_write_callback.bind(); }
void map(address_map &map);
protected:
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
@ -67,6 +71,9 @@ protected:
required_device<mips3_device> m_maincpu;
devcb_read8 m_rtc_read_callback;
devcb_write8 m_rtc_write_callback;
enum
{
ISA_INT_COMPARE1 = 0x2000,
@ -98,19 +105,11 @@ protected:
uint64_t m_vout_msc_ust;
};
// DS17287 RTC; proper hookup is unknown
struct rtc_t
{
uint64_t m_unknown;
};
isa_t m_isa;
ust_msc_t m_ust_msc;
emu_timer *m_timer_ust;
emu_timer *m_timer_msc;
rtc_t m_rtc;
};
DECLARE_DEVICE_TYPE(SGI_MACE, mace_device)