2020-12-24 08:30:36 -05:00
|
|
|
// Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
|
|
|
|
//
|
|
|
|
// Licensed 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.
|
|
|
|
|
2021-09-01 09:55:50 -04:00
|
|
|
|
|
|
|
#include <xtensa/coreasm.h>
|
|
|
|
#include <xtensa/corebits.h>
|
|
|
|
#include <xtensa/config/system.h>
|
|
|
|
#include "freertos/xtensa_context.h"
|
|
|
|
#include "sdkconfig.h"
|
|
|
|
#include "soc/soc.h"
|
|
|
|
|
2021-09-02 09:49:30 -04:00
|
|
|
#if CONFIG_BTDM_CTRL_HLI
|
|
|
|
|
2021-09-01 09:55:50 -04:00
|
|
|
/* Interrupt stack size, for C code.
|
|
|
|
* TODO: reduce and make configurable.
|
|
|
|
*/
|
|
|
|
#define L4_INTR_STACK_SIZE 4096
|
|
|
|
|
|
|
|
/* Save area for the CPU state:
|
|
|
|
* - 64 words for the general purpose registers
|
|
|
|
* - 7 words for some of the special registers:
|
|
|
|
* - WINDOWBASE, WINDOWSTART — only WINDOWSTART is truly needed
|
|
|
|
* - SAR, LBEG, LEND, LCOUNT — since the C code might use these
|
|
|
|
* - EPC1 — since the C code might cause window overflow exceptions
|
2020-12-24 08:30:36 -05:00
|
|
|
* This is not laid out as standard exception frame structure
|
2021-09-01 09:55:50 -04:00
|
|
|
* for simplicity of the save/restore code.
|
|
|
|
*/
|
|
|
|
#define REG_FILE_SIZE (64 * 4)
|
|
|
|
#define SPECREG_OFFSET REG_FILE_SIZE
|
|
|
|
#define SPECREG_SIZE (7 * 4)
|
2020-12-24 08:30:36 -05:00
|
|
|
#define REG_SAVE_AREA_SIZE (SPECREG_OFFSET + SPECREG_SIZE)
|
2021-09-01 09:55:50 -04:00
|
|
|
|
|
|
|
.data
|
|
|
|
_l4_intr_stack:
|
|
|
|
.space L4_INTR_STACK_SIZE
|
|
|
|
_l4_save_ctx:
|
|
|
|
.space REG_SAVE_AREA_SIZE
|
|
|
|
|
|
|
|
.section .iram1,"ax"
|
|
|
|
.global xt_highint4
|
|
|
|
.type xt_highint4,@function
|
|
|
|
.align 4
|
|
|
|
|
|
|
|
xt_highint4:
|
2021-09-02 08:54:21 -04:00
|
|
|
|
|
|
|
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
|
|
|
/*
|
|
|
|
Here, Timer2 is used to count a little time(50us).
|
|
|
|
The subsequent dram0 write operation is blocked due to live lock, which will
|
2020-12-24 08:30:36 -05:00
|
|
|
cause timer2 to timeout and trigger a level 5 interrupt.
|
2021-09-02 08:54:21 -04:00
|
|
|
*/
|
|
|
|
rsr.ccount a0
|
|
|
|
addmi a0, a0, (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ*50)
|
|
|
|
wsr a0, CCOMPARE2
|
|
|
|
|
|
|
|
/* Enable Timer 2 interrupt */
|
|
|
|
rsr a0, INTENABLE
|
|
|
|
extui a0, a0, 16, 1
|
|
|
|
bnez a0, 1f
|
|
|
|
movi a0, 0
|
2020-12-24 08:30:36 -05:00
|
|
|
xsr a0, INTENABLE /* disable all interrupts */
|
|
|
|
/* And a0 with (1 << 16) for Timer 2 interrupt mask */
|
2021-09-02 08:54:21 -04:00
|
|
|
addmi a0, a0, (1<<14)
|
|
|
|
addmi a0, a0, (1<<14)
|
|
|
|
addmi a0, a0, (1<<14)
|
|
|
|
addmi a0, a0, (1<<14)
|
2020-12-24 08:30:36 -05:00
|
|
|
wsr a0, INTENABLE /* Enable Timer 2 */
|
2021-09-02 08:54:21 -04:00
|
|
|
1:
|
|
|
|
#endif
|
|
|
|
|
2021-09-01 09:55:50 -04:00
|
|
|
movi a0, _l4_save_ctx
|
|
|
|
/* save 4 lower registers */
|
|
|
|
s32i a1, a0, 4
|
|
|
|
s32i a2, a0, 8
|
|
|
|
s32i a3, a0, 12
|
|
|
|
rsr a2, EXCSAVE_4 /* holds the value of a0 */
|
|
|
|
s32i a2, a0, 0
|
|
|
|
|
|
|
|
/* Save special registers */
|
|
|
|
addi a0, a0, SPECREG_OFFSET
|
|
|
|
rsr a2, WINDOWBASE
|
|
|
|
s32i a2, a0, 0
|
|
|
|
rsr a2, WINDOWSTART
|
|
|
|
s32i a2, a0, 4
|
|
|
|
rsr a2, SAR
|
|
|
|
s32i a2, a0, 8
|
|
|
|
rsr a2, LBEG
|
|
|
|
s32i a2, a0, 12
|
|
|
|
rsr a2, LEND
|
|
|
|
s32i a2, a0, 16
|
|
|
|
rsr a2, LCOUNT
|
|
|
|
s32i a2, a0, 20
|
|
|
|
rsr a2, EPC1
|
|
|
|
s32i a2, a0, 24
|
|
|
|
|
2021-09-02 08:54:21 -04:00
|
|
|
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
|
|
|
movi a0, 0
|
2020-12-24 08:30:36 -05:00
|
|
|
xsr a0, INTENABLE /* disable all interrupts */
|
2021-09-02 08:54:21 -04:00
|
|
|
movi a2, ~(1<<16)
|
|
|
|
and a0, a2, a0
|
|
|
|
wsr a0, INTENABLE
|
|
|
|
#endif
|
|
|
|
|
2021-09-01 09:55:50 -04:00
|
|
|
/* disable exception mode, window overflow */
|
2020-12-24 08:30:36 -05:00
|
|
|
movi a0, PS_INTLEVEL(5) | PS_EXCM
|
2021-09-01 09:55:50 -04:00
|
|
|
wsr a0, PS
|
|
|
|
rsync
|
|
|
|
|
|
|
|
/* Save the remaining physical registers.
|
|
|
|
* 4 registers are already saved, which leaves 60 registers to save.
|
|
|
|
* (FIXME: consider the case when the CPU is configured with physical 32 registers)
|
|
|
|
* These 60 registers are saved in 5 iterations, 12 registers at a time.
|
|
|
|
*/
|
|
|
|
movi a1, 5
|
|
|
|
movi a3, _l4_save_ctx + 4 * 4
|
|
|
|
|
|
|
|
/* This is repeated 5 times, each time the window is shifted by 12 registers.
|
|
|
|
* We come here with a1 = downcounter, a3 = save pointer, a2 and a0 unused.
|
|
|
|
*/
|
|
|
|
1:
|
|
|
|
s32i a4, a3, 0
|
|
|
|
s32i a5, a3, 4
|
|
|
|
s32i a6, a3, 8
|
|
|
|
s32i a7, a3, 12
|
|
|
|
s32i a8, a3, 16
|
|
|
|
s32i a9, a3, 20
|
|
|
|
s32i a10, a3, 24
|
|
|
|
s32i a11, a3, 28
|
|
|
|
s32i a12, a3, 32
|
|
|
|
s32i a13, a3, 36
|
|
|
|
s32i a14, a3, 40
|
|
|
|
s32i a15, a3, 44
|
|
|
|
|
|
|
|
/* We are about to rotate the window, so that a12-a15 will become the new a0-a3.
|
|
|
|
* Copy a0-a3 to a12-15 to still have access to these values.
|
|
|
|
* At the same time we can decrement the counter and adjust the save area pointer
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* a0 is constant (_l4_save_ctx), no need to copy */
|
|
|
|
addi a13, a1, -1 /* copy and decrement the downcounter */
|
|
|
|
/* a2 is scratch so no need to copy */
|
|
|
|
addi a15, a3, 48 /* copy and adjust the save area pointer */
|
|
|
|
beqz a13, 2f /* have saved all registers ? */
|
|
|
|
rotw 3 /* rotate the window and go back */
|
|
|
|
j 1b
|
|
|
|
|
|
|
|
/* the loop is complete */
|
|
|
|
2:
|
|
|
|
rotw 4 /* this brings us back to the original window */
|
|
|
|
/* a0 still points to _l4_save_ctx */
|
|
|
|
|
|
|
|
/* Can clear WINDOWSTART now, all registers are saved */
|
|
|
|
rsr a2, WINDOWBASE
|
|
|
|
/* WINDOWSTART = (1 << WINDOWBASE) */
|
|
|
|
movi a3, 1
|
|
|
|
ssl a2
|
|
|
|
sll a3, a3
|
|
|
|
wsr a3, WINDOWSTART
|
|
|
|
|
|
|
|
_highint4_stack_switch:
|
|
|
|
movi a0, 0
|
|
|
|
movi sp, _l4_intr_stack + L4_INTR_STACK_SIZE - 16
|
|
|
|
s32e a0, sp, -12 /* For GDB: set null SP */
|
|
|
|
s32e a0, sp, -16 /* For GDB: set null PC */
|
|
|
|
movi a0, _highint4_stack_switch /* For GDB: cosmetics, for the frame where stack switch happened */
|
|
|
|
|
|
|
|
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
|
|
|
|
movi a6, PS_INTLEVEL(4) | PS_UM | PS_WOE
|
|
|
|
wsr a6, PS
|
|
|
|
rsync
|
|
|
|
|
|
|
|
/* Call C handler */
|
|
|
|
mov a6, sp
|
|
|
|
call4 hli_c_handler
|
|
|
|
|
|
|
|
l32e sp, sp, -12 /* switch back to the original stack */
|
|
|
|
|
|
|
|
/* Done with C handler; re-enable exception mode, disabling window overflow */
|
|
|
|
movi a2, PS_INTLEVEL(5) | PS_EXCM /* TOCHECK */
|
|
|
|
wsr a2, PS
|
|
|
|
rsync
|
|
|
|
|
|
|
|
/* Restore the special registers.
|
|
|
|
* WINDOWSTART will be restored near the end.
|
|
|
|
*/
|
|
|
|
movi a0, _l4_save_ctx + SPECREG_OFFSET
|
|
|
|
l32i a2, a0, 8
|
|
|
|
wsr a2, SAR
|
|
|
|
l32i a2, a0, 12
|
|
|
|
wsr a2, LBEG
|
|
|
|
l32i a2, a0, 16
|
|
|
|
wsr a2, LEND
|
|
|
|
l32i a2, a0, 20
|
|
|
|
wsr a2, LCOUNT
|
|
|
|
l32i a2, a0, 24
|
|
|
|
wsr a2, EPC1
|
|
|
|
|
|
|
|
/* Restoring the physical registers.
|
|
|
|
* This is the reverse to the saving process above.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Rotate back to the final window, then start loading 12 registers at a time,
|
|
|
|
* in 5 iterations.
|
|
|
|
* Again, a1 is the downcounter and a3 is the save area pointer.
|
|
|
|
* After each rotation, a1 and a3 are copied from a13 and a15.
|
|
|
|
* To simplify the loop, we put the initial values into a13 and a15.
|
|
|
|
*/
|
|
|
|
rotw -4
|
|
|
|
movi a15, _l4_save_ctx + 64 * 4 /* point to the end of the save area */
|
|
|
|
movi a13, 5
|
|
|
|
|
|
|
|
1:
|
|
|
|
/* Copy a1 and a3 from their previous location,
|
|
|
|
* at the same time decrementing and adjusting the save area pointer.
|
|
|
|
*/
|
|
|
|
addi a1, a13, -1
|
|
|
|
addi a3, a15, -48
|
|
|
|
|
|
|
|
/* Load 12 registers */
|
|
|
|
l32i a4, a3, 0
|
|
|
|
l32i a5, a3, 4
|
|
|
|
l32i a6, a3, 8
|
|
|
|
l32i a7, a3, 12
|
|
|
|
l32i a8, a3, 16
|
|
|
|
l32i a9, a3, 20
|
|
|
|
l32i a10, a3, 24
|
|
|
|
l32i a11, a3, 28 /* ensure PS and EPC written */
|
|
|
|
l32i a12, a3, 32
|
|
|
|
l32i a13, a3, 36
|
|
|
|
l32i a14, a3, 40
|
|
|
|
l32i a15, a3, 44
|
|
|
|
|
|
|
|
/* Done with the loop? */
|
|
|
|
beqz a1, 2f
|
|
|
|
/* If no, rotate the window and repeat */
|
|
|
|
rotw -3
|
|
|
|
j 1b
|
|
|
|
|
|
|
|
2:
|
|
|
|
/* Done with the loop. Only 4 registers (a0-a3 in the original window) remain
|
|
|
|
* to be restored. Also need to restore WINDOWSTART, since all the general
|
|
|
|
* registers are now in place.
|
|
|
|
*/
|
|
|
|
movi a0, _l4_save_ctx
|
|
|
|
|
|
|
|
l32i a2, a0, SPECREG_OFFSET + 4
|
|
|
|
wsr a2, WINDOWSTART
|
|
|
|
|
|
|
|
l32i a1, a0, 4
|
|
|
|
l32i a2, a0, 8
|
|
|
|
l32i a3, a0, 12
|
|
|
|
rsr a0, EXCSAVE_4 /* holds the value of a0 before the interrupt handler */
|
|
|
|
|
|
|
|
/* Return from the interrupt, restoring PS from EPS_4 */
|
|
|
|
rfi 4
|
|
|
|
|
2021-09-02 09:49:30 -04:00
|
|
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
|
|
|
|
2021-09-01 09:55:50 -04:00
|
|
|
/* The linker has no reason to link in this file; all symbols it exports are already defined
|
|
|
|
(weakly!) in the default int handler. Define a symbol here so we can use it to have the
|
|
|
|
linker inspect this anyway. */
|
|
|
|
|
|
|
|
.global ld_include_hli_vectors_bt
|
|
|
|
ld_include_hli_vectors_bt:
|