Merge pull request #12276 from kenrabold/pr-fe310_intr_cleanup
cpu/fe310: interrupt handling cleanup
This commit is contained in:
commit
1543a8c438
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 JP Bonn
|
* Copyright (C) 2017, 2019 JP Bonn, Ken Rabold
|
||||||
*
|
*
|
||||||
* This file is subject to the terms and conditions of the GNU Lesser
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
* General Public License v2.1. See the file LICENSE in the top level
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
@ -40,8 +40,6 @@ static void check_context_switch_frame_alignment(void)
|
|||||||
"Stack pointer should be 16 byte aligned");
|
"Stack pointer should be 16 byte aligned");
|
||||||
_Static_assert(sizeof(struct context_switch_frame) == CONTEXT_FRAME_SIZE,
|
_Static_assert(sizeof(struct context_switch_frame) == CONTEXT_FRAME_SIZE,
|
||||||
"context_switch_frame size mismatch");
|
"context_switch_frame size mismatch");
|
||||||
CHECK_OFFSET(pad);
|
|
||||||
CHECK_OFFSET(pc);
|
|
||||||
CHECK_OFFSET(s0);
|
CHECK_OFFSET(s0);
|
||||||
CHECK_OFFSET(s1);
|
CHECK_OFFSET(s1);
|
||||||
CHECK_OFFSET(s2);
|
CHECK_OFFSET(s2);
|
||||||
@ -55,7 +53,6 @@ static void check_context_switch_frame_alignment(void)
|
|||||||
CHECK_OFFSET(s10);
|
CHECK_OFFSET(s10);
|
||||||
CHECK_OFFSET(s11);
|
CHECK_OFFSET(s11);
|
||||||
CHECK_OFFSET(ra);
|
CHECK_OFFSET(ra);
|
||||||
CHECK_OFFSET(tp);
|
|
||||||
CHECK_OFFSET(t0);
|
CHECK_OFFSET(t0);
|
||||||
CHECK_OFFSET(t1);
|
CHECK_OFFSET(t1);
|
||||||
CHECK_OFFSET(t2);
|
CHECK_OFFSET(t2);
|
||||||
@ -71,6 +68,8 @@ static void check_context_switch_frame_alignment(void)
|
|||||||
CHECK_OFFSET(a5);
|
CHECK_OFFSET(a5);
|
||||||
CHECK_OFFSET(a6);
|
CHECK_OFFSET(a6);
|
||||||
CHECK_OFFSET(a7);
|
CHECK_OFFSET(a7);
|
||||||
|
CHECK_OFFSET(pc);
|
||||||
|
CHECK_OFFSET(pad);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* also check the SP offset in the _frame structure
|
* also check the SP offset in the _frame structure
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 Ken Rabold, JP Bonn
|
* Copyright (C) 2017, 2019 Ken Rabold, JP Bonn
|
||||||
*
|
*
|
||||||
* This file is subject to the terms and conditions of the GNU Lesser
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
* General Public License v2.1. See the file LICENSE in the top level
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
@ -39,8 +40,8 @@
|
|||||||
|
|
||||||
volatile int __in_isr = 0;
|
volatile int __in_isr = 0;
|
||||||
|
|
||||||
|
/* ISR trap vector */
|
||||||
void trap_entry(void);
|
void trap_entry(void);
|
||||||
void thread_start(void);
|
|
||||||
|
|
||||||
/* PLIC external ISR function list */
|
/* PLIC external ISR function list */
|
||||||
static external_isr_ptr_t _ext_isrs[PLIC_NUM_INTERRUPTS];
|
static external_isr_ptr_t _ext_isrs[PLIC_NUM_INTERRUPTS];
|
||||||
@ -160,8 +161,12 @@ void external_isr(void)
|
|||||||
/**
|
/**
|
||||||
* @brief Global trap and interrupt handler
|
* @brief Global trap and interrupt handler
|
||||||
*/
|
*/
|
||||||
void handle_trap(unsigned int mcause)
|
void handle_trap(unsigned int mcause, unsigned int mepc, unsigned int mtval)
|
||||||
{
|
{
|
||||||
|
#ifndef DEVELHELP
|
||||||
|
(void) mepc;
|
||||||
|
(void) mtval;
|
||||||
|
#endif
|
||||||
/* Tell RIOT to set sched_context_switch_request instead of
|
/* Tell RIOT to set sched_context_switch_request instead of
|
||||||
* calling thread_yield(). */
|
* calling thread_yield(). */
|
||||||
__in_isr = 1;
|
__in_isr = 1;
|
||||||
@ -170,6 +175,12 @@ void handle_trap(unsigned int mcause)
|
|||||||
if ((mcause & MCAUSE_INT) == MCAUSE_INT) {
|
if ((mcause & MCAUSE_INT) == MCAUSE_INT) {
|
||||||
/* Cause is an interrupt - determine type */
|
/* Cause is an interrupt - determine type */
|
||||||
switch (mcause & MCAUSE_CAUSE) {
|
switch (mcause & MCAUSE_CAUSE) {
|
||||||
|
case IRQ_M_SOFT:
|
||||||
|
/* Handle software interrupt - flag for context switch */
|
||||||
|
sched_context_switch_request = 1;
|
||||||
|
CLINT_REG(0) = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
#ifdef MODULE_PERIPH_TIMER
|
#ifdef MODULE_PERIPH_TIMER
|
||||||
case IRQ_M_TIMER:
|
case IRQ_M_TIMER:
|
||||||
/* Handle timer interrupt */
|
/* Handle timer interrupt */
|
||||||
@ -188,10 +199,21 @@ void handle_trap(unsigned int mcause)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
#ifdef DEVELHELP
|
||||||
|
printf("Unhandled trap:\n");
|
||||||
|
printf(" mcause: 0x%08x\n", mcause);
|
||||||
|
printf(" mepc: 0x%08x\n", mepc);
|
||||||
|
printf(" mtval: 0x%08x\n", mtval);
|
||||||
|
#endif
|
||||||
/* Unknown trap */
|
/* Unknown trap */
|
||||||
core_panic(PANIC_GENERAL_ERROR, "Unhandled trap");
|
core_panic(PANIC_GENERAL_ERROR, "Unhandled trap");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if context change was requested */
|
||||||
|
if (sched_context_switch_request) {
|
||||||
|
sched_run();
|
||||||
|
}
|
||||||
|
|
||||||
/* ISR done - no more changes to thread states */
|
/* ISR done - no more changes to thread states */
|
||||||
__in_isr = 0;
|
__in_isr = 0;
|
||||||
}
|
}
|
||||||
@ -253,7 +275,6 @@ char *thread_stack_init(thread_task_func_t task_func,
|
|||||||
int stack_size)
|
int stack_size)
|
||||||
{
|
{
|
||||||
struct context_switch_frame *sf;
|
struct context_switch_frame *sf;
|
||||||
uint32_t *reg;
|
|
||||||
uint32_t *stk_top;
|
uint32_t *stk_top;
|
||||||
|
|
||||||
/* calculate the top of the stack */
|
/* calculate the top of the stack */
|
||||||
@ -275,11 +296,10 @@ char *thread_stack_init(thread_task_func_t task_func,
|
|||||||
/* populate the stack frame with default values for starting the thread. */
|
/* populate the stack frame with default values for starting the thread. */
|
||||||
sf = (struct context_switch_frame *) stk_top;
|
sf = (struct context_switch_frame *) stk_top;
|
||||||
|
|
||||||
/* a7 is register with highest memory address in frame */
|
/* Clear stack frame */
|
||||||
reg = &sf->a7;
|
memset(sf, 0, sizeof(*sf));
|
||||||
while (reg != &sf->pc) {
|
|
||||||
*reg-- = 0;
|
/* set initial reg values */
|
||||||
}
|
|
||||||
sf->pc = (uint32_t) task_func;
|
sf->pc = (uint32_t) task_func;
|
||||||
sf->a0 = (uint32_t) arg;
|
sf->a0 = (uint32_t) arg;
|
||||||
|
|
||||||
@ -292,7 +312,11 @@ char *thread_stack_init(thread_task_func_t task_func,
|
|||||||
void thread_print_stack(void)
|
void thread_print_stack(void)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
uint32_t *sp = (uint32_t *) sched_active_thread->sp;
|
uint32_t *sp = (uint32_t *) ((sched_active_thread) ? sched_active_thread->sp : NULL);
|
||||||
|
|
||||||
|
if (sp == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
printf("printing the current stack of thread %" PRIkernel_pid "\n",
|
printf("printing the current stack of thread %" PRIkernel_pid "\n",
|
||||||
thread_getpid());
|
thread_getpid());
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 JP Bonn
|
* Copyright (C) 2017, 2019 JP Bonn, Ken Rabold
|
||||||
*
|
*
|
||||||
* This file is subject to the terms and conditions of the GNU Lesser
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
* General Public License v2.1. See the file LICENSE in the top level
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
@ -40,8 +40,6 @@ extern "C" {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct context_switch_frame {
|
struct context_switch_frame {
|
||||||
uint32_t pad[2]; /**< padding to maintain 16 byte alignment */
|
|
||||||
uint32_t pc; /**< program counter */
|
|
||||||
/* Callee saved registers */
|
/* Callee saved registers */
|
||||||
uint32_t s0; /**< s0 register */
|
uint32_t s0; /**< s0 register */
|
||||||
uint32_t s1; /**< s1 register */
|
uint32_t s1; /**< s1 register */
|
||||||
@ -57,7 +55,6 @@ struct context_switch_frame {
|
|||||||
uint32_t s11; /**< s11 register */
|
uint32_t s11; /**< s11 register */
|
||||||
/* Caller saved registers */
|
/* Caller saved registers */
|
||||||
uint32_t ra; /**< ra register */
|
uint32_t ra; /**< ra register */
|
||||||
uint32_t tp; /**< tp register */
|
|
||||||
uint32_t t0; /**< t0 register */
|
uint32_t t0; /**< t0 register */
|
||||||
uint32_t t1; /**< t1 register */
|
uint32_t t1; /**< t1 register */
|
||||||
uint32_t t2; /**< t2 register */
|
uint32_t t2; /**< t2 register */
|
||||||
@ -73,6 +70,9 @@ struct context_switch_frame {
|
|||||||
uint32_t a5; /**< a5 register */
|
uint32_t a5; /**< a5 register */
|
||||||
uint32_t a6; /**< a6 register */
|
uint32_t a6; /**< a6 register */
|
||||||
uint32_t a7; /**< a7 register */
|
uint32_t a7; /**< a7 register */
|
||||||
|
/* Saved PC for return from ISR */
|
||||||
|
uint32_t pc; /**< program counter */
|
||||||
|
uint32_t pad[3]; /**< padding to maintain 16 byte alignment */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __ASSEMBLER__ */
|
#endif /* __ASSEMBLER__ */
|
||||||
@ -83,43 +83,42 @@ struct context_switch_frame {
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
/* These values are checked for correctness in context_frame.c */
|
/* These values are checked for correctness in context_frame.c */
|
||||||
#define pad_OFFSET 0
|
#define s0_OFFSET 0
|
||||||
#define pc_OFFSET 8
|
#define s1_OFFSET 4
|
||||||
#define s0_OFFSET 12
|
#define s2_OFFSET 8
|
||||||
#define s1_OFFSET 16
|
#define s3_OFFSET 12
|
||||||
#define s2_OFFSET 20
|
#define s4_OFFSET 16
|
||||||
#define s3_OFFSET 24
|
#define s5_OFFSET 20
|
||||||
#define s4_OFFSET 28
|
#define s6_OFFSET 24
|
||||||
#define s5_OFFSET 32
|
#define s7_OFFSET 28
|
||||||
#define s6_OFFSET 36
|
#define s8_OFFSET 32
|
||||||
#define s7_OFFSET 40
|
#define s9_OFFSET 36
|
||||||
#define s8_OFFSET 44
|
#define s10_OFFSET 40
|
||||||
#define s9_OFFSET 48
|
#define s11_OFFSET 44
|
||||||
#define s10_OFFSET 52
|
#define ra_OFFSET 48
|
||||||
#define s11_OFFSET 56
|
#define t0_OFFSET 52
|
||||||
#define ra_OFFSET 60
|
#define t1_OFFSET 56
|
||||||
#define tp_OFFSET 64
|
#define t2_OFFSET 60
|
||||||
#define t0_OFFSET 68
|
#define t3_OFFSET 64
|
||||||
#define t1_OFFSET 72
|
#define t4_OFFSET 68
|
||||||
#define t2_OFFSET 76
|
#define t5_OFFSET 72
|
||||||
#define t3_OFFSET 80
|
#define t6_OFFSET 76
|
||||||
#define t4_OFFSET 84
|
#define a0_OFFSET 80
|
||||||
#define t5_OFFSET 88
|
#define a1_OFFSET 84
|
||||||
#define t6_OFFSET 92
|
#define a2_OFFSET 88
|
||||||
#define a0_OFFSET 96
|
#define a3_OFFSET 92
|
||||||
#define a1_OFFSET 100
|
#define a4_OFFSET 96
|
||||||
#define a2_OFFSET 104
|
#define a5_OFFSET 100
|
||||||
#define a3_OFFSET 108
|
#define a6_OFFSET 104
|
||||||
#define a4_OFFSET 112
|
#define a7_OFFSET 108
|
||||||
#define a5_OFFSET 116
|
#define pc_OFFSET 112
|
||||||
#define a6_OFFSET 120
|
#define pad_OFFSET 116
|
||||||
#define a7_OFFSET 124
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Size of context switch frame
|
* @brief Size of context switch frame
|
||||||
*/
|
*/
|
||||||
#define CONTEXT_FRAME_SIZE (a7_OFFSET + 4)
|
#define CONTEXT_FRAME_SIZE (pad_OFFSET + 12)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Offset of stack pointer in struct _thread
|
* @brief Offset of stack pointer in struct _thread
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 JP Bonn
|
* Copyright (C) 2017, 2019 JP Bonn, Ken Rabold
|
||||||
*
|
*
|
||||||
* This file is subject to the terms and conditions of the GNU Lesser
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
* General Public License v2.1. See the file LICENSE in the top level
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
@ -9,22 +9,12 @@
|
|||||||
#include "vendor/encoding.h"
|
#include "vendor/encoding.h"
|
||||||
#include "context_frame.h"
|
#include "context_frame.h"
|
||||||
|
|
||||||
/* from platform.h TODO:fix this hard code.... */
|
|
||||||
CLINT_CTRL_ADDR = 0x02000000
|
|
||||||
|
|
||||||
.section .text.entry
|
.section .text.entry
|
||||||
.align 2
|
.align 2
|
||||||
.global trap_entry
|
.global trap_entry
|
||||||
|
|
||||||
trap_entry:
|
trap_entry:
|
||||||
/*
|
/* Save registers to stack */
|
||||||
* Save all regs on the currently active stack.
|
|
||||||
* This coule be the active thread's stack,
|
|
||||||
* or if no thread is active, it is saved on ISR stack
|
|
||||||
* (if initial startup) or on the deactivated threads
|
|
||||||
* stack (in the case of thread exit). In the latter
|
|
||||||
* two cases the stack is just abandoned.
|
|
||||||
*/
|
|
||||||
addi sp, sp, -CONTEXT_FRAME_SIZE
|
addi sp, sp, -CONTEXT_FRAME_SIZE
|
||||||
|
|
||||||
sw s0, s0_OFFSET(sp)
|
sw s0, s0_OFFSET(sp)
|
||||||
@ -40,7 +30,6 @@ trap_entry:
|
|||||||
sw s10, s10_OFFSET(sp)
|
sw s10, s10_OFFSET(sp)
|
||||||
sw s11, s11_OFFSET(sp)
|
sw s11, s11_OFFSET(sp)
|
||||||
sw ra, ra_OFFSET(sp)
|
sw ra, ra_OFFSET(sp)
|
||||||
sw tp, tp_OFFSET(sp)
|
|
||||||
sw t0, t0_OFFSET(sp)
|
sw t0, t0_OFFSET(sp)
|
||||||
sw t1, t1_OFFSET(sp)
|
sw t1, t1_OFFSET(sp)
|
||||||
sw t2, t2_OFFSET(sp)
|
sw t2, t2_OFFSET(sp)
|
||||||
@ -58,33 +47,40 @@ trap_entry:
|
|||||||
sw a7, a7_OFFSET(sp)
|
sw a7, a7_OFFSET(sp)
|
||||||
|
|
||||||
|
|
||||||
/* Get the interrupt cause */
|
/* Get the interrupt cause, PC, and address */
|
||||||
csrr a0, mcause
|
csrr a0, mcause
|
||||||
|
csrr a1, mepc
|
||||||
|
csrr a2, mtval
|
||||||
|
|
||||||
/* Save active thread stack pointer in a callee save register */
|
/* Save return PC in stack frame */
|
||||||
mv s1, sp
|
sw a1, pc_OFFSET(sp)
|
||||||
|
|
||||||
|
/* Get the active thread (could be NULL) */
|
||||||
|
lw tp, sched_active_thread
|
||||||
|
beqz tp, null_thread
|
||||||
|
|
||||||
|
/* Save stack pointer of current thread */
|
||||||
|
sw sp, SP_OFFSET_IN_THREAD(tp)
|
||||||
|
|
||||||
|
null_thread:
|
||||||
/* Switch to ISR stack. Interrupts are not nested so use fixed
|
/* Switch to ISR stack. Interrupts are not nested so use fixed
|
||||||
* starting address and just abandon stack when finished. */
|
* starting address and just abandon stack when finished. */
|
||||||
la sp, _sp
|
la sp, _sp
|
||||||
addi sp, sp, -4
|
|
||||||
|
|
||||||
/* Is it a software interrupt? */
|
/* Call handle_trap with MCAUSE and MEPC register value as args */
|
||||||
li t0, 0x80000003
|
call handle_trap
|
||||||
beq a0, t0, context_switch
|
|
||||||
|
|
||||||
/* Call handle_trap with MCAUSE register value as arg */
|
/* Get the active thread (guaranteed to be non NULL) */
|
||||||
jal handle_trap
|
lw tp, sched_active_thread
|
||||||
|
|
||||||
/* See if a context switch was requested by the ISR */
|
/* Load the thread SP of scheduled thread */
|
||||||
lw a0, sched_context_switch_request
|
lw sp, SP_OFFSET_IN_THREAD(tp)
|
||||||
bnez a0, context_switch
|
|
||||||
|
|
||||||
/* Restore active thread stack pointer */
|
/* Set return PC */
|
||||||
mv sp, s1
|
lw a1, pc_OFFSET(sp)
|
||||||
|
csrw mepc, a1
|
||||||
|
|
||||||
/* Restore remaining registers */
|
/* Restore registers from stack */
|
||||||
trap_exit:
|
|
||||||
lw s0, s0_OFFSET(sp)
|
lw s0, s0_OFFSET(sp)
|
||||||
lw s1, s1_OFFSET(sp)
|
lw s1, s1_OFFSET(sp)
|
||||||
lw s2, s2_OFFSET(sp)
|
lw s2, s2_OFFSET(sp)
|
||||||
@ -98,7 +94,6 @@ trap_exit:
|
|||||||
lw s10, s10_OFFSET(sp)
|
lw s10, s10_OFFSET(sp)
|
||||||
lw s11, s11_OFFSET(sp)
|
lw s11, s11_OFFSET(sp)
|
||||||
lw ra, ra_OFFSET(sp)
|
lw ra, ra_OFFSET(sp)
|
||||||
lw tp, tp_OFFSET(sp)
|
|
||||||
lw t0, t0_OFFSET(sp)
|
lw t0, t0_OFFSET(sp)
|
||||||
lw t1, t1_OFFSET(sp)
|
lw t1, t1_OFFSET(sp)
|
||||||
lw t2, t2_OFFSET(sp)
|
lw t2, t2_OFFSET(sp)
|
||||||
@ -117,35 +112,3 @@ trap_exit:
|
|||||||
|
|
||||||
addi sp, sp, CONTEXT_FRAME_SIZE
|
addi sp, sp, CONTEXT_FRAME_SIZE
|
||||||
mret
|
mret
|
||||||
|
|
||||||
|
|
||||||
context_switch:
|
|
||||||
/* clear the software interrupt */
|
|
||||||
li t0, CLINT_CTRL_ADDR
|
|
||||||
sw zero, (t0)
|
|
||||||
|
|
||||||
/* save the active thread's PC prior to interrupt on the stack */
|
|
||||||
csrr a0, mepc
|
|
||||||
sw a0, pc_OFFSET(s1)
|
|
||||||
|
|
||||||
/* get the active thread - it may be 0 if none currently active */
|
|
||||||
lw t0, sched_active_thread
|
|
||||||
/* was there a previously running thread? */
|
|
||||||
beqz t0, no_sp_save
|
|
||||||
/* if so, save the thread's SP in the _thread structure */
|
|
||||||
sw s1,SP_OFFSET_IN_THREAD(t0)
|
|
||||||
|
|
||||||
no_sp_save:
|
|
||||||
/* all current thread state is saved - schedule a new thread */
|
|
||||||
call sched_run
|
|
||||||
lw tp, sched_active_thread
|
|
||||||
|
|
||||||
/* set the threads SP from the newly scheduled thread
|
|
||||||
* and abandon ISR stack. */
|
|
||||||
lw sp, SP_OFFSET_IN_THREAD(tp)
|
|
||||||
|
|
||||||
/* restore the PC */
|
|
||||||
lw a0, pc_OFFSET(sp)
|
|
||||||
csrw mepc, a0
|
|
||||||
|
|
||||||
j trap_exit
|
|
||||||
|
|||||||
177
cpu/fe310/ldscripts/fe310_base.ld
Normal file
177
cpu/fe310/ldscripts/fe310_base.ld
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017, 2019 Ken Rabold
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup cpu_fe310
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Common linker directives for the SiFive FE310
|
||||||
|
*
|
||||||
|
* @author Ken Rabold
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
OUTPUT_ARCH( "riscv" )
|
||||||
|
|
||||||
|
ENTRY( _start )
|
||||||
|
|
||||||
|
PHDRS
|
||||||
|
{
|
||||||
|
flash PT_LOAD;
|
||||||
|
ram_init PT_LOAD;
|
||||||
|
ram PT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
__stack_size = DEFINED(__stack_size) ? __stack_size : 256;
|
||||||
|
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.init)))
|
||||||
|
} >flash AT>flash :flash
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text.unlikely .text.unlikely.*)
|
||||||
|
*(.text.startup .text.startup.*)
|
||||||
|
*(.text .text.*)
|
||||||
|
*(.gnu.linkonce.t.*)
|
||||||
|
} >flash AT>flash :flash
|
||||||
|
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.fini)))
|
||||||
|
} >flash AT>flash :flash
|
||||||
|
|
||||||
|
PROVIDE (__etext = .);
|
||||||
|
PROVIDE (_etext = .);
|
||||||
|
PROVIDE (etext = .);
|
||||||
|
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
*(.rdata)
|
||||||
|
*(.rodata .rodata.*)
|
||||||
|
*(.gnu.linkonce.r.*)
|
||||||
|
} >flash AT>flash :flash
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
|
||||||
|
.preinit_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||||
|
} >flash AT>flash :flash
|
||||||
|
|
||||||
|
.init_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__init_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||||
|
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
|
||||||
|
PROVIDE_HIDDEN (__init_array_end = .);
|
||||||
|
} >flash AT>flash :flash
|
||||||
|
|
||||||
|
.fini_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||||
|
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||||
|
} >flash AT>flash :flash
|
||||||
|
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
/* gcc uses crtbegin.o to find the start of
|
||||||
|
the constructors, so we make sure it is
|
||||||
|
first. Because this is a wildcard, it
|
||||||
|
doesn't matter if the user does not
|
||||||
|
actually link against crtbegin.o; the
|
||||||
|
linker won't look for a file to match a
|
||||||
|
wildcard. The wildcard also means that it
|
||||||
|
doesn't matter which directory crtbegin.o
|
||||||
|
is in. */
|
||||||
|
KEEP (*crtbegin.o(.ctors))
|
||||||
|
KEEP (*crtbegin?.o(.ctors))
|
||||||
|
/* We don't want to include the .ctor section from
|
||||||
|
the crtend.o file until after the sorted ctors.
|
||||||
|
The .ctor section from the crtend file contains the
|
||||||
|
end of ctors marker and it must be last */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
} >flash AT>flash :flash
|
||||||
|
|
||||||
|
.dtors :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*crtbegin?.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
} >flash AT>flash :flash
|
||||||
|
|
||||||
|
.lalign :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE( _data_lma = . );
|
||||||
|
} >flash AT>flash :flash
|
||||||
|
|
||||||
|
.dalign :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE( _data = . );
|
||||||
|
} >ram AT>flash :ram_init
|
||||||
|
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.ramfunc .ramfunc.*)
|
||||||
|
*(.data .data.*)
|
||||||
|
*(.gnu.linkonce.d.*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
PROVIDE( __global_pointer$ = . + 0x800 );
|
||||||
|
*(.sdata .sdata.*)
|
||||||
|
*(.gnu.linkonce.s.*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
*(.srodata.cst16)
|
||||||
|
*(.srodata.cst8)
|
||||||
|
*(.srodata.cst4)
|
||||||
|
*(.srodata.cst2)
|
||||||
|
*(.srodata .srodata.*)
|
||||||
|
} >ram AT>flash :ram_init
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE( _edata = . );
|
||||||
|
PROVIDE( edata = . );
|
||||||
|
|
||||||
|
PROVIDE( _fbss = . );
|
||||||
|
PROVIDE( __bss_start = . );
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
*(.sbss*)
|
||||||
|
*(.gnu.linkonce.sb.*)
|
||||||
|
*(.bss .bss.*)
|
||||||
|
*(.gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(4);
|
||||||
|
} >ram AT>ram :ram
|
||||||
|
|
||||||
|
. = ALIGN(8);
|
||||||
|
PROVIDE( _end = . );
|
||||||
|
PROVIDE( end = . );
|
||||||
|
PROVIDE( _heap_start = . );
|
||||||
|
|
||||||
|
.stack ORIGIN(ram) + LENGTH(ram) - __stack_size :
|
||||||
|
{
|
||||||
|
PROVIDE( _heap_end = . );
|
||||||
|
. = __stack_size;
|
||||||
|
PROVIDE( _sp = . );
|
||||||
|
} >ram AT>ram :ram
|
||||||
|
}
|
||||||
@ -18,10 +18,6 @@
|
|||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OUTPUT_ARCH( "riscv" )
|
|
||||||
|
|
||||||
ENTRY( _start )
|
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
flash (rxai!w) : ORIGIN = 0x20400000, LENGTH = 0x1fc00000
|
flash (rxai!w) : ORIGIN = 0x20400000, LENGTH = 0x1fc00000
|
||||||
@ -29,156 +25,4 @@ MEMORY
|
|||||||
itim (wxa!ri) : ORIGIN = 0x08000000, LENGTH = 0x00002000
|
itim (wxa!ri) : ORIGIN = 0x08000000, LENGTH = 0x00002000
|
||||||
}
|
}
|
||||||
|
|
||||||
PHDRS
|
INCLUDE fe310_base.ld
|
||||||
{
|
|
||||||
flash PT_LOAD;
|
|
||||||
ram_init PT_LOAD;
|
|
||||||
ram PT_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
__stack_size = DEFINED(__stack_size) ? __stack_size : 1K;
|
|
||||||
|
|
||||||
.init :
|
|
||||||
{
|
|
||||||
KEEP (*(SORT_NONE(.init)))
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.text :
|
|
||||||
{
|
|
||||||
*(.text.unlikely .text.unlikely.*)
|
|
||||||
*(.text.startup .text.startup.*)
|
|
||||||
*(.text .text.*)
|
|
||||||
*(.gnu.linkonce.t.*)
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.fini :
|
|
||||||
{
|
|
||||||
KEEP (*(SORT_NONE(.fini)))
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
PROVIDE (__etext = .);
|
|
||||||
PROVIDE (_etext = .);
|
|
||||||
PROVIDE (etext = .);
|
|
||||||
|
|
||||||
.rodata :
|
|
||||||
{
|
|
||||||
*(.rdata)
|
|
||||||
*(.rodata .rodata.*)
|
|
||||||
*(.gnu.linkonce.r.*)
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
. = ALIGN(4);
|
|
||||||
|
|
||||||
.preinit_array :
|
|
||||||
{
|
|
||||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
|
||||||
KEEP (*(.preinit_array))
|
|
||||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.init_array :
|
|
||||||
{
|
|
||||||
PROVIDE_HIDDEN (__init_array_start = .);
|
|
||||||
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
|
||||||
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
|
|
||||||
PROVIDE_HIDDEN (__init_array_end = .);
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.fini_array :
|
|
||||||
{
|
|
||||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
|
||||||
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
|
||||||
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
|
||||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.ctors :
|
|
||||||
{
|
|
||||||
/* gcc uses crtbegin.o to find the start of
|
|
||||||
the constructors, so we make sure it is
|
|
||||||
first. Because this is a wildcard, it
|
|
||||||
doesn't matter if the user does not
|
|
||||||
actually link against crtbegin.o; the
|
|
||||||
linker won't look for a file to match a
|
|
||||||
wildcard. The wildcard also means that it
|
|
||||||
doesn't matter which directory crtbegin.o
|
|
||||||
is in. */
|
|
||||||
KEEP (*crtbegin.o(.ctors))
|
|
||||||
KEEP (*crtbegin?.o(.ctors))
|
|
||||||
/* We don't want to include the .ctor section from
|
|
||||||
the crtend.o file until after the sorted ctors.
|
|
||||||
The .ctor section from the crtend file contains the
|
|
||||||
end of ctors marker and it must be last */
|
|
||||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
|
||||||
KEEP (*(SORT(.ctors.*)))
|
|
||||||
KEEP (*(.ctors))
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.dtors :
|
|
||||||
{
|
|
||||||
KEEP (*crtbegin.o(.dtors))
|
|
||||||
KEEP (*crtbegin?.o(.dtors))
|
|
||||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
|
||||||
KEEP (*(SORT(.dtors.*)))
|
|
||||||
KEEP (*(.dtors))
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.lalign :
|
|
||||||
{
|
|
||||||
. = ALIGN(4);
|
|
||||||
PROVIDE( _data_lma = . );
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.dalign :
|
|
||||||
{
|
|
||||||
. = ALIGN(4);
|
|
||||||
PROVIDE( _data = . );
|
|
||||||
} >ram AT>flash :ram_init
|
|
||||||
|
|
||||||
.data :
|
|
||||||
{
|
|
||||||
*(.ramfunc .ramfunc.*)
|
|
||||||
*(.data .data.*)
|
|
||||||
*(.gnu.linkonce.d.*)
|
|
||||||
. = ALIGN(8);
|
|
||||||
PROVIDE( __global_pointer$ = . + 0x800 );
|
|
||||||
*(.sdata .sdata.*)
|
|
||||||
*(.gnu.linkonce.s.*)
|
|
||||||
. = ALIGN(8);
|
|
||||||
*(.srodata.cst16)
|
|
||||||
*(.srodata.cst8)
|
|
||||||
*(.srodata.cst4)
|
|
||||||
*(.srodata.cst2)
|
|
||||||
*(.srodata .srodata.*)
|
|
||||||
} >ram AT>flash :ram_init
|
|
||||||
|
|
||||||
. = ALIGN(4);
|
|
||||||
PROVIDE( _edata = . );
|
|
||||||
PROVIDE( edata = . );
|
|
||||||
|
|
||||||
PROVIDE( _fbss = . );
|
|
||||||
PROVIDE( __bss_start = . );
|
|
||||||
.bss :
|
|
||||||
{
|
|
||||||
*(.sbss*)
|
|
||||||
*(.gnu.linkonce.sb.*)
|
|
||||||
*(.bss .bss.*)
|
|
||||||
*(.gnu.linkonce.b.*)
|
|
||||||
*(COMMON)
|
|
||||||
. = ALIGN(4);
|
|
||||||
} >ram AT>ram :ram
|
|
||||||
|
|
||||||
. = ALIGN(8);
|
|
||||||
PROVIDE( _end = . );
|
|
||||||
PROVIDE( end = . );
|
|
||||||
PROVIDE( _heap_start = . );
|
|
||||||
|
|
||||||
.stack ORIGIN(ram) + LENGTH(ram) - __stack_size :
|
|
||||||
{
|
|
||||||
PROVIDE( _heap_end = . );
|
|
||||||
. = __stack_size;
|
|
||||||
PROVIDE( _sp = . );
|
|
||||||
} >ram AT>ram :ram
|
|
||||||
}
|
|
||||||
@ -18,10 +18,6 @@
|
|||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OUTPUT_ARCH( "riscv" )
|
|
||||||
|
|
||||||
ENTRY( _start )
|
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
flash (rxai!w) : ORIGIN = 0x20010000, LENGTH = 0x0006a120
|
flash (rxai!w) : ORIGIN = 0x20010000, LENGTH = 0x0006a120
|
||||||
@ -29,156 +25,4 @@ MEMORY
|
|||||||
itim (wxa!ri) : ORIGIN = 0x08000000, LENGTH = 0x00002000
|
itim (wxa!ri) : ORIGIN = 0x08000000, LENGTH = 0x00002000
|
||||||
}
|
}
|
||||||
|
|
||||||
PHDRS
|
INCLUDE fe310_base.ld
|
||||||
{
|
|
||||||
flash PT_LOAD;
|
|
||||||
ram_init PT_LOAD;
|
|
||||||
ram PT_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
__stack_size = DEFINED(__stack_size) ? __stack_size : 1K;
|
|
||||||
|
|
||||||
.init :
|
|
||||||
{
|
|
||||||
KEEP (*(SORT_NONE(.init)))
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.text :
|
|
||||||
{
|
|
||||||
*(.text.unlikely .text.unlikely.*)
|
|
||||||
*(.text.startup .text.startup.*)
|
|
||||||
*(.text .text.*)
|
|
||||||
*(.gnu.linkonce.t.*)
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.fini :
|
|
||||||
{
|
|
||||||
KEEP (*(SORT_NONE(.fini)))
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
PROVIDE (__etext = .);
|
|
||||||
PROVIDE (_etext = .);
|
|
||||||
PROVIDE (etext = .);
|
|
||||||
|
|
||||||
.rodata :
|
|
||||||
{
|
|
||||||
*(.rdata)
|
|
||||||
*(.rodata .rodata.*)
|
|
||||||
*(.gnu.linkonce.r.*)
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
. = ALIGN(4);
|
|
||||||
|
|
||||||
.preinit_array :
|
|
||||||
{
|
|
||||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
|
||||||
KEEP (*(.preinit_array))
|
|
||||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.init_array :
|
|
||||||
{
|
|
||||||
PROVIDE_HIDDEN (__init_array_start = .);
|
|
||||||
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
|
||||||
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
|
|
||||||
PROVIDE_HIDDEN (__init_array_end = .);
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.fini_array :
|
|
||||||
{
|
|
||||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
|
||||||
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
|
||||||
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
|
||||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.ctors :
|
|
||||||
{
|
|
||||||
/* gcc uses crtbegin.o to find the start of
|
|
||||||
the constructors, so we make sure it is
|
|
||||||
first. Because this is a wildcard, it
|
|
||||||
doesn't matter if the user does not
|
|
||||||
actually link against crtbegin.o; the
|
|
||||||
linker won't look for a file to match a
|
|
||||||
wildcard. The wildcard also means that it
|
|
||||||
doesn't matter which directory crtbegin.o
|
|
||||||
is in. */
|
|
||||||
KEEP (*crtbegin.o(.ctors))
|
|
||||||
KEEP (*crtbegin?.o(.ctors))
|
|
||||||
/* We don't want to include the .ctor section from
|
|
||||||
the crtend.o file until after the sorted ctors.
|
|
||||||
The .ctor section from the crtend file contains the
|
|
||||||
end of ctors marker and it must be last */
|
|
||||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
|
||||||
KEEP (*(SORT(.ctors.*)))
|
|
||||||
KEEP (*(.ctors))
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.dtors :
|
|
||||||
{
|
|
||||||
KEEP (*crtbegin.o(.dtors))
|
|
||||||
KEEP (*crtbegin?.o(.dtors))
|
|
||||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
|
||||||
KEEP (*(SORT(.dtors.*)))
|
|
||||||
KEEP (*(.dtors))
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.lalign :
|
|
||||||
{
|
|
||||||
. = ALIGN(4);
|
|
||||||
PROVIDE( _data_lma = . );
|
|
||||||
} >flash AT>flash :flash
|
|
||||||
|
|
||||||
.dalign :
|
|
||||||
{
|
|
||||||
. = ALIGN(4);
|
|
||||||
PROVIDE( _data = . );
|
|
||||||
} >ram AT>flash :ram_init
|
|
||||||
|
|
||||||
.data :
|
|
||||||
{
|
|
||||||
*(.ramfunc .ramfunc.*)
|
|
||||||
*(.data .data.*)
|
|
||||||
*(.gnu.linkonce.d.*)
|
|
||||||
. = ALIGN(8);
|
|
||||||
PROVIDE( __global_pointer$ = . + 0x800 );
|
|
||||||
*(.sdata .sdata.*)
|
|
||||||
*(.gnu.linkonce.s.*)
|
|
||||||
. = ALIGN(8);
|
|
||||||
*(.srodata.cst16)
|
|
||||||
*(.srodata.cst8)
|
|
||||||
*(.srodata.cst4)
|
|
||||||
*(.srodata.cst2)
|
|
||||||
*(.srodata .srodata.*)
|
|
||||||
} >ram AT>flash :ram_init
|
|
||||||
|
|
||||||
. = ALIGN(4);
|
|
||||||
PROVIDE( _edata = . );
|
|
||||||
PROVIDE( edata = . );
|
|
||||||
|
|
||||||
PROVIDE( _fbss = . );
|
|
||||||
PROVIDE( __bss_start = . );
|
|
||||||
.bss :
|
|
||||||
{
|
|
||||||
*(.sbss*)
|
|
||||||
*(.gnu.linkonce.sb.*)
|
|
||||||
*(.bss .bss.*)
|
|
||||||
*(.gnu.linkonce.b.*)
|
|
||||||
*(COMMON)
|
|
||||||
. = ALIGN(4);
|
|
||||||
} >ram AT>ram :ram
|
|
||||||
|
|
||||||
. = ALIGN(8);
|
|
||||||
PROVIDE( _end = . );
|
|
||||||
PROVIDE( end = . );
|
|
||||||
PROVIDE( _heap_start = . );
|
|
||||||
|
|
||||||
.stack ORIGIN(ram) + LENGTH(ram) - __stack_size :
|
|
||||||
{
|
|
||||||
PROVIDE( _heap_end = . );
|
|
||||||
. = __stack_size;
|
|
||||||
PROVIDE( _sp = . );
|
|
||||||
} >ram AT>ram :ram
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user