summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices
diff options
context:
space:
mode:
author Patrick Mackinlay <pmackinlay@hotmail.com>2020-11-25 10:48:15 +0700
committer Patrick Mackinlay <pmackinlay@hotmail.com>2020-11-25 10:48:15 +0700
commit481e06f3fed2018cbd3a0349370114fd214475a5 (patch)
tree1eeec7dca5720aa9fb3798005f1365cd64250a8c /src/devices
parenta35cd5698f0f0c7fa5464ef6129240f1b4d218fd (diff)
mc146818: add square wave output
Diffstat (limited to 'src/devices')
-rw-r--r--src/devices/machine/mc146818.cpp31
-rw-r--r--src/devices/machine/mc146818.h3
2 files changed, 29 insertions, 5 deletions
diff --git a/src/devices/machine/mc146818.cpp b/src/devices/machine/mc146818.cpp
index 06525f07893..cbce9ced926 100644
--- a/src/devices/machine/mc146818.cpp
+++ b/src/devices/machine/mc146818.cpp
@@ -39,12 +39,14 @@ mc146818_device::mc146818_device(const machine_config &mconfig, device_type type
m_index(0),
m_last_refresh(attotime::zero), m_clock_timer(nullptr), m_periodic_timer(nullptr),
m_write_irq(*this),
+ m_write_sqw(*this),
m_century_index(-1),
m_epoch(0),
m_use_utc(false),
m_binary(false),
m_hour(false),
- m_binyear(false)
+ m_binyear(false),
+ m_sqw_state(false)
{
}
@@ -60,9 +62,11 @@ void mc146818_device::device_start()
m_periodic_timer = timer_alloc(TIMER_PERIODIC);
m_write_irq.resolve_safe();
+ m_write_sqw.resolve_safe();
save_pointer(NAME(m_data), data_size());
save_item(NAME(m_index));
+ save_item(NAME(m_sqw_state));
}
@@ -75,6 +79,10 @@ void mc146818_device::device_reset()
m_data[REG_B] &= ~(REG_B_UIE | REG_B_AIE | REG_B_PIE | REG_B_SQWE);
m_data[REG_C] = 0;
+ // square wave output is disabled
+ if (m_sqw_state)
+ m_write_sqw(CLEAR_LINE);
+
update_irq();
}
@@ -87,8 +95,17 @@ void mc146818_device::device_timer(emu_timer &timer, device_timer_id id, int par
switch (id)
{
case TIMER_PERIODIC:
- m_data[REG_C] |= REG_C_PF;
- update_irq();
+ m_sqw_state = !m_sqw_state;
+
+ if (m_data[REG_B] & REG_B_SQWE)
+ m_write_sqw(m_sqw_state);
+
+ // periodic flag/interrupt on rising edge of periodic timer
+ if (m_sqw_state)
+ {
+ m_data[REG_C] |= REG_C_PF;
+ update_irq();
+ }
break;
case TIMER_CLOCK:
@@ -464,8 +481,9 @@ void mc146818_device::update_timer()
double periodic_hz = (double) clock() / (1 << shift);
// TODO: take the time since last timer into account
- periodic_period = attotime::from_hz(periodic_hz * 2);
- periodic_interval = attotime::from_hz(periodic_hz);
+ // periodic frequency is doubled to produce square wave output
+ periodic_period = attotime::from_hz(periodic_hz * 4);
+ periodic_interval = attotime::from_hz(periodic_hz * 2);
}
}
@@ -662,6 +680,9 @@ void mc146818_device::internal_write(offs_t offset, uint8_t data)
if ((data & REG_B_SET) && !(m_data[REG_B] & REG_B_SET))
data &= ~REG_B_UIE;
+ if (!(data & REG_B_SQWE) && (m_data[REG_B] & REG_B_SQWE) && m_sqw_state)
+ m_write_sqw(CLEAR_LINE);
+
m_data[REG_B] = data;
update_irq();
break;
diff --git a/src/devices/machine/mc146818.h b/src/devices/machine/mc146818.h
index 18588b71827..83d45292dbc 100644
--- a/src/devices/machine/mc146818.h
+++ b/src/devices/machine/mc146818.h
@@ -26,6 +26,7 @@ public:
// callbacks
auto irq() { return m_write_irq.bind(); }
+ auto sqw() { return m_write_sqw.bind(); }
// 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; }
@@ -165,8 +166,10 @@ protected:
emu_timer *m_periodic_timer;
devcb_write_line m_write_irq;
+ devcb_write_line m_write_sqw;
int m_century_index, m_epoch;
bool m_use_utc, m_binary, m_hour, m_binyear;
+ bool m_sqw_state;
};