From 0622928f226ca1c277bb1b77ce7b4c7ee908ef91 Mon Sep 17 00:00:00 2001 From: Lephe Date: Sun, 19 Jul 2020 20:06:50 +0200 Subject: [PATCH] rtc: robust interrupt handling and SH3 compatibility This commit changes the interrupt handler arrangement to support the PRI interrupt on SH3 (a gap is needed between 0xaa0 and its helper). It also introduces the use of the _gint_inth_callback function for the callback, which provides dynamic TLB during the interrupt, and revealed a bug about IMASK not being set automatically on SH3. Finally, it sets the interrupt settings of the RTC more conservatively, by wiping RCR1 and the carry, alarm and periodic interrupt flags during initialization and context restoration. --- src/core/inth.S | 8 ++++---- src/core/kernel.c | 1 + src/rtc/inth.s | 16 +++++++++------- src/rtc/rtc.c | 22 ++++++++++++++++------ 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/core/inth.S b/src/core/inth.S index 2cd6be2..2be849f 100644 --- a/src/core/inth.S +++ b/src/core/inth.S @@ -156,13 +156,13 @@ _gint_inth_7705: The VBR interrupt space on SH3 is laid out as follows: VBR offset SH3 events Description - ---------------------------------------------------------------- + ------------------------------------------------------------------- 0x200 400 420 440 --- TMU0, TMU1, TMU2 and a helper 0x280 f00 --- --- --- ETMU0, ETMU1, ETMU2 and a helper - 0x300 4a0 --- RTC Periodic Interrupt and a helper - ---------------------------------------------------------------- + 0x300 4a0 [ ] --- RTC Periodic Interrupt, gap and helper + ------------------------------------------------------------------- 0x600 --- --- Entry gate - ---------------------------------------------------------------- + ------------------------------------------------------------------- There is space for 16 gates at VBR + 0x200 so the VBR currently ends after the interrupt entry gate at VBR + 0x640. */ diff --git a/src/core/kernel.c b/src/core/kernel.c index 43b85bf..ad93f2b 100644 --- a/src/core/kernel.c +++ b/src/core/kernel.c @@ -155,6 +155,7 @@ static const uint16_t sh3_vbr_map[] = { 0xc40, /* ETMU2 underflow (used as helper on SH3) */ 0xc60, /* (gint custom: ETMU helper) */ 0xaa0, /* RTC Periodic Interrupt */ + 1, /* (Filler to maintain the gap between 0xaa0 and 0xae0) */ 0xae0, /* (gint custom: RTC helper) */ 0 }; diff --git a/src/rtc/inth.s b/src/rtc/inth.s index b21b5f7..5c067d8 100644 --- a/src/rtc/inth.s +++ b/src/rtc/inth.s @@ -14,17 +14,15 @@ _inth_rtc_pri: /* Invoke the callback function with its argument */ sts.l pr, @-r15 - mov.l 1f, r0 - mov.l 2f, r4 + mov.l .gint_inth_callback, r0 + mov.l 1f, r4 + mov.l 2f, r5 jsr @r0 nop /* Save the return value */ mov r0, r3 - /* Prepare to clear the interrupt flag */ - mov.l 3f, r1 - /* Jump to another gate to finish the work: - 0xc is the size of storage below - 0x20 is the size of the gap before next gate (alarm interrupt) */ @@ -34,12 +32,15 @@ _inth_rtc_pri: 1: .long 0 /* Callback function: edited dynamically */ 2: .long 0 /* Argument to callback function */ -3: .long 0xa413fede /* RCR2 address, edited at startup on SH3 */ + +.gint_inth_callback: + .long _gint_inth_callback _inth_rtc_pri_helper: .clear: /* Clear the interrupt flag */ + mov.l .RCR2, r1 mov.b @r1, r0 tst #0x80, r0 and #0x7f, r0 @@ -56,5 +57,6 @@ _inth_rtc_pri_helper: lds.l @r15+, pr rts nop + nop - .zero 8 +.RCR2: .long 0xa413fede /* RCR2 address, edited at startup on SH3 */ diff --git a/src/rtc/rtc.c b/src/rtc/rtc.c index 47231aa..c118e29 100644 --- a/src/rtc/rtc.c +++ b/src/rtc/rtc.c @@ -25,7 +25,6 @@ static rtc_t *RTC = &SH7305_RTC; GBSS static struct { void *function; uint32_t arg; - volatile uint8_t *RCR2; } GPACKED(4) *timer_params; //--- @@ -144,6 +143,12 @@ static void driver_sh3(void) static void init(void) { + /* Disable the carry and alarm interrupts (they share their IPR bits + with the periodic interrupt, which we want to enable) */ + RTC->RCR1.byte = 0; + /* Clear the periodic interrupt flag */ + RTC->RCR2.PEF = 0; + /* Interrupt handlers provided by rtc/inth.s */ extern void inth_rtc_pri(void); extern void inth_rtc_pri_helper(void); @@ -154,11 +159,15 @@ static void init(void) h1 = gint_inthandler(0xae0, inth_rtc_pri_helper, 32); timer_params = h0 + 20; - timer_params->RCR2 = &RTC->RCR2.byte; - /* Disable the periodic interrupt for now, but give it priority 5 */ + volatile uint8_t **RCR2_pointer = h1 + 28; + *RCR2_pointer = &RTC->RCR2.byte; + + /* Disable the RTC interrupts for now. Give them priority 1; higher + priorities cause freezes when going back to the system on SH3 + (TODO: Find out about the RTC interrupt problem on SH3) */ RTC->RCR2.PES = RTC_NONE; - intc_priority(INTC_RTC_PRI, 5); + intc_priority(INTC_RTC_PRI, 1); } //--- @@ -183,8 +192,9 @@ static void ctx_save(void *buf) static void ctx_restore(void *buf) { ctx_t *ctx = buf; - RTC->RCR1.byte = ctx->RCR1; - RTC->RCR2.byte = ctx->RCR2; + + RTC->RCR1.byte = ctx->RCR1 & 0x18; + RTC->RCR2.byte = ctx->RCR2 & 0x7f; } //---