summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2020-03-16 09:30:49 -0400
committer AJR <ajrhacker@users.noreply.github.com>2020-03-16 09:31:01 -0400
commitb5a63a8e557a048e75556710bf25013b57dcb675 (patch)
treed84e9641fbac7736ed8ae86f657ce01e9f804aee
parente302ab780a35c896834163a4618385d6a3ec28c6 (diff)
Add second timer output comparator and associated status register to the HD6301X and HD6301Y
-rw-r--r--src/devices/cpu/m6800/m6801.cpp278
-rw-r--r--src/devices/cpu/m6800/m6801.h23
2 files changed, 262 insertions, 39 deletions
diff --git a/src/devices/cpu/m6800/m6801.cpp b/src/devices/cpu/m6800/m6801.cpp
index cf05e910468..9143eda9f6a 100644
--- a/src/devices/cpu/m6800/m6801.cpp
+++ b/src/devices/cpu/m6800/m6801.cpp
@@ -34,23 +34,12 @@
#define OC m_output_compare.w.l
#define OCH m_output_compare.w.h
#define OCD m_output_compare.d
+#define OC2 m_output_compare2.w.l
+#define OC2H m_output_compare2.w.h
+#define OC2D m_output_compare2.d
#define TOH m_timer_over.w.l
#define TOD m_timer_over.d
-#define MODIFIED_tcsr { \
- m_irq2 = (m_tcsr&(m_tcsr<<3))&(TCSR_ICF|TCSR_OCF|TCSR_TOF); \
-}
-
-#define SET_TIMER_EVENT { \
- m_timer_next = (OCD - CTD < TOD - CTD) ? OCD : TOD; \
-}
-
-/* when change freerunningcounter or outputcapture */
-#define MODIFIED_counters { \
- OCH = (OC >= CT) ? CTH : CTH+1; \
- SET_TIMER_EVENT; \
-}
-
// serial I/O
#define M6801_RMCR_SS_MASK 0x03 // Speed Select
@@ -104,6 +93,12 @@ enum
#define TCSR_OCF 0x40
#define TCSR_ICF 0x80
+#define TCSR2_OE1 0x01
+#define TCSR2_OE2 0x02
+#define TCSR2_OLVL2 0x04
+#define TCSR2_EOCI2 0x08
+#define TCSR2_OCF2 0x20
+
/* Note: don't use 0 cycles here for invalid opcodes so that we don't */
/* hang in an infinite loop if we hit one */
#define XX 5 // invalid opcode unknown cc
@@ -269,7 +264,7 @@ void hd6301x_cpu_device::hd6301x_io(address_map &map)
map(0x000c, 0x000c).rw(FUNC(hd6301x_cpu_device::ocrl_r), FUNC(hd6301x_cpu_device::ocrl_w));
map(0x000d, 0x000d).r(FUNC(hd6301x_cpu_device::icrh_r));
map(0x000e, 0x000e).r(FUNC(hd6301x_cpu_device::icrl_r));
- //map(0x000f, 0x000f).rw(FUNC(hd6301x_cpu_device::tcsr2_r), FUNC(hd6301x_cpu_device::tcsr2_w));
+ map(0x000f, 0x000f).rw(FUNC(hd6301x_cpu_device::tcsr2_r), FUNC(hd6301x_cpu_device::tcsr2_w));
map(0x0010, 0x0010).rw(FUNC(hd6301x_cpu_device::sci_rmcr_r), FUNC(hd6301x_cpu_device::sci_rmcr_w));
map(0x0011, 0x0011).rw(FUNC(hd6301x_cpu_device::sci_trcsr_r), FUNC(hd6301x_cpu_device::sci_trcsr_w));
map(0x0012, 0x0012).r(FUNC(hd6301x_cpu_device::sci_rdr_r));
@@ -279,8 +274,8 @@ void hd6301x_cpu_device::hd6301x_io(address_map &map)
map(0x0016, 0x0016).rw(FUNC(hd6301x_cpu_device::ff_r), FUNC(hd6301x_cpu_device::p6_ddr_w));
map(0x0017, 0x0017).rw(FUNC(hd6301x_cpu_device::p6_data_r), FUNC(hd6301x_cpu_device::p6_data_w));
map(0x0018, 0x0018).rw(FUNC(hd6301x_cpu_device::p7_data_r), FUNC(hd6301x_cpu_device::p7_data_w)); // TODO: external except in single-chip mode
- //map(0x0019, 0x0019).rw(FUNC(hd6301x_cpu_device::ocr2h_r), FUNC(hd6301x_cpu_device::ocr2h_w));
- //map(0x001a, 0x001a).rw(FUNC(hd6301x_cpu_device::ocr2l_r), FUNC(hd6301x_cpu_device::ocr2l_w));
+ map(0x0019, 0x0019).rw(FUNC(hd6301x_cpu_device::ocr2h_r), FUNC(hd6301x_cpu_device::ocr2h_w));
+ map(0x001a, 0x001a).rw(FUNC(hd6301x_cpu_device::ocr2l_r), FUNC(hd6301x_cpu_device::ocr2l_w));
//map(0x001b, 0x001b).rw(FUNC(hd6301x_cpu_device::tcsr3_r), FUNC(hd6301x_cpu_device::tcsr3_w));
//map(0x001c, 0x001c).rw(FUNC(hd6301x_cpu_device::ff_r), FUNC(hd6301x_cpu_device::tconr_w));
//map(0x001d, 0x001d).rw(FUNC(hd6301x_cpu_device::t2cnt_r), FUNC(hd6301x_cpu_device::t2cnt_w));
@@ -422,6 +417,69 @@ void m6801_cpu_device::m6800_check_irq2()
}
}
+void hd6301x_cpu_device::m6800_check_irq2()
+{
+ if ((m_tcsr & (TCSR_EICI|TCSR_ICF)) == (TCSR_EICI|TCSR_ICF))
+ {
+ TAKE_ICI;
+ standard_irq_callback(M6801_TIN_LINE);
+ }
+ else if ((m_tcsr & (TCSR_EOCI|TCSR_OCF)) == (TCSR_EOCI|TCSR_OCF) ||
+ (m_tcsr2 & (TCSR2_EOCI2|TCSR2_OCF2)) == (TCSR2_EOCI2|TCSR2_OCF2))
+ {
+ TAKE_OCI;
+ }
+ else if ((m_tcsr & (TCSR_ETOI|TCSR_TOF)) == (TCSR_ETOI|TCSR_TOF))
+ {
+ TAKE_TOI;
+ }
+ else if (((m_trcsr & (M6801_TRCSR_RIE|M6801_TRCSR_RDRF)) == (M6801_TRCSR_RIE|M6801_TRCSR_RDRF)) ||
+ ((m_trcsr & (M6801_TRCSR_RIE|M6801_TRCSR_ORFE)) == (M6801_TRCSR_RIE|M6801_TRCSR_ORFE)) ||
+ ((m_trcsr & (M6801_TRCSR_TIE|M6801_TRCSR_TDRE)) == (M6801_TRCSR_TIE|M6801_TRCSR_TDRE)))
+ {
+ LOG("SCI interrupt\n");
+ TAKE_SCI;
+ }
+}
+
+void m6801_cpu_device::modified_tcsr()
+{
+ m_irq2 = (m_tcsr&(m_tcsr<<3))&(TCSR_ICF|TCSR_OCF|TCSR_TOF);
+}
+
+void hd6301x_cpu_device::modified_tcsr()
+{
+ m6801_cpu_device::modified_tcsr();
+ if ((m_tcsr2 & TCSR2_EOCI2) && (m_tcsr2 & TCSR2_OCF2))
+ m_irq2 |= TCSR_OCF;
+}
+
+void m6801_cpu_device::set_timer_event()
+{
+ m_timer_next = (OCD - CTD < TOD - CTD) ? OCD : TOD;
+}
+
+void hd6301x_cpu_device::set_timer_event()
+{
+ m6801_cpu_device::set_timer_event();
+ if (OC2D - CTD < m_timer_next)
+ m_timer_next = OC2D;
+}
+
+/* when change freerunningcounter or outputcapture */
+void m6801_cpu_device::modified_counters()
+{
+ OCH = (OC >= CT) ? CTH : CTH+1;
+ set_timer_event();
+}
+
+void hd6301x_cpu_device::modified_counters()
+{
+ OCH = (OC >= CT) ? CTH : CTH+1;
+ OC2H = (OC2 >= CT) ? CTH : CTH+1;
+ set_timer_event();
+}
+
/* check OCI or TOI */
void m6801_cpu_device::check_timer_event()
{
@@ -431,11 +489,7 @@ void m6801_cpu_device::check_timer_event()
OCH++; // next IRQ point
m_tcsr |= TCSR_OCF;
m_pending_tcsr |= TCSR_OCF;
- MODIFIED_tcsr;
- if((m_tcsr & TCSR_EOCI) && m_wai_state & M6800_SLP)
- m_wai_state &= ~M6800_SLP;
- if ( !(m_cc & 0x10) && (m_tcsr & TCSR_EOCI))
- TAKE_OCI;
+ modified_tcsr();
// if output on P21 is enabled, let's do it
if (m_port_ddr[1] & 2)
@@ -455,14 +509,78 @@ void m6801_cpu_device::check_timer_event()
#endif
m_tcsr |= TCSR_TOF;
m_pending_tcsr |= TCSR_TOF;
- MODIFIED_tcsr;
- if((m_tcsr & TCSR_ETOI) && m_wai_state & M6800_SLP)
+ modified_tcsr();
+ }
+
+ if (m_irq2 & (TCSR_OCF | TCSR_TOF))
+ {
+ if (m_wai_state & M6800_SLP)
m_wai_state &= ~M6800_SLP;
- if ( !(m_cc & 0x10) && (m_tcsr & TCSR_ETOI))
- TAKE_TOI;
+ if (!(m_cc & 0x10))
+ m6800_check_irq2();
}
/* set next event */
- SET_TIMER_EVENT;
+ set_timer_event();
+}
+
+void hd6301x_cpu_device::check_timer_event()
+{
+ /* OCI */
+ if (CTD >= OCD)
+ {
+ OCH++; // next IRQ point
+ m_tcsr |= TCSR_OCF;
+ m_pending_tcsr |= TCSR_OCF;
+ modified_tcsr();
+
+ // if output on P21 is enabled, let's do it
+ if (m_tcsr2 & TCSR2_OE1)
+ {
+ m_port_data[1] &= ~2;
+ m_port_data[1] |= (m_tcsr & TCSR_OLVL) << 1;
+ m_port2_written = true;
+ write_port2();
+ }
+ }
+ if (CTD >= OC2D)
+ {
+ OC2H++; // next IRQ point
+ m_tcsr2 |= TCSR2_OCF2;
+ m_pending_tcsr2 |= TCSR2_OCF2;
+ modified_tcsr();
+
+ // if output on P25 is enabled, let's do it
+ if (m_tcsr2 & TCSR2_OE2)
+ {
+ if (m_tcsr2 & TCSR2_OLVL2)
+ m_port_data[1] |= 0x20;
+ else
+ m_port_data[1] &= ~0x20;
+ m_port2_written = true;
+ write_port2();
+ }
+ }
+ /* TOI */
+ if (CTD >= TOD)
+ {
+ TOH++; // next IRQ point
+#if 0
+ CLEANUP_COUNTERS();
+#endif
+ m_tcsr |= TCSR_TOF;
+ m_pending_tcsr |= TCSR_TOF;
+ modified_tcsr();
+ }
+
+ if (m_irq2 & (TCSR_OCF | TCSR_TOF))
+ {
+ if (m_wai_state & M6800_SLP)
+ m_wai_state &= ~M6800_SLP;
+ if (!(m_cc & 0x10))
+ m6800_check_irq2();
+ }
+ /* set next event */
+ set_timer_event();
}
void m6801_cpu_device::increment_counter(int amount)
@@ -486,11 +604,17 @@ void m6801_cpu_device::CLEANUP_COUNTERS()
OCH -= CTH;
TOH -= CTH;
CTH = 0;
- SET_TIMER_EVENT;
+ set_timer_event();
if (CTD >= m_timer_next)
check_timer_event();
}
+void hd6301x_cpu_device::CLEANUP_COUNTERS()
+{
+ OC2H -= CTH;
+ m6801_cpu_device::CLEANUP_COUNTERS();
+}
+
void m6801_cpu_device::set_rmcr(uint8_t data)
{
if (m_rmcr == data) return;
@@ -772,7 +896,7 @@ void m6801_cpu_device::execute_set_input(int irqline, int state)
m_tcsr |= TCSR_ICF;
m_pending_tcsr |= TCSR_ICF;
m_input_capture = CT;
- MODIFIED_tcsr;
+ modified_tcsr();
}
break;
@@ -864,6 +988,9 @@ void hd6301x_cpu_device::device_start()
save_item(NAME(m_portx_ddr));
save_item(NAME(m_portx_data));
+ save_item(NAME(m_tcsr2));
+ save_item(NAME(m_pending_tcsr2));
+ save_item(NAME(m_output_compare2.d));
}
void m6801_cpu_device::device_reset()
@@ -912,6 +1039,10 @@ void hd6301x_cpu_device::device_reset()
m_portx_ddr[0] = 0x00;
m_portx_ddr[1] = 0x00;
+
+ m_tcsr2 = 0x00;
+ m_pending_tcsr2 = 0x00;
+ OC2D = 0xffff;
}
@@ -930,6 +1061,7 @@ void m6801_cpu_device::write_port2()
if (m_trcsr & M6801_TRCSR_TE)
{
data = (data & 0xef) | (m_tx << 4);
+ ddr |= 0x10;
}
data &= 0x1f;
@@ -942,11 +1074,17 @@ void hd6301x_cpu_device::write_port2()
if (!m_port2_written) return;
uint8_t ddr = m_port_ddr[1];
+ if (m_tcsr2 & TCSR2_OE1)
+ ddr |= 0x02;
+ if (m_tcsr2 & TCSR2_OE2)
+ ddr |= 0x20;
+
uint8_t data = (m_port_data[1] & ddr) | (ddr ^ 0xff);
if (m_trcsr & M6801_TRCSR_TE)
{
data = (data & 0xef) | (m_tx << 4);
+ ddr |= 0x10;
}
m_out_port_func[1](0, data, ddr);
@@ -1235,7 +1373,7 @@ void m6801_cpu_device::tcsr_w(uint8_t data)
m_tcsr = data;
m_pending_tcsr &= m_tcsr;
- MODIFIED_tcsr;
+ modified_tcsr();
if( !(m_cc & 0x10) )
m6800_check_irq2();
}
@@ -1245,7 +1383,7 @@ uint8_t m6801_cpu_device::ch_r()
if(!(m_pending_tcsr&TCSR_TOF) && !machine().side_effects_disabled())
{
m_tcsr &= ~TCSR_TOF;
- MODIFIED_tcsr;
+ modified_tcsr();
}
return m_counter.b.h;
}
@@ -1266,7 +1404,7 @@ void m6801_cpu_device::ch_w(uint8_t data)
m_latch09 = data & 0xff; /* 6301 only */
CT = 0xfff8;
TOH = CTH;
- MODIFIED_counters;
+ modified_counters();
}
void m6801_cpu_device::cl_w(uint8_t data)
@@ -1275,7 +1413,7 @@ void m6801_cpu_device::cl_w(uint8_t data)
CT = (m_latch09 << 8) | (data & 0xff);
TOH = CTH;
- MODIFIED_counters;
+ modified_counters();
}
uint8_t m6801_cpu_device::ocrh_r()
@@ -1283,7 +1421,7 @@ uint8_t m6801_cpu_device::ocrh_r()
if(!(m_pending_tcsr&TCSR_OCF) && !machine().side_effects_disabled())
{
m_tcsr &= ~TCSR_OCF;
- MODIFIED_tcsr;
+ modified_tcsr();
}
return m_output_compare.b.h;
}
@@ -1293,7 +1431,7 @@ uint8_t m6801_cpu_device::ocrl_r()
if(!(m_pending_tcsr&TCSR_OCF) && !machine().side_effects_disabled())
{
m_tcsr &= ~TCSR_OCF;
- MODIFIED_tcsr;
+ modified_tcsr();
}
return m_output_compare.b.l;
}
@@ -1305,7 +1443,7 @@ void m6801_cpu_device::ocrh_w(uint8_t data)
if( m_output_compare.b.h != data)
{
m_output_compare.b.h = data;
- MODIFIED_counters;
+ modified_counters();
}
}
@@ -1316,7 +1454,7 @@ void m6801_cpu_device::ocrl_w(uint8_t data)
if( m_output_compare.b.l != data)
{
m_output_compare.b.l = data;
- MODIFIED_counters;
+ modified_counters();
}
}
@@ -1325,7 +1463,7 @@ uint8_t m6801_cpu_device::icrh_r()
if(!(m_pending_tcsr&TCSR_ICF) && !machine().side_effects_disabled())
{
m_tcsr &= ~TCSR_ICF;
- MODIFIED_tcsr;
+ modified_tcsr();
}
return (m_input_capture >> 0) & 0xff;
}
@@ -1335,6 +1473,70 @@ uint8_t m6801_cpu_device::icrl_r()
return (m_input_capture >> 8) & 0xff;
}
+uint8_t hd6301x_cpu_device::tcsr2_r()
+{
+ if (!machine().side_effects_disabled())
+ {
+ m_pending_tcsr &= ~(TCSR_ICF | TCSR_OCF);
+ m_pending_tcsr2 = 0;
+ }
+ return m_tcsr2 | (m_tcsr & (TCSR_ICF | TCSR_OCF)) | 0x10;
+}
+
+void hd6301x_cpu_device::tcsr2_w(uint8_t data)
+{
+ LOGTIMER("Timer Control and Status Register 2: %02x\n", data);
+
+ data &= TCSR2_OE1 | TCSR2_OE2 | TCSR2_OLVL2 | TCSR2_EOCI2;
+ m_tcsr2 = data | (m_tcsr2 & TCSR2_OCF2);
+ m_pending_tcsr2 &= m_tcsr2;
+ modified_tcsr();
+ if( !(m_cc & 0x10) )
+ m6800_check_irq2();
+}
+
+uint8_t hd6301x_cpu_device::ocr2h_r()
+{
+ if(!(m_pending_tcsr2&TCSR2_OCF2) && !machine().side_effects_disabled())
+ {
+ m_tcsr2 &= ~TCSR2_OCF2;
+ modified_tcsr();
+ }
+ return m_output_compare2.b.h;
+}
+
+uint8_t hd6301x_cpu_device::ocr2l_r()
+{
+ if(!(m_pending_tcsr2&TCSR2_OCF2) && !machine().side_effects_disabled())
+ {
+ m_tcsr2 &= ~TCSR2_OCF2;
+ modified_tcsr();
+ }
+ return m_output_compare2.b.l;
+}
+
+void hd6301x_cpu_device::ocr2h_w(uint8_t data)
+{
+ LOGTIMER("Output Compare High Register 2: %02x\n", data);
+
+ if( m_output_compare2.b.h != data)
+ {
+ m_output_compare2.b.h = data;
+ modified_counters();
+ }
+}
+
+void hd6301x_cpu_device::ocr2l_w(uint8_t data)
+{
+ LOGTIMER("Output Compare Low Register 2: %02x\n", data);
+
+ if( m_output_compare2.b.l != data)
+ {
+ m_output_compare2.b.l = data;
+ modified_counters();
+ }
+}
+
uint8_t m6801_cpu_device::sci_rmcr_r()
{
diff --git a/src/devices/cpu/m6800/m6801.h b/src/devices/cpu/m6800/m6801.h
index af911a48842..b9d65bb9d02 100644
--- a/src/devices/cpu/m6800/m6801.h
+++ b/src/devices/cpu/m6800/m6801.h
@@ -166,7 +166,10 @@ protected:
virtual void EAT_CYCLES() override;
virtual void CLEANUP_COUNTERS() override;
- void check_timer_event();
+ virtual void modified_tcsr();
+ virtual void set_timer_event();
+ virtual void modified_counters();
+ virtual void check_timer_event();
void set_rmcr(uint8_t data);
virtual void write_port2();
int m6800_rx();
@@ -274,11 +277,29 @@ protected:
uint8_t p7_data_r();
void p7_data_w(uint8_t data);
+ uint8_t tcsr2_r();
+ void tcsr2_w(uint8_t data);
+ uint8_t ocr2h_r();
+ void ocr2h_w(uint8_t data);
+ uint8_t ocr2l_r();
+ void ocr2l_w(uint8_t data);
+
+ virtual void m6800_check_irq2() override;
+ virtual void modified_tcsr() override;
+ virtual void set_timer_event() override;
+ virtual void modified_counters() override;
+ virtual void check_timer_event() override;
+ virtual void CLEANUP_COUNTERS() override;
+
devcb_read8::array<2> m_in_portx_func;
devcb_write8::array<3> m_out_portx_func;
uint8_t m_portx_ddr[2];
uint8_t m_portx_data[3];
+
+ uint8_t m_tcsr2;
+ uint8_t m_pending_tcsr2;
+ PAIR m_output_compare2;
};