tlsr82/tc32: optimize the irq process

1. using armv6-m arm_irq();
2. simplify the interrupt number get process;
3. To improve the performance, move common exception code to ram_code.

Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
This commit is contained in:
wangbowen6 2022-05-11 20:23:23 +08:00 committed by Xiang Xiao
parent 6caa8f1075
commit c39d3fa9e4
4 changed files with 253 additions and 317 deletions

View file

@ -68,11 +68,9 @@
.global __LOAD_DUT
.global __LOAD_FLASH
.extern g_current_regs
__start: @ MUST, referenced by boot.link
.extern irq_handler
.extern tc32_exception
.extern firmwareVersion
@ -388,176 +386,20 @@ IDLE_STACK:
@ src code for the irq proc part .
__irq:
/* Save R0 ~ R3, these registers will be used */
/* Save R0 ~ R3, these registers will be used before saved */
tpush {r0}
tpush {r1}
tpush {r2}
tpush {r3}
/* Switch to SVC mode to get the SVC mode SP, then save context
* into the interrupted task stack.
*/
/* Disable interrupt, because cpu will switch into SVC mode, interrupt
* nested should be prevented, this is not supported by tc32
* architecture.
*/
tloadr r0, _REG_IRQ_EN @ disable irq
tloadrb r1, [r0] @ get irq state in R1
tmov r2, #0 @ disable irq
tstorerb r2, [r0] @ disable irq
/* Switch to SVC mode and get the LR and SP in SVC mode */
tloadr r0, _REG_IRQ_EN + 4 @ switch to SVC mode
tnop
tmcsr r0 @ switch to SVC mode
tnop
tmov r2, r14 @ get SVC mode LR in R2
tmov r3, r13 @ get SVC mode SP in R3
tloadr r0, _REG_IRQ_EN + 8 @ return to IRQ mode
tnop
tmcsr r0 @ return to IRQ mode
tnop
/* R0 = the interrupted task SP after context save */
tmov r0, #XCPTCONTEXT_SIZE
tsub r0, r3, r0
/* Save IRQ_STATE, SVC mode SP and SVC mode LR as PC */
tstorer r1, [r0, #(4 * REG_IRQ_EN)]
tstorer r3, [r0, #(4 * REG_SP)]
tstorer r2, [r0, #(4 * REG_PC)]
/* Get SPSR and save as CPSR */
tmrss r1
tstorer r1, [r0, #(4 * REG_CPSR)]
/* Save IRQ mode LR as LR */
tmov r1, r14
tstorer r1, [r0, #(4 * REG_LR)]
/* Pop the saved R1 ~ R3 (pushed in beginning of irq),
* then save R1 ~ R7.
*/
tpop {r3}
tpop {r2}
tpop {r1}
tstorer r1, [r0, #(4 * REG_R1)]
tstorer r2, [r0, #(4 * REG_R2)]
tstorer r3, [r0, #(4 * REG_R3)]
tstorer r4, [r0, #(4 * REG_R4)]
tstorer r5, [r0, #(4 * REG_R5)]
tstorer r6, [r0, #(4 * REG_R6)]
tstorer r7, [r0, #(4 * REG_R7)]
/* Pop R0 and save it */
tpop {r1}
tstorer r1, [r0, #(4 * REG_R0)]
/* Save R8 ~ R12 */
tmov r1, r8
tstorer r1, [r0, #(4 * REG_R8)]
tmov r1, r9
tstorer r1, [r0, #(4 * REG_R9)]
tmov r1, r10
tstorer r1, [r0, #(4 * REG_R10)]
tmov r1, r11
tstorer r1, [r0, #(4 * REG_R11)]
tmov r1, r12
tstorer r1, [r0, #(4 * REG_R12)]
/* R0 = interrupted task SP after the context save */
tjl irq_handler
/* R0 = interrupted task SP after the context save (no context switch)
* = next task tcb->regs (with context switch)
* Restore all the register according to R0
*/
/* Dsiable interrupt to protect the SVC mode */
tloadr r2, _REG_IRQ_EN @ disable irq
tmov r3, #0 @ disable irq
tstorerb r3, [r2] @ disable irq
/* Restore SVC mode SP (R13), SVC mode LR (R14, based saved PC)
* PC is not need to retore */
tloadr r2, [r0, #(4 * REG_SP)]
tloadr r3, [r0, #(4 * REG_PC)]
tloadr r1, _REG_IRQ_EN + 4 @ switch to SVC mode
tnop
tmcsr r1 @ switch to SVC mode
tnop
tmov r14, r3 @ restore SVC mode LR
tmov r13, r2 @ restore SVC mode SP
tloadr r1, _REG_IRQ_EN + 8 @ return to IRQ mode
tnop
tmcsr r1 @ return to IRQ mode
tnop
/* Restore CPSR to SPSR, IRQ_STATE */
tloadr r2, [r0, #(4 * REG_CPSR)]
tloadr r3, [r0, #(4 * REG_IRQ_EN)]
tmssr r2 @ restore CPSR to SPSR
tloadr r1, _REG_IRQ_EN @ restore IRQ enable flag
tstorerb r3, [r1] @ restore IRQ enable flag
/* Restore R8 ~ R12, IRQ mode LR */
tloadr r2, [r0, #(4 * REG_R8)]
tloadr r3, [r0, #(4 * REG_R9)]
tloadr r4, [r0, #(4 * REG_R10)]
tloadr r5, [r0, #(4 * REG_R11)]
tloadr r6, [r0, #(4 * REG_R12)]
tloadr r7, [r0, #(4 * REG_LR)]
tmov r8, r2
tmov r9, r3
tmov r10, r4
tmov r11, r5
tmov r12, r6
tmov r14, r7
/* Restore R1 ~ R7 */
tloadr r1, [r0, #(4 * REG_R1)]
tloadr r2, [r0, #(4 * REG_R2)]
tloadr r3, [r0, #(4 * REG_R3)]
tloadr r4, [r0, #(4 * REG_R4)]
tloadr r5, [r0, #(4 * REG_R5)]
tloadr r6, [r0, #(4 * REG_R6)]
tloadr r7, [r0, #(4 * REG_R7)]
/* Restore R0 */
tloadr r0, [r0, #(4 * REG_R0)]
/* Return to interrupted task or next task */
/* Save LR, LR will change after tjl instruction */
tpush {r14}
treti {r15}
.align 4
_REG_IRQ_EN:
.word 0x00800643
.word 0x00000093
.word 0x00000092
/* Call tc32_exception */
tjl tc32_exception
ASMEND:
.section .bss

View file

@ -42,11 +42,12 @@ CMN_CSRCS := $(filter-out $(TC32_CSRCS_FILTER), $(CMN_CSRCS))
# Common files in arch/arm/src/armv6-m
CMN_CSRCS += arm_sigdeliver.c
CMN_CSRCS += arm_sigdeliver.c arm_doirq.c
# Common files in arch/arm/src/tlsr82/tc32
CMN_ASRCS += tc32_fullcontextrestore.S tc32_switchcontext.S tc32_saveusercontext.S
CMN_ASRCS += tc32_fullcontextrestore.S tc32_switchcontext.S
CMN_ASRCS += tc32_saveusercontext.S tc32_exception.S
CMN_CSRCS += tc32_doirq.c tc32_initialstate.c tc32_schedulesigaction.c
CMN_CSRCS += tc32_syscall.c tc32_udelay.c

View file

@ -37,8 +37,6 @@
#include "arm_internal.h"
#include "group/group.h"
#include "hardware/tlsr82_irq.h"
/****************************************************************************
@ -53,75 +51,10 @@
* Private Data
****************************************************************************/
static const uint8_t tc32_lowbit_bitmap[] =
{
0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 00 */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 10 */
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 20 */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 30 */
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 40 */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 50 */
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 60 */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 70 */
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 80 */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 90 */
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* A0 */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* B0 */
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* C0 */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* D0 */
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* E0 */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* F0 */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: tc32_ffs
*
* Description:
* This function finds the first bit set (beginning with the least
* significant bit) in value and return the index of that bit.
* TC32 archtecture does not support clz instruction.
*
* Parameters:
* uint32_t - value
*
* Return Value:
* [1, 32] - On Success.
* 0 - No set bit in value (value = 0).
*
****************************************************************************/
static inline int locate_code(".ram_code") tc32_ffs(uint32_t value)
{
int ret;
if (value == 0)
{
ret = 0;
}
else if (value & 0xff)
{
ret = (int)tc32_lowbit_bitmap[value & 0xff] + 1;
}
else if (value & 0xff00)
{
ret = (int)tc32_lowbit_bitmap[(value & 0xff00) >> 8] + 9;
}
else if (value & 0xff0000)
{
ret = (int)tc32_lowbit_bitmap[(value & 0xff0000) >> 16] + 17;
}
else
{
ret = (int)tc32_lowbit_bitmap[(value & 0xff000000) >> 24] + 25;
}
return ret;
}
/****************************************************************************
* Name: tc32_getirq
*
@ -141,22 +74,17 @@ static inline int locate_code(".ram_code") tc32_ffs(uint32_t value)
static int locate_code(".ram_code") tc32_getirq(void)
{
int irq;
uint32_t value;
/* Only detect the enable interrupt */
value = IRQ_SRC_REG & IRQ_MASK_REG;
irq = tc32_ffs(IRQ_SRC_REG & IRQ_MASK_REG);
if (irq > 0 && irq <= NR_IRQS)
if (value == 0)
{
/* Minus one to obatin the correct irq number */
irq = irq - 1;
irq = NR_IRQS;
}
else
{
/* Invalid irq number */
irq = NR_IRQS;
irq = __builtin_ctz(value);
}
return irq;
@ -166,82 +94,16 @@ static int locate_code(".ram_code") tc32_getirq(void)
* Public Functions
****************************************************************************/
/**
* @brief This function serves to handle the interrupt of MCU
* @param[in] none
* @return none
*/
/****************************************************************************
* Name: arm_ack_irq
*
* Description:
* Acknowledge the IRQ
*
****************************************************************************/
uint32_t *arm_doirq(int irq, uint32_t *regs)
void arm_ack_irq(int irq)
{
board_autoled_on(LED_INIRQ);
#ifdef CONFIG_SUPPRESS_INTERRUPTS
PANIC();
#else
/* Current regs non-zero indicates that we are processing an interrupt;
* g_current_regs is also used to manage interrupt level context switches.
*
* Nested interrupts are not supported
*/
DEBUGASSERT(CURRENT_REGS == NULL);
CURRENT_REGS = regs;
/* Disable further occurrences of this interrupt (until the interrupt
* sources have been clear by the driver).
*/
/* Deliver the IRQ */
irq_dispatch(irq, regs);
#if defined(CONFIG_ARCH_FPU) || defined(CONFIG_ARCH_ADDRENV)
/* Check for a context switch. If a context switch occurred, then
* g_current_regs will have a different value than it did on entry. If an
* interrupt level context switch has occurred, then restore the floating
* point state and the establish the correct address environment before
* returning from the interrupt.
*/
if (regs != CURRENT_REGS)
{
#ifdef CONFIG_ARCH_FPU
/* Restore floating point registers */
riscv_restorefpu(CURRENT_REGS);
#endif
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously
* running task is closed down gracefully (data caches dump,
* MMU flushed) and set up the address environment for the new
* thread at the head of the ready-to-run list.
*/
group_addrenv(NULL);
#endif
}
#endif
/* If a context switch occurred while processing the interrupt then
* g_current_regs may have change value. If we return any value different
* from the input regs, then the lower level will know that a context
* switch occurred during interrupt processing.
*/
regs = (uint32_t *)CURRENT_REGS;
/* Set g_current_regs to NULL to indicate that we are no longer in an
* interrupt handler.
*/
CURRENT_REGS = NULL;
/* Unmask the last interrupt (global interrupts are still disabled) */
#endif
board_autoled_off(LED_INIRQ);
return regs;
}
/****************************************************************************

View file

@ -0,0 +1,231 @@
/****************************************************************************
* arch/arm/src/tlsr82/tc32/tc32_exception.S
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <arch/chip/irq.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Symbols
****************************************************************************/
.file "tc32_exception.S"
/****************************************************************************
* Macros
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: tc32_exception
*
* Description:
* TC32 Common exception
*
****************************************************************************/
.align 2
.code 16
.thumb_func
.section .ram_code,"ax"
.extern irq_handler
.global tc32_exception
.type tc32_exception, function
tc32_exception:
/* Restore the R14 (LR) saved in __irq */
tpop {r3}
tmov r14, r3
/* Switch to SVC mode to get the SVC mode SP, then save context
* into the interrupted task stack.
*/
/* Disable interrupt, because cpu will switch into SVC mode, interrupt
* nested should be prevented, this is not supported by tc32
* architecture.
*/
tloadr r0, _REG_IRQ_EN /* disable irq */
tloadrb r1, [r0] /* get irq state in R1 */
tmov r2, #0 /* disable irq */
tstorerb r2, [r0] /* disable irq */
/* Switch to SVC mode and get the LR and SP in SVC mode */
tloadr r0, _REG_IRQ_EN + 4 /* switch to SVC mode */
tnop
tmcsr r0 /* switch to SVC mode */
tnop
tmov r2, r14 /* get SVC mode LR in R2 */
tmov r3, r13 /* get SVC mode SP in R3 */
tloadr r0, _REG_IRQ_EN + 8 /* return to IRQ mode */
tnop
tmcsr r0 /* return to IRQ mode */
tnop
/* R0 = the interrupted task SP after context save */
tmov r0, #XCPTCONTEXT_SIZE
tsub r0, r3, r0
/* Save IRQ_STATE, SVC mode SP and SVC mode LR as PC */
tstorer r1, [r0, #(4 * REG_IRQ_EN)]
tstorer r3, [r0, #(4 * REG_SP)]
tstorer r2, [r0, #(4 * REG_PC)]
/* Get SPSR and save as CPSR */
tmrss r1
tstorer r1, [r0, #(4 * REG_CPSR)]
/* Save IRQ mode LR as LR */
tmov r1, r14
tstorer r1, [r0, #(4 * REG_LR)]
/* Pop the saved R1 ~ R3 (pushed in beginning of irq),
* then save R1 ~ R7.
*/
tpop {r3}
tpop {r2}
tpop {r1}
tstorer r1, [r0, #(4 * REG_R1)]
tstorer r2, [r0, #(4 * REG_R2)]
tstorer r3, [r0, #(4 * REG_R3)]
tstorer r4, [r0, #(4 * REG_R4)]
tstorer r5, [r0, #(4 * REG_R5)]
tstorer r6, [r0, #(4 * REG_R6)]
tstorer r7, [r0, #(4 * REG_R7)]
/* Pop R0 and save it */
tpop {r1}
tstorer r1, [r0, #(4 * REG_R0)]
/* Save R8 ~ R12 */
tmov r1, r8
tstorer r1, [r0, #(4 * REG_R8)]
tmov r1, r9
tstorer r1, [r0, #(4 * REG_R9)]
tmov r1, r10
tstorer r1, [r0, #(4 * REG_R10)]
tmov r1, r11
tstorer r1, [r0, #(4 * REG_R11)]
tmov r1, r12
tstorer r1, [r0, #(4 * REG_R12)]
/* R0 = interrupted task SP after the context save */
tjl irq_handler
/* R0 = interrupted task SP after the context save (no context switch)
* = next task tcb->regs (with context switch)
* Restore all the register according to R0
*/
/* Dsiable interrupt to protect the SVC mode */
tloadr r2, _REG_IRQ_EN /* disable irq */
tmov r3, #0 /* disable irq */
tstorerb r3, [r2] /* disable irq */
/* Restore SVC mode SP (R13), SVC mode LR (R14, based saved PC)
* PC is not need to retore */
tloadr r2, [r0, #(4 * REG_SP)]
tloadr r3, [r0, #(4 * REG_PC)]
tloadr r1, _REG_IRQ_EN + 4 /* switch to SVC mode */
tnop
tmcsr r1 /* switch to SVC mode */
tnop
tmov r14, r3 /* restore SVC mode LR */
tmov r13, r2 /* restore SVC mode SP */
tloadr r1, _REG_IRQ_EN + 8 /* return to IRQ mode */
tnop
tmcsr r1 /* return to IRQ mode */
tnop
/* Restore CPSR to SPSR, IRQ_STATE */
tloadr r2, [r0, #(4 * REG_CPSR)]
tloadr r3, [r0, #(4 * REG_IRQ_EN)]
tmssr r2 /* restore CPSR to SPSR */
tloadr r1, _REG_IRQ_EN /* restore IRQ enable flag */
tstorerb r3, [r1] /* restore IRQ enable flag */
/* Restore R8 ~ R12, IRQ mode LR */
tloadr r2, [r0, #(4 * REG_R8)]
tloadr r3, [r0, #(4 * REG_R9)]
tloadr r4, [r0, #(4 * REG_R10)]
tloadr r5, [r0, #(4 * REG_R11)]
tloadr r6, [r0, #(4 * REG_R12)]
tloadr r7, [r0, #(4 * REG_LR)]
tmov r8, r2
tmov r9, r3
tmov r10, r4
tmov r11, r5
tmov r12, r6
tmov r14, r7
/* Restore R1 ~ R7 */
tloadr r1, [r0, #(4 * REG_R1)]
tloadr r2, [r0, #(4 * REG_R2)]
tloadr r3, [r0, #(4 * REG_R3)]
tloadr r4, [r0, #(4 * REG_R4)]
tloadr r5, [r0, #(4 * REG_R5)]
tloadr r6, [r0, #(4 * REG_R6)]
tloadr r7, [r0, #(4 * REG_R7)]
/* Restore R0 */
tloadr r0, [r0, #(4 * REG_R0)]
/* Return to interrupted task or next task */
tpush {r14}
treti {r15}
.align 4
_REG_IRQ_EN:
.word 0x00800643
.word 0x00000093
.word 0x00000092
.size tc32_exception, .-tc32_exception
.end