1/*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date           Author       Notes
8 */
9    .extern main                               /* 引入外部C入口 */
10
11    .extern rt_interrupt_enter
12    .extern rt_interrupt_leave
13    .extern rt_thread_switch_interrupt_flag
14    .extern rt_interrupt_from_thread
15    .extern rt_interrupt_to_thread
16    .extern rt_hw_trap_irq
17
18    .global start
19    .global endless_loop
20    .global rt_hw_context_switch_interrupt_do
21
22    /* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs */
23    .set  MODE_USR, 0x10            /* User Mode */
24    .set  MODE_FIQ, 0x11            /* FIQ Mode */
25    .set  MODE_IRQ, 0x12            /* IRQ Mode */
26    .set  MODE_SVC, 0x13            /* Supervisor Mode */
27    .set  MODE_ABT, 0x17            /* Abort Mode */
28    .set  MODE_UND, 0x1B            /* Undefined Mode */
29    .set  MODE_SYS, 0x1F            /* System Mode */
30
31    .equ  I_BIT, 0x80               /* when I bit is set, IRQ is disabled */
32    .equ  F_BIT, 0x40               /* when F bit is set, FIQ is disabled */
33    .equ  I_Bit, 0x80               /* when I bit is set, IRQ is disabled */
34    .equ  F_Bit, 0x40               /* when F bit is set, FIQ is disabled */
35
36    /* VPBDIV definitions*/
37    .equ  VPBDIV,       0xE01FC100
38    .set  VPBDIV_VALUE, 0x00000000
39
40    /* Phase Locked Loop (PLL) definitions*/
41    .equ  PLL_BASE,      0xE01FC080  /* PLL Base Address */
42    .equ  PLLCON_OFS,    0x00        /* PLL Control Offset */
43    .equ  PLLCFG_OFS,    0x04        /* PLL Configuration Offset */
44    .equ  PLLSTAT_OFS,   0x08        /* PLL Status Offset */
45    .equ  PLLFEED_OFS,   0x0C        /* PLL Feed Offset */
46    .equ  PLLCON_PLLE,   (1<<0)      /* PLL Enable */
47    .equ  PLLCON_PLLC,   (1<<1)      /* PLL Connect */
48    .equ  PLLCFG_MSEL,   (0x1F<<0)   /* PLL Multiplier */
49    .equ  PLLCFG_PSEL,   (0x03<<5)   /* PLL Divider */
50    .equ  PLLSTAT_PLOCK, (1<<10)     /* PLL Lock Status */
51    .equ  PLLCFG_Val,    0x00000024  /* <o1.0..4>   MSEL: PLL Multiplier Selection,<o1.5..6>   PSEL: PLL Divider Selection */
52
53    .equ  MEMMAP,       0xE01FC040     /*Memory Mapping Control*/
54
55
56    /* Memory Accelerator Module (MAM) definitions*/
57    .equ  MAM_BASE,     0xE01FC000
58    .equ  MAMCR_OFS,    0x00
59    .equ  MAMTIM_OFS,   0x04
60    .equ  MAMCR_Val,    0x00000002
61    .equ  MAMTIM_Val,   0x00000004
62
63    .equ  VICIntEnClr,  0xFFFFF014
64    .equ  VICIntSelect, 0xFFFFF00C
65/************* 目标配置结束 *************/
66
67
68/* Setup the operating mode & stack.*/
69/* --------------------------------- */
70    .global _reset
71_reset:
72    .code 32
73    .align 0
74
75/************************* PLL_SETUP **********************************/
76        ldr     r0, =PLL_BASE
77        mov     r1, #0xAA
78        mov     r2, #0x55
79
80/* Configure and Enable PLL */
81        mov     r3, #PLLCFG_Val
82        str     r3, [r0, #PLLCFG_OFS]
83        mov     r3, #PLLCON_PLLE
84        str     r3, [r0, #PLLCON_OFS]
85        str     r1, [r0, #PLLFEED_OFS]
86        str     r2, [r0, #PLLFEED_OFS]
87
88/*  Wait until PLL Locked */
89PLL_Locked_loop:
90        ldr     r3, [r0, #PLLSTAT_OFS]
91        ands    r3, r3, #PLLSTAT_PLOCK
92        beq     PLL_Locked_loop
93
94/*  Switch to PLL Clock */
95        mov     r3, #(PLLCON_PLLE|PLLCON_PLLC)
96        str     r3, [r0, #PLLCON_OFS]
97        str     r1, [r0, #PLLFEED_OFS]
98        str     R2, [r0, #PLLFEED_OFS]
99/************************* PLL_SETUP **********************************/
100
101/************************ Setup VPBDIV ********************************/
102        ldr     r0, =VPBDIV
103        ldr     r1, =VPBDIV_VALUE
104        str     r1, [r0]
105/************************ Setup VPBDIV ********************************/
106
107/************** Setup MAM **************/
108        ldr     r0, =MAM_BASE
109        mov     r1, #MAMTIM_Val
110        str     r1, [r0, #MAMTIM_OFS]
111        mov     r1, #MAMCR_Val
112        str     r1, [r0, #MAMCR_OFS]
113/************** Setup MAM **************/
114
115/************************ setup stack *********************************/
116    ldr   r0, .undefined_stack_top
117    sub   r0, r0, #4
118    msr   CPSR_c, #MODE_UND|I_BIT|F_BIT /* Undefined Instruction Mode */
119    mov   sp, r0
120
121    ldr   r0, .abort_stack_top
122    sub   r0, r0, #4
123    msr   CPSR_c, #MODE_ABT|I_BIT|F_BIT /* Abort Mode */
124    mov   sp, r0
125
126    ldr   r0, .fiq_stack_top
127    sub   r0, r0, #4
128    msr   CPSR_c, #MODE_FIQ|I_BIT|F_BIT /* FIQ Mode */
129    mov   sp, r0
130
131    ldr   r0, .irq_stack_top
132    sub   r0, r0, #4
133    msr   CPSR_c, #MODE_IRQ|I_BIT|F_BIT /* IRQ Mode */
134    mov   sp, r0
135
136    ldr   r0, .svc_stack_top
137    sub   r0, r0, #4
138    msr   CPSR_c, #MODE_SVC|I_BIT|F_BIT  /* Supervisor Mode */
139    mov   sp, r0
140/************************ setup stack ********************************/
141
142    /* copy .data to SRAM */
143    ldr     r1, =_sidata            /* .data start in image */
144    ldr     r2, =_edata             /* .data end in image   */
145    ldr     r3, =_sdata             /* sram data start      */
146data_loop:
147    ldr     r0, [r1, #0]
148    str     r0, [r3]
149
150    add     r1, r1, #4
151    add     r3, r3, #4
152
153    cmp     r3, r2                   /* check if data to clear */
154    blo     data_loop                /* loop until done        */
155
156    /* clear .bss */
157    mov     r0,#0                   /* get a zero */
158    ldr     r1,=__bss_start         /* bss start  */
159    ldr     r2,=__bss_end           /* bss end    */
160
161bss_loop:
162    cmp     r1,r2                   /* check if data to clear */
163    strlo   r0,[r1],#4              /* clear 4 bytes          */
164    blo     bss_loop                /* loop until done        */
165
166
167    /* call C++ constructors of global objects */
168    ldr     r0, =__ctors_start__
169    ldr     r1, =__ctors_end__
170
171ctor_loop:
172    cmp     r0, r1
173    beq     ctor_end
174    ldr     r2, [r0], #4
175    stmfd   sp!, {r0-r1}
176    mov     lr, pc
177    bx      r2
178    ldmfd   sp!, {r0-r1}
179    b       ctor_loop
180ctor_end:
181
182    /* enter C code */
183    bl      main
184
185    .align 0
186    .undefined_stack_top:
187    .word   _undefined_stack_top
188    .abort_stack_top:
189    .word   _abort_stack_top
190    .fiq_stack_top:
191    .word   _fiq_stack_top
192    .irq_stack_top:
193    .word   _irq_stack_top
194    .svc_stack_top:
195    .word   _svc_stack_top
196/*********************** END Clear BSS  ******************************/
197
198.section .init,"ax"
199.code 32
200.align 0
201.globl _start
202_start:
203
204    ldr   pc, __start                   /* reset - _start           */
205    ldr   pc, _undf                     /* undefined - _undf        */
206    ldr   pc, _swi                      /* SWI - _swi               */
207    ldr   pc, _pabt                     /* program abort - _pabt    */
208    ldr   pc, _dabt                     /* data abort - _dabt       */
209    .word 0xB8A06F58                    /* reserved                 */
210    ldr   pc, __IRQ_Handler             /* IRQ - read the VIC       */
211    ldr   pc, _fiq                      /* FIQ - _fiq               */
212
213__start:.word _reset
214_undf:  .word __undf                    /* undefined                */
215_swi:   .word __swi                     /* SWI                      */
216_pabt:  .word __pabt                    /* program abort            */
217_dabt:  .word __dabt                    /* data abort               */
218temp1:  .word 0
219__IRQ_Handler:  .word IRQ_Handler
220_fiq:   .word __fiq                     /* FIQ                      */
221
222__undf: b     .                         /* undefined                */
223__swi : b     .
224__pabt: b     .                         /* program abort            */
225__dabt: b     .                         /* data abort               */
226__fiq : b     .                         /* FIQ                      */
227
228/* IRQ入口 */
229IRQ_Handler :
230        stmfd   sp!, {r0-r12,lr}               /* 对R0 – R12,LR寄存器压栈      */
231        bl  rt_interrupt_enter                 /* 通知RT-Thread进入中断模式     */
232        bl  rt_hw_trap_irq                     /* 相应中断服务例程处理        */
233        bl  rt_interrupt_leave                 /* ; 通知RT-Thread要离开中断模式 */
234
235        /* 如果设置了rt_thread_switch_interrupt_flag,进行中断中的线程上下文处理 */
236        ldr r0, =rt_thread_switch_interrupt_flag
237        ldr r1, [r0]
238        cmp r1, #1
239        beq rt_hw_context_switch_interrupt_do  /* 中断中切换发生 */
240                                               /* 如果跳转了,将不会回来 */
241        ldmfd   sp!, {r0-r12,lr}               /* 恢复栈 */
242        subs    pc, lr, #4                     /* 从IRQ中返回 */
243
244/*
245* void rt_hw_context_switch_interrupt_do(rt_base_t flag)
246* 中断结束后的上下文切换
247*/
248rt_hw_context_switch_interrupt_do:
249                mov r1,  #0             /* clear flag */
250                                        /* 清楚中断中切换标志 */
251                str r1,  [r0]           /* */
252
253                ldmfd   sp!, {r0-r12,lr}/* reload saved registers */
254                                        /* 先恢复被中断线程的上下文 */
255                stmfd   sp!, {r0-r3}    /* save r0-r3 */
256                                        /* 对R0 – R3压栈,因为后面会用到 */
257                mov r1,  sp             /* 把此处的栈值保存到R1 */
258                add sp,  sp, #16        /* restore sp */
259                                        /* 恢复IRQ的栈,后面会跳出IRQ模式 */
260                sub r2,  lr, #4         /* save old task's pc to r2 */
261                                        /* 保存切换出线程的PC到R2 */
262
263                mrs r3,  spsr           /* disable interrupt 保存中断前的CPSR到R3寄存器 */
264                                        /* 获得SPSR寄存器值 */
265                orr r0,  r3, #I_BIT|F_BIT
266                msr spsr_c, r0          /*  关闭SPSR中的IRQ/FIQ中断 */
267
268                ldr r0,  =.+8           /* 把当前地址+8载入到R0寄存器中 switch to interrupted task's stack */
269                movs pc,  r0            /* 退出IRQ模式,由于SPSR被设置成关中断模式 */
270                                        /* 所以从IRQ返回后,中断并没有打开
271                                        ; R0寄存器中的位置实际就是下一条指令,
272                                        ; 即PC继续往下走
273                                        ; 此时
274                                        ; 模式已经换成中断前的SVC模式,
275                                        ; SP寄存器也是SVC模式下的栈寄存器
276                                        ; R1保存IRQ模式下的栈指针
277                                        ; R2保存切换出线程的PC
278                                        ; R3保存切换出线程的CPSR */
279                stmfd   sp!, {r2}       /* push old task's pc */
280                                        /* 保存切换出任务的PC */
281                stmfd   sp!, {r4-r12,lr}/* push old task's lr,r12-r4 */
282                                        /* 保存R4 – R12,LR寄存器 */
283                mov r4,  r1             /* Special optimised code below */
284                                        /* R1保存有压栈R0 – R3处的栈位置 */
285                mov r5,  r3             /* R3切换出线程的CPSR */
286                ldmfd   r4!, {r0-r3}    /* 恢复R0 – R3 */
287                stmfd   sp!, {r0-r3}    /* push old task's r3-r0 */
288                                        /*  R0 – R3压栈到切换出线程 */
289                stmfd   sp!, {r5}       /* push old task's psr */
290                                        /* 切换出线程CPSR压栈 */
291                mrs r4,  spsr
292                stmfd   sp!, {r4}       /* push old task's spsr */
293                                        /* 切换出线程SPSR压栈 */
294
295                ldr r4,  =rt_interrupt_from_thread
296                ldr r5,  [r4]
297                str sp,  [r5]           /* store sp in preempted tasks's TCB */
298                                        /* 保存切换出线程的SP指针 */
299
300                ldr r6,  =rt_interrupt_to_thread
301                ldr r6,  [r6]
302                ldr sp,  [r6]           /* get new task's stack pointer */
303                                        /* 获得切换到线程的栈 */
304
305                ldmfd   sp!, {r4}       /* pop new task's spsr */
306                                        /* 恢复SPSR */
307                msr SPSR_cxsf, r4
308                ldmfd   sp!, {r4}       /* pop new task's psr */
309                                        /* 恢复CPSR */
310                msr CPSR_cxsf, r4
311
312                ldmfd   sp!, {r0-r12,lr,pc} /* pop new task's r0-r12,lr & pc */
313                                            /* 恢复R0 – R12,LR及PC寄存器 */
314
315/* 代码加密功能 */
316#if defined(CODE_PROTECTION)
317.org 0x01FC
318.word 0x87654321
319#endif
320
321