diff options
-rw-r--r-- | src/devices/machine/68340.cpp | 89 | ||||
-rw-r--r-- | src/devices/machine/68340.h | 9 | ||||
-rw-r--r-- | src/devices/machine/68340ser.cpp | 17 | ||||
-rw-r--r-- | src/devices/machine/68340ser.h | 4 | ||||
-rw-r--r-- | src/devices/machine/68340sim.cpp | 59 | ||||
-rw-r--r-- | src/devices/machine/68340sim.h | 1 | ||||
-rw-r--r-- | src/devices/machine/68340tmu.cpp | 64 | ||||
-rw-r--r-- | src/devices/machine/68340tmu.h | 8 |
8 files changed, 159 insertions, 92 deletions
diff --git a/src/devices/machine/68340.cpp b/src/devices/machine/68340.cpp index 6110a5345cb..827bb48c7aa 100644 --- a/src/devices/machine/68340.cpp +++ b/src/devices/machine/68340.cpp @@ -7,6 +7,13 @@ #include "emu.h" #include "68340.h" +#include <algorithm> + +#define LOG_BASE (1 << 1U) +#define LOG_IPL (1 << 2U) +#define VERBOSE (LOG_BASE) +#include "logmacro.h" + DEFINE_DEVICE_TYPE(M68340, m68340_cpu_device, "mc68340", "MC68340") int m68340_cpu_device::calc_cs(offs_t address) const @@ -41,17 +48,88 @@ uint16_t m68340_cpu_device::get_cs(offs_t address) +void m68340_cpu_device::update_ipl() +{ + uint8_t new_ipl = std::max({ + pit_irq_level(), + m_serial->irq_level(), + m_timer[0]->irq_level(), + m_timer[1]->irq_level() + }); + if (m_ipl != new_ipl) + { + if (m_ipl != 0) + set_input_line(m_ipl, CLEAR_LINE); + LOGMASKED(LOG_IPL, "Changing interrupt level from %d to %d\n", m_ipl, new_ipl); + m_ipl = new_ipl; + if (m_ipl != 0) + set_input_line(m_ipl, ASSERT_LINE); + } +} + +IRQ_CALLBACK_MEMBER(m68340_cpu_device::int_ack) +{ + uint8_t pit_iarb = pit_arbitrate(irqline); + uint8_t scu_iarb = m_serial->arbitrate(irqline); + uint8_t t1_iarb = m_timer[0]->arbitrate(irqline); + uint8_t t2_iarb = m_timer[1]->arbitrate(irqline); + uint8_t iarb = std::max({pit_iarb, scu_iarb, t1_iarb, t2_iarb}); + LOGMASKED(LOG_IPL, "Level %d interrupt arbitration: PIT = %X, SCU = %X, T1 = %X, T2 = %X\n", irqline, pit_iarb, scu_iarb, t1_iarb, t2_iarb); + int response = 0; + uint32_t vector = standard_irq_callback(irqline); + + if (iarb != 0) + { + if (iarb == scu_iarb) + { + vector = m_serial->irq_vector(); + LOGMASKED(LOG_IPL, "SCU acknowledged interrupt with vector %02X\n", vector); + response++; + } + + if (iarb == t1_iarb) + { + vector = m_timer[0]->irq_vector(); + LOGMASKED(LOG_IPL, "T1 acknowledged interrupt with vector %02X\n", vector); + response++; + } + + if (iarb == t2_iarb) + { + vector = m_timer[1]->irq_vector(); + LOGMASKED(LOG_IPL, "T2 acknowledged interrupt with vector %02X\n", vector); + response++; + } + + if (iarb == pit_iarb) + { + vector = pit_iack(); + LOGMASKED(LOG_IPL, "PIT acknowledged interrupt with vector %02X\n", vector); + response++; + } + } + + if (response == 0) + logerror("Spurious interrupt (level %d)\n", irqline); + else if (response > 1) + logerror("%d modules responded to interrupt (level %d, IARB = %X)\n", response, irqline, iarb); + + return vector; +} + + /* 68340 specifics - MOVE */ READ32_MEMBER( m68340_cpu_device::m68340_internal_base_r ) { - logerror("%08x m68340_internal_base_r %08x, (%08x)\n", m_ppc, offset*4,mem_mask); + if (!machine().side_effects_disabled()) + LOGMASKED(LOG_BASE, "%08x m68340_internal_base_r %08x, (%08x)\n", m_ppc, offset*4,mem_mask); return m_m68340_base; } WRITE32_MEMBER( m68340_cpu_device::m68340_internal_base_w ) { - logerror("%08x m68340_internal_base_w %08x, %08x (%08x)\n", m_ppc, offset*4,data,mem_mask); + LOGMASKED(LOG_BASE, "%08x m68340_internal_base_w %08x, %08x (%08x)\n", m_ppc, offset*4,data,mem_mask); // other conditions? if (m_dfc==0x7) @@ -69,7 +147,7 @@ WRITE32_MEMBER( m68340_cpu_device::m68340_internal_base_w ) } COMBINE_DATA(&m_m68340_base); - logerror("%08x m68340_internal_base_w %08x, %08x (%08x) (m_m68340_base write)\n", pc(), offset*4,data,mem_mask); + LOGMASKED(LOG_BASE, "%08x m68340_internal_base_w %08x, %08x (%08x) (m_m68340_base write)\n", pc(), offset*4,data,mem_mask); // map new modules if (m_m68340_base&1) @@ -103,7 +181,7 @@ WRITE32_MEMBER( m68340_cpu_device::m68340_internal_base_w ) } else { - logerror("%08x m68340_internal_base_w %08x, %04x (%04x) (should fall through?)\n", pc(), offset*4,data,mem_mask); + LOGMASKED(LOG_BASE, "%08x m68340_internal_base_w %08x, %04x (%04x) (should fall through?)\n", pc(), offset*4,data,mem_mask); } @@ -148,6 +226,7 @@ m68340_cpu_device::m68340_cpu_device(const machine_config &mconfig, const char * m_m68340SIM = nullptr; m_m68340DMA = nullptr; m_m68340_base = 0; + m_ipl = 0; } void m68340_cpu_device::device_reset() @@ -179,4 +258,6 @@ void m68340_cpu_device::device_start() m_m68340_base = 0x00000000; m_internal = &space(AS_PROGRAM); + + m_int_ack_callback = device_irq_acknowledge_delegate(FUNC(m68340_cpu_device::int_ack), this); } diff --git a/src/devices/machine/68340.h b/src/devices/machine/68340.h index 3a661ff742c..12af250c5b2 100644 --- a/src/devices/machine/68340.h +++ b/src/devices/machine/68340.h @@ -53,11 +53,16 @@ private: required_device<mc68340_serial_module_device> m_serial; required_device_array<mc68340_timer_module_device, 2> m_timer; + void update_ipl(); + IRQ_CALLBACK_MEMBER(int_ack); + TIMER_CALLBACK_MEMBER(periodic_interrupt_timer_callback); void start_68340_sim(); - void do_pit_irq(); void do_tick_pit(); + uint8_t pit_irq_level() const; + uint8_t pit_arbitrate(uint8_t level) const; + uint8_t pit_iack(); int calc_cs(offs_t address) const; int get_timer_index(mc68340_timer_module_device *timer) { return (timer == m_timer[0].target()) ? 0 : 1; } @@ -100,6 +105,8 @@ private: emu_timer *m_irq_timer; + uint8_t m_ipl; + devcb_write8 m_pa_out_cb; devcb_read8 m_pa_in_cb; devcb_write8 m_pb_out_cb; diff --git a/src/devices/machine/68340ser.cpp b/src/devices/machine/68340ser.cpp index 622b63a2a5f..fcf6708305e 100644 --- a/src/devices/machine/68340ser.cpp +++ b/src/devices/machine/68340ser.cpp @@ -127,12 +127,13 @@ void mc68340_serial_module_device::write(offs_t offset, uint8_t data) m_mcrl = data; LOGSERIAL("PC: %08x %s %04x, %04x (MCRL - Module Configuration Register Low byte)\n", m_cpu->pcbase(), FUNCNAME, offset, data); LOGSERIAL("- Supervisor registers %s - not implemented\n", data & REG_MCRL_SUPV ? "requries supervisor privileges" : "can be accessed by user privileged software"); - LOGSERIAL("- Interrupt Arbitration level: %02x - not implemented\n", data & REG_MCRL_ARBLV); + LOGSERIAL("- Interrupt Arbitration level: %02x\n", data & REG_MCRL_ARBLV); break; case REG_ILR: m_ilr = data; LOGSERIAL("PC: %08x %s %04x, %04x (ILR - Interrupt Level Register)\n", m_cpu->pcbase(), FUNCNAME, offset, data); LOGSERIAL("- Interrupt Level: %02x\n", data & REG_ILR_MASK); + m_cpu->update_ipl(); break; case REG_IVR: m_ivr = data; @@ -148,19 +149,7 @@ void mc68340_serial_module_device::write(offs_t offset, uint8_t data) WRITE_LINE_MEMBER( mc68340_serial_module_device::irq_w ) { LOGINT("IRQ!\n%s\n", FUNCNAME); - if (m_ilr > 0) - { - if (((m_cpu->m_m68340SIM->m_avr_rsr >> (8 + m_ilr)) & 1) != 0) // use autovector ? - { - LOGINT("- Autovector level %d\n", m_ilr); - m_cpu->set_input_line(m_ilr, HOLD_LINE); - } - else // otherwise not... - { - LOGINT("- Vector %02x level %d\n", m_ivr, m_ilr); - m_cpu->set_input_line_and_vector(m_ilr, HOLD_LINE, m_ivr); - } - } + m_cpu->update_ipl(); } mc68340_serial_module_device::mc68340_serial_module_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) diff --git a/src/devices/machine/68340ser.h b/src/devices/machine/68340ser.h index 210edba58aa..e658d719c05 100644 --- a/src/devices/machine/68340ser.h +++ b/src/devices/machine/68340ser.h @@ -28,6 +28,10 @@ public: virtual void write(offs_t offset, uint8_t data) override; DECLARE_WRITE_LINE_MEMBER(irq_w); + uint8_t irq_level() const { return irq_pending() ? (m_ilr & REG_ILR_MASK) : 0; } + uint8_t irq_vector() const { return m_ivr; } + uint8_t arbitrate(uint8_t level) const { return (irq_level() == level) ? (m_mcrl & REG_MCRL_ARBLV) : 0; } + protected: m68340_cpu_device *m_cpu; diff --git a/src/devices/machine/68340sim.cpp b/src/devices/machine/68340sim.cpp index a9506f32944..cf299ba2b22 100644 --- a/src/devices/machine/68340sim.cpp +++ b/src/devices/machine/68340sim.cpp @@ -20,7 +20,7 @@ #define LOG_PIT (1U << 8) #define LOG_CS (1U << 9) -//#define VERBOSE (LOG_CS) +#define VERBOSE (LOG_PIT) #define LOG_OUTPUT_FUNC printf // Needs always to be enabled as the default value 'logerror' is not available here #include "logmacro.h" @@ -61,7 +61,7 @@ READ16_MEMBER( m68340_cpu_device::m68340_internal_sim_r ) val = sim.m_syncr; break; - case m68340_sim::REG_AVR_RSR: + case m68340_sim::REG_AVR_RSR: // Manual seems to say that AVR only autovectors externally triggered interrupts (INT1-INT7) LOGSIM("- %08x %s %04x, (%04x) (AVR, RSR - Auto Vector Register, Reset Status Register) - not implemented\n", m_ppc, FUNCNAME, offset*2,mem_mask); val = sim.m_avr_rsr; break; @@ -165,6 +165,7 @@ WRITE16_MEMBER( m68340_cpu_device::m68340_internal_sim_w ) COMBINE_DATA(&sim.m_picr); LOGPIT("- PIRQL: Periodic Interrupt Level %d%s\n", (data & m68340_sim::REG_PICR_PIRQL) >> 8, (data & m68340_sim::REG_PICR_PIRQL) == 0 ? " (disabled)" : ""); LOGPIT("- PIV : Periodic Interrupt Vector %02x\n", (data & m68340_sim::REG_PICR_PIVEC)); + update_ipl(); break; case m68340_sim::REG_PITR: @@ -426,35 +427,6 @@ WRITE32_MEMBER( m68340_cpu_device::m68340_internal_sim_cs_w ) } } -void m68340_cpu_device::do_pit_irq() -{ - assert(m_m68340SIM); - m68340_sim &sim = *m_m68340SIM; - - //logerror("do_pit_irq\n"); - int timer_irq_level = (sim.m_picr & 0x0700) >> 8; - int timer_irq_vector = (sim.m_picr & 0x00ff) >> 0; - - if (timer_irq_level) // 0 is irq disabled - { - int use_autovector = (sim.m_avr_rsr >> (8 + timer_irq_level)) & 1; - - LOGPIT("PIT IRQ triggered, Lvl: %d using Vector: %d (0 = auto vector)\n", timer_irq_level, use_autovector ? 0 : timer_irq_vector); - - if (use_autovector) - { - //logerror("irq with autovector\n"); - set_input_line(timer_irq_level, HOLD_LINE); - } - else - { - //logerror("irq without autovector\n"); - set_input_line_and_vector(timer_irq_level, HOLD_LINE, timer_irq_vector); - } - - } -} - TIMER_CALLBACK_MEMBER(m68340_cpu_device::periodic_interrupt_timer_callback) { do_tick_pit(); @@ -518,7 +490,7 @@ void m68340_sim::reset() m_picr= 0x000f; m_pitr= 0x0000; // TODO: read MODCK pin to set the clock modes for watch dog and periodic timer m_swsr= 0x0000; - + m_pit_irq = false; } /* do_tick_pit works on whole clock cycles, no flank support */ @@ -544,7 +516,8 @@ void m68340_cpu_device::do_tick_pit() if (sim.m_pit_counter == 0) // Zero detect { LOGPIT("PIT timer reached zero!\n"); - do_pit_irq(); + sim.m_pit_irq = true; + update_ipl(); } } @@ -557,3 +530,23 @@ WRITE_LINE_MEMBER( m68340_cpu_device::extal_w ) do_tick_pit(); } } + +uint8_t m68340_cpu_device::pit_irq_level() const +{ + return m_m68340SIM->m_pit_irq ? (m_m68340SIM->m_picr & m68340_sim::REG_PICR_PIRQL) >> 8 : 0; +} + +uint8_t m68340_cpu_device::pit_arbitrate(uint8_t level) const +{ + if (pit_irq_level() == level) + return m_m68340SIM->m_mcr & m68340_sim::REG_MCR_ARBLV; + else + return 0; +} + +uint8_t m68340_cpu_device::pit_iack() +{ + m_m68340SIM->m_pit_irq = false; + update_ipl(); + return m_m68340SIM->m_picr & m68340_sim::REG_PICR_PIVEC; +} diff --git a/src/devices/machine/68340sim.h b/src/devices/machine/68340sim.h index d8447b999fc..3c839984db2 100644 --- a/src/devices/machine/68340sim.h +++ b/src/devices/machine/68340sim.h @@ -32,6 +32,7 @@ public: // Timers and counters uint8_t m_pit_counter; + bool m_pit_irq; void reset(); diff --git a/src/devices/machine/68340tmu.cpp b/src/devices/machine/68340tmu.cpp index 660079aaded..1ceaf65f600 100644 --- a/src/devices/machine/68340tmu.cpp +++ b/src/devices/machine/68340tmu.cpp @@ -21,7 +21,6 @@ #define LOG_INT (1U << 4) //#define VERBOSE (LOG_SETUP|LOG_INT|LOG_TIMER) -#define LOG_OUTPUT_FUNC printf // Needs always to be enabled as the default value 'logerror' is not available here #include "logmacro.h" @@ -86,6 +85,8 @@ READ16_MEMBER( mc68340_timer_module_device::read ) break; case REG_COM: val = m_com; + if (!machine().side_effects_disabled()) + m_sr &= ~REG_SR_COM; LOGTIMER("- %08x %s %04x, %04x (%04x) (COM - Compare Register)\n", m_cpu->pcbase(), FUNCNAME, offset * 2, val, mem_mask); break; default: @@ -121,13 +122,14 @@ WRITE16_MEMBER( mc68340_timer_module_device::write ) LOGTIMER("- Clocks are %s\n", data & REG_MCR_STP ? "stopped" : "running"); LOGTIMER("- Freeze signal %s - not implemented\n", data & REG_MCR_FRZ1 ? "stops execution" : "is ignored"); LOGTIMER("- Supervisor registers %s - not implemented\n", data & REG_MCR_SUPV ? "requries supervisor privileges" : "can be accessed by user privileged software"); - LOGTIMER("- Interrupt Arbitration level: %02x - not implemented\n", data & REG_MCR_ARBLV); + LOGTIMER("- Interrupt Arbitration level: %02x\n", data & REG_MCR_ARBLV); break; case REG_IR: COMBINE_DATA(&m_ir); LOGTIMER("PC: %08x %s %04x, %04x (%04x) (IR - Interrupt Register)\n", m_cpu->pcbase(), FUNCNAME, offset * 2, data, mem_mask); LOGTIMER("- Interrupt level : %02x\n", (data & REG_IR_INTLEV) >> 8); LOGTIMER("- Interrupt vector: %02x\n", (data & REG_IR_INTVEC)); + m_cpu->update_ipl(); break; case REG_CR: COMBINE_DATA(&m_cr); @@ -135,9 +137,9 @@ WRITE16_MEMBER( mc68340_timer_module_device::write ) LOGTIMER("- Software reset: %s\n", (data & REG_CR_SWR) ? "inactive" : "active" ); LOGTIMER("- Enabled interrupts: %02x TO:%d TG:%d TC:%d\n", data & REG_CR_INTMSK, - (data & REG_CR_IE0) ? 1 : 0, + (data & REG_CR_IE2) ? 1 : 0, (data & REG_CR_IE1) ? 1 : 0, - (data & REG_CR_IE2) ? 1 : 0); + (data & REG_CR_IE0) ? 1 : 0); LOGTIMER("- TGE signal, TGATE%d is %s\n", m_cpu->get_timer_index(this) + 1, (data & REG_CR_TGE) ? "enabled" : "disabled"); LOGTIMER("- PCLK: Counter uses %s\n", (data & REG_CR_PCLK) ? "prescaler" : "clock"); LOGTIMER("- CPE: Counter is %s\n", (data & REG_CR_CPE) ? "enabled" : "disabled"); @@ -163,6 +165,7 @@ WRITE16_MEMBER( mc68340_timer_module_device::write ) register (PREL1). TODO: make sure of the intial load of PREL1 on first falling flank */ if (m_cr & REG_CR_SWR) { + m_sr &= ~REG_SR_COM; if (m_cr & REG_CR_CPE) { m_sr |= REG_SR_ON; // Starts the counter @@ -202,13 +205,14 @@ WRITE16_MEMBER( mc68340_timer_module_device::write ) /* IRQ - Interrupt Request bit 1 = An interrupt condition has occurred. This bit is the logical OR of the enabled TO, TG, and TC interrupt bits. 0 = The bit(s) that caused the interrupt condition has been cleared. If an IRQ signal has been asserted, it is negated when this bit is cleared. */ - data = (m_sr & ~(data & (REG_SR_TO | REG_SR_TG | REG_SR_TC))); // Clear only the set interrupt bits - if ((data & (REG_SR_TO | REG_SR_TG | REG_SR_TC)) == 0) + m_sr &= ~(data & mem_mask & (REG_SR_TO | REG_SR_TG | REG_SR_TC)); // Clear only the set interrupt bits + if ((m_sr & (REG_SR_IRQ | REG_SR_TO | REG_SR_TG | REG_SR_TC)) == REG_SR_IRQ) { - data &= ~REG_SR_IRQ; - // TODO: clear IRQ line + LOGINT("TIMER IRQ cleared\n"); + m_sr &= ~REG_SR_IRQ; + m_cpu->update_ipl(); } - COMBINE_DATA(&m_sr); + data = m_sr; LOGTIMER("PC %08x %s %04x, %04x (%04x) (SR - Status/Prescaler Register)\n", m_cpu->pcbase(), FUNCNAME, offset * 2, data, mem_mask); LOGTIMER("- IRQ: %s\n", (data & REG_SR_IRQ) ? "Yes" : "None"); LOGTIMER("- TO TimeOut int : %s\n", (data & REG_SR_TO) ? "Asserted" : "Cleared"); @@ -238,6 +242,7 @@ WRITE16_MEMBER( mc68340_timer_module_device::write ) COMBINE_DATA(&m_com); LOGTIMER("PC %08x %s %04x, %04x (%04x) (COM - Compare Register)\n", m_cpu->pcbase(), FUNCNAME, offset * 2, data, mem_mask); LOGTIMER("- COM15-COM0: %04x\n", (data & 0xfff)); + m_sr &= ~REG_SR_COM; break; default: LOGTIMER("- %08x FUNCNAME %08x, %08x (%08x) - not implemented\n", m_cpu->pcbase(), offset * 2, data, mem_mask); @@ -267,10 +272,8 @@ WRITE_LINE_MEMBER( mc68340_timer_module_device::tgate_w) m_sr |= REG_SR_TG; if (m_cr & REG_CR_IE1) { - LOGTIMER(" - TG interrupt"); + LOGTIMER(" - TG interrupt\n"); do_timer_irq(); - m_sr |= REG_SR_IRQ; - } } m_sr |= REG_SR_TGL; @@ -307,27 +310,12 @@ void mc68340_timer_module_device::device_start() void mc68340_timer_module_device::do_timer_irq() { - assert(m_cpu->m_m68340SIM); - m68340_sim &sim = *m_cpu->m_m68340SIM; - int timer_irq_level = (m_ir & 0x0700) >> 8; - int timer_irq_vector = (m_ir & 0x00ff) >> 0; - - if (timer_irq_level) // 0 is irq disabled + assert((m_sr & (REG_SR_TO | REG_SR_TG | REG_SR_TC)) != 0); + if ((m_sr & REG_SR_IRQ) == 0) { - int use_autovector = (sim.m_avr_rsr >> (8 + timer_irq_level)) & 1; - - LOGINT("TIMER IRQ triggered, Lvl: %d using Vector: %d (0 = auto vector)\n", timer_irq_level, use_autovector ? 0 : timer_irq_vector); - - if (use_autovector) - { - //logerror("irq with autovector\n"); - m_cpu->set_input_line(timer_irq_level, HOLD_LINE); - } - else - { - //logerror("irq without autovector\n"); - m_cpu->set_input_line_and_vector(timer_irq_level, HOLD_LINE, timer_irq_vector); - } + LOGINT("TIMER IRQ triggered\n"); + m_sr |= REG_SR_IRQ; + m_cpu->update_ipl(); } } @@ -358,7 +346,7 @@ void mc68340_timer_module_device::do_timer_tick() affected by disabling the timer (SWR = 0).*/ if (m_cntr == m_com) // Check COM register { - m_sr |= (REG_SR_TC | REG_SR_COM); + m_sr |= REG_SR_COM; } } @@ -457,22 +445,22 @@ void mc68340_timer_module_device::do_timer_tick() if (m_cntr_reg == 0) // timer reached timeout value? { + m_sr &= ~REG_SR_COM; m_cntr = m_prel1; // TODO: Support prel2 for certain modes + m_sr |= REG_SR_TO; if (m_cr & REG_CR_IE2) { - LOGTIMER(" - TO interrupt"); + LOGTIMER(" - TO interrupt\n"); do_timer_irq(); - m_sr |= REG_SR_IRQ; } } if ((m_sr & REG_SR_COM) != 0) // timer reached compare value? ) { + m_sr |= REG_SR_TC; if (m_cr & REG_CR_IE0) { - LOGTIMER(" - TC interrupt"); + LOGTIMER(" - TC interrupt\n"); do_timer_irq(); - m_sr |= REG_SR_IRQ; - } } } diff --git a/src/devices/machine/68340tmu.h b/src/devices/machine/68340tmu.h index 005f66fba6d..0582debd475 100644 --- a/src/devices/machine/68340tmu.h +++ b/src/devices/machine/68340tmu.h @@ -22,6 +22,10 @@ public: DECLARE_WRITE_LINE_MEMBER( tin_w ); DECLARE_WRITE_LINE_MEMBER( tgate_w ); + uint8_t irq_level() const { return (m_sr & REG_SR_IRQ) ? (m_ir & REG_IR_INTLEV) >> 8 : 0; } + uint8_t irq_vector() const { return m_ir & REG_IR_INTVEC; } + uint8_t arbitrate(uint8_t level) const { return (irq_level() == level) ? (m_mcr & REG_MCR_ARBLV) : 0; } + protected: m68340_cpu_device *m_cpu; @@ -75,9 +79,9 @@ public: enum { REG_CR_SWR = 0x8000, REG_CR_INTMSK = 0x7000, - REG_CR_IE0 = 0x4000, + REG_CR_IE2 = 0x4000, REG_CR_IE1 = 0x2000, - REG_CR_IE2 = 0x1000, + REG_CR_IE0 = 0x1000, REG_CR_TGE = 0x0800, REG_CR_PCLK = 0x0400, REG_CR_CPE = 0x0200, |