Add second timer output comparator and associated status register to the HD6301X and HD6301Y

This commit is contained in:
AJR 2020-03-16 09:30:49 -04:00
parent e302ab780a
commit b5a63a8e55
2 changed files with 262 additions and 39 deletions

View File

@ -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()
{

View File

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