1;/**************************************************************************/
2;/*                                                                        */
3;/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4;/*                                                                        */
5;/*       This software is licensed under the Microsoft Software License   */
6;/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7;/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8;/*       and in the root directory of this software.                      */
9;/*                                                                        */
10;/**************************************************************************/
11;
12;
13;/**************************************************************************/
14;/**************************************************************************/
15;/**                                                                       */
16;/** ThreadX Component                                                     */
17;/**                                                                       */
18;/**   Initialize                                                          */
19;/**                                                                       */
20;/**************************************************************************/
21;/**************************************************************************/
22;
23;
24;#define TX_SOURCE_CODE
25;
26;
27;/* Include necessary system files.  */
28;
29;#include "tx_api.h"
30;#include "tx_initialize.h"
31;#include "tx_thread.h"
32;#include "tx_timer.h"
33;
34;
35SVC_MODE        EQU     0xD3                    ; Disable IRQ/FIQ SVC mode
36IRQ_MODE        EQU     0xD2                    ; Disable IRQ/FIQ IRQ mode
37FIQ_MODE        EQU     0xD1                    ; Disable IRQ/FIQ FIQ mode
38SYS_MODE        EQU     0xDF                    ; Disable IRQ/FIQ SYS mode
39HEAP_SIZE       EQU     4096                    ; Heap size
40FIQ_STACK_SIZE  EQU     512                     ; FIQ stack size
41SYS_STACK_SIZE  EQU     1024                    ; SYS stack size (used for nested interrupts)
42IRQ_STACK_SIZE  EQU     1024                    ; IRQ stack size
43;
44;
45;/* ARM9 ARMulator Timer and Interrupt controller information.  This depends on
46;   the ARMulator's Interrupt Controller and Timer being enabled in the default.ami.
47;   In addition, the addresses must match those specified in the peripherals.ami file.
48;   Please refer to section 2.10 and 4.16 of the Debug Target Guide, version 1.2.  */
49;
50IRQStatus       EQU     0x0a000000              ; IRQ Status Register
51IRQRawStatus    EQU     0x0a000004              ; IRQ Raw Status Register
52IRQEnable       EQU     0x0a000008              ; IRQ Enable Set Register
53IRQEnableClear  EQU     0x0a00000C              ; IRQ Enable Clear Register
54IRQSoft         EQU     0x0a000010              ; IRQ Soft
55FIQStatus       EQU     0x0a000100              ; FIQ Status Register
56FIQRawStatus    EQU     0x0a000104              ; FIQ Raw Status Register
57FIQEnable       EQU     0x0a000108              ; FIQ Enable Set Register
58FIQEnableClear  EQU     0x0a00010C              ; FIQ Enable Clear Register
59
60TIMER1_BIT      EQU     0x00000010              ; IRQ/FIQ Timer1 bit
61TIMER2_BIT      EQU     0x00000020              ; IRQ/FIQ Timer2 bit
62
63Timer1Load      EQU     0x0a800000              ; Timer1 Load Register
64Timer1Value     EQU     0x0a800004              ; Timer1 Value Register
65Timer1Control   EQU     0x0a800008              ; Timer1 Control Register
66Timer1Clear     EQU     0x0a80000C              ; Timer1 Clear Register
67
68Timer1Mode      EQU     0x000000C0              ; Timer1 Control Value, Timer enable, periodic, no prescaler
69Timer1Period    EQU     0x0000FFFF              ; Timer1 count-down period, maximum value
70
71Timer2Load      EQU     0x0a800020              ; Timer2 Load Register
72Timer2Value     EQU     0x0a800024              ; Timer2 Value Register
73Timer2Control   EQU     0x0a800028              ; Timer2 Control Register
74Timer2Clear     EQU     0x0a80002C              ; Timer2 Clear Register
75;
76;
77    IMPORT      _tx_thread_system_stack_ptr
78    IMPORT      _tx_initialize_unused_memory
79    IMPORT      _tx_thread_context_save
80    IMPORT      _tx_thread_context_restore
81    IF  :DEF:TX_ENABLE_FIQ_SUPPORT
82    IMPORT      _tx_thread_fiq_context_save
83    IMPORT      _tx_thread_fiq_context_restore
84    ENDIF
85    IF  :DEF:TX_ENABLE_IRQ_NESTING
86    IMPORT      _tx_thread_irq_nesting_start
87    IMPORT      _tx_thread_irq_nesting_end
88    ENDIF
89    IF  :DEF:TX_ENABLE_FIQ_NESTING
90    IMPORT      _tx_thread_fiq_nesting_start
91    IMPORT      _tx_thread_fiq_nesting_end
92    ENDIF
93    IMPORT      _tx_timer_interrupt
94    IMPORT      __main
95    IMPORT      _tx_version_id
96    IMPORT      _tx_build_options
97    IMPORT      |Image$$ZI$$Limit|
98;
99;
100        AREA  Init, CODE, READONLY
101;
102;/* Define the ARM9 vector area.  This should be located or copied to 0.  */
103;
104    EXPORT  __vectors
105__vectors
106    LDR     pc,=__main                          ; Reset goes to startup function
107    LDR     pc,=__tx_undefined                  ; Undefined handler
108    LDR     pc,=__tx_swi_interrupt              ; Software interrupt handler
109    LDR     pc,=__tx_prefetch_handler           ; Prefetch exception handler
110    LDR     pc,=__tx_abort_handler              ; Abort exception handler
111    LDR     pc,=__tx_reserved_handler           ; Reserved exception handler
112    LDR     pc,=__tx_irq_handler                ; IRQ interrupt handler
113    LDR     pc,=__tx_fiq_handler                ; FIQ interrupt handler
114;
115;
116        AREA ||.text||, CODE, READONLY
117;/**************************************************************************/
118;/*                                                                        */
119;/*  FUNCTION                                               RELEASE        */
120;/*                                                                        */
121;/*    _tx_initialize_low_level                             ARM9/AC5       */
122;/*                                                           6.1          */
123;/*  AUTHOR                                                                */
124;/*                                                                        */
125;/*    William E. Lamie, Microsoft Corporation                             */
126;/*                                                                        */
127;/*  DESCRIPTION                                                           */
128;/*                                                                        */
129;/*    This function is responsible for any low-level processor            */
130;/*    initialization, including setting up interrupt vectors, setting     */
131;/*    up a periodic timer interrupt source, saving the system stack       */
132;/*    pointer for use in ISR processing later, and finding the first      */
133;/*    available RAM memory address for tx_application_define.             */
134;/*                                                                        */
135;/*  INPUT                                                                 */
136;/*                                                                        */
137;/*    None                                                                */
138;/*                                                                        */
139;/*  OUTPUT                                                                */
140;/*                                                                        */
141;/*    None                                                                */
142;/*                                                                        */
143;/*  CALLS                                                                 */
144;/*                                                                        */
145;/*    None                                                                */
146;/*                                                                        */
147;/*  CALLED BY                                                             */
148;/*                                                                        */
149;/*    _tx_initialize_kernel_enter           ThreadX entry function        */
150;/*                                                                        */
151;/*  RELEASE HISTORY                                                       */
152;/*                                                                        */
153;/*    DATE              NAME                      DESCRIPTION             */
154;/*                                                                        */
155;/*  09-30-2020     William E. Lamie         Initial Version 6.1           */
156;/*                                                                        */
157;/**************************************************************************/
158;VOID   _tx_initialize_low_level(VOID)
159;{
160    EXPORT  _tx_initialize_low_level
161_tx_initialize_low_level
162;
163;
164;    /****** NOTE ****** We must be in SVC MODE at this point.  Some monitors
165;       enter this routine in USER mode and require a software interrupt to
166;       change into SVC mode.  */
167;
168    LDR     r1, =|Image$$ZI$$Limit|             ; Get end of non-initialized RAM area
169    LDR     r2, =HEAP_SIZE                      ; Pickup the heap size
170    ADD     r1, r2, r1                          ; Setup heap limit
171    ADD     r1, r1, #4                          ; Setup stack limit
172;
173    IF :DEF:TX_ENABLE_IRQ_NESTING
174;    /* Setup the system mode stack for nested interrupt support  */
175    LDR     r2, =SYS_STACK_SIZE                 ; Pickup stack size
176    MOV     r3, #SYS_MODE                       ; Build SYS mode CPSR
177    MSR     CPSR_cxsf, r3                       ; Enter SYS mode
178    ADD     r1, r1, r2                          ; Calculate start of SYS stack
179    BIC     r1, r1, #7                          ; Ensure 8-byte alignment
180    MOV     sp, r1                              ; Setup SYS stack pointer
181    ENDIF
182;
183    LDR     r2, =FIQ_STACK_SIZE                 ; Pickup stack size
184    MOV     r0, #FIQ_MODE                       ; Build FIQ mode CPSR
185    MSR     CPSR_c, r0                          ; Enter FIQ mode
186    ADD     r1, r1, r2                          ; Calculate start of FIQ stack
187    BIC     r1, r1, #7                          ; Ensure 8-byte alignment
188    MOV     sp, r1                              ; Setup FIQ stack pointer
189    MOV     sl, #0                              ; Clear sl
190    MOV     fp, #0                              ; Clear fp
191    LDR     r2, =IRQ_STACK_SIZE                 ; Pickup IRQ (system stack size)
192    MOV     r0, #IRQ_MODE                       ; Build IRQ mode CPSR
193    MSR     CPSR_c, r0                          ; Enter IRQ mode
194    ADD     r1, r1, r2                          ; Calculate start of IRQ stack
195    BIC     r1, r1, #7                          ; Ensure 8-byte alignment
196    MOV     sp, r1                              ; Setup IRQ stack pointer
197    MOV     r0, #SVC_MODE                       ; Build SVC mode CPSR
198    MSR     CPSR_c, r0                          ; Enter SVC mode
199    LDR     r3, =_tx_thread_system_stack_ptr    ; Pickup stack pointer
200    STR     r1, [r3, #0]                        ; Save the system stack
201;
202;    /* Save the system stack pointer.  */
203;    _tx_thread_system_stack_ptr = (VOID_PTR) (sp);
204;
205    LDR     r1, =_tx_thread_system_stack_ptr    ; Pickup address of system stack ptr
206    LDR     r0, [r1, #0]                        ; Pickup system stack
207    ADD     r0, r0, #4                          ; Increment to next free word
208;
209;    /* Save the first available memory address.  */
210;    _tx_initialize_unused_memory =  (VOID_PTR) |Image$$ZI$$Limit| + HEAP + [SYS_STACK] + FIQ_STACK + IRQ_STACK;
211;
212    LDR     r2, =_tx_initialize_unused_memory   ; Pickup unused memory ptr address
213    STR     r0, [r2, #0]                        ; Save first free memory address
214;
215;    /* Setup Timer for periodic interrupts.  */
216;
217;    /* Setup ARMulator Timer1 for periodic interrupts.  */
218;
219    LDR     r0,=IRQEnable                       ; Build address of IRQ enable register
220    LDR     r1,=TIMER1_BIT                      ; Build value of Timer1 IRQ enable
221    STR     r1,[r0]                             ; Enable IRQ interrupts for Timer1
222
223    LDR     r0,=Timer1Load                      ; Build address of Timer1 load register
224    LDR     r1,=Timer1Period                    ; Build Timer1 periodic value
225    STR     r1,[r0]                             ; Set Timer1 load value
226
227    LDR     r0,=Timer1Control                   ; Build address of Timer1 control register
228    LDR     r1,=Timer1Mode                      ; Build Timer1 control value
229    STR     r1,[r0]                             ; Enable Timer1
230;
231;    /* Done, return to caller.  */
232;
233    IF  {INTER} = {TRUE}
234    BX      lr                                  ; Return to caller
235    ELSE
236    MOV     pc, lr                              ; Return to caller
237    ENDIF
238;}
239;
240;
241;/* Define initial heap/stack routine for the ARM RealView (and ADS) startup code.  This
242;   routine will set the initial stack to use the ThreadX IRQ & FIQ &
243;   (optionally SYS) stack areas.  */
244;
245    EXPORT  __user_initial_stackheap
246__user_initial_stackheap
247    LDR     r0, =|Image$$ZI$$Limit|             ; Get end of non-initialized RAM area
248    LDR     r2, =HEAP_SIZE                      ; Pickup the heap size
249    ADD     r2, r2, r0                          ; Setup heap limit
250    ADD     r3, r2, #4                          ; Setup stack limit
251    MOV     r1, r3                              ; Setup start of stack
252    IF :DEF:TX_ENABLE_IRQ_NESTING
253    LDR     r12, =SYS_STACK_SIZE                ; Pickup IRQ system stack
254    ADD     r1, r1, r12                         ; Setup the return system stack
255    BIC     r1, r1, #7                          ; Ensure 8-byte alignment
256    ENDIF
257    LDR     r12, =FIQ_STACK_SIZE                ; Pickup FIQ stack size
258    ADD     r1, r1, r12                         ; Setup the return system stack
259    BIC     r1, r1, #7                          ; Ensure 8-byte alignment
260    LDR     r12, =IRQ_STACK_SIZE                ; Pickup IRQ system stack
261    ADD     r1, r1, r12                         ; Setup the return system stack
262    BIC     r1, r1, #7                          ; Ensure 8-byte alignment
263    IF  {INTER} = {TRUE}
264    BX      lr                                  ; Return to caller
265    ELSE
266    MOV     pc, lr                              ; Return to caller
267    ENDIF
268;
269;
270;/* Define shells for each of the interrupt vectors.  */
271;
272    EXPORT  __tx_undefined
273__tx_undefined
274    B       __tx_undefined                      ; Undefined handler
275;
276    EXPORT  __tx_swi_interrupt
277__tx_swi_interrupt
278    B       __tx_swi_interrupt                  ; Software interrupt handler
279;
280    EXPORT  __tx_prefetch_handler
281__tx_prefetch_handler
282    B       __tx_prefetch_handler               ; Prefetch exception handler
283;
284    EXPORT  __tx_abort_handler
285__tx_abort_handler
286    B       __tx_abort_handler                  ; Abort exception handler
287;
288    EXPORT  __tx_reserved_handler
289__tx_reserved_handler
290    B       __tx_reserved_handler               ; Reserved exception handler
291;
292;
293    EXPORT  __tx_irq_handler
294    EXPORT  __tx_irq_processing_return
295__tx_irq_handler
296;
297;    /* Jump to context save to save system context.  */
298    B       _tx_thread_context_save
299__tx_irq_processing_return
300;
301;    /* At this point execution is still in the IRQ mode.  The CPSR, point of
302;       interrupt, and all C scratch registers are available for use.  In
303;       addition, IRQ interrupts may be re-enabled - with certain restrictions -
304;       if nested IRQ interrupts are desired.  Interrupts may be re-enabled over
305;       small code sequences where lr is saved before enabling interrupts and
306;       restored after interrupts are again disabled.  */
307;
308;
309;    /* Check for Timer1 interrupts on the ARMulator.  */
310
311    LDR     r1,=IRQStatus                       ; Pickup address of IRQStatus register
312    LDR     r2, [r1]                            ; Read IRQStatus
313    LDR     r0,=TIMER1_BIT                      ; Pickup Timer1 interrupt present bit
314    AND     r2, r2, r0                          ; Is this a timer interrupt?
315    CMP     r2, r0                              ;
316    BNE     _tx_not_timer_interrupt             ; If 0, not a timer interrupt
317
318    LDR     r1,=Timer1Clear                     ; Build address of Timer1 clear register
319    MOV     r0,#0                               ;
320    STR     r0, [r1]                            ; Clear timer 0 interrupt
321
322    BL      _tx_timer_interrupt                 ; Timer interrupt handler
323_tx_not_timer_interrupt
324;
325;    /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start
326;       from IRQ mode with interrupts disabled.  This routine switches to the
327;       system mode and returns with IRQ interrupts enabled.
328;
329;       NOTE:  It is very important to ensure all IRQ interrupts are cleared
330;       prior to enabling nested IRQ interrupts.  */
331    IF :DEF:TX_ENABLE_IRQ_NESTING
332    BL      _tx_thread_irq_nesting_start
333    ENDIF
334;
335;
336;    /* Application IRQ handlers can be called here!  */
337;
338;    /* If interrupt nesting was started earlier, the end of interrupt nesting
339;       service must be called before returning to _tx_thread_context_restore.
340;       This routine returns in processing in IRQ mode with interrupts disabled.  */
341    IF :DEF:TX_ENABLE_IRQ_NESTING
342    BL      _tx_thread_irq_nesting_end
343    ENDIF
344;
345;    /* Jump to context restore to restore system context.  */
346    B       _tx_thread_context_restore
347;
348;
349;    /* This is an example of a vectored IRQ handler.  */
350;
351    EXPORT  __tx_example_vectored_irq_handler
352__tx_example_vectored_irq_handler
353;
354;
355;    /* Save initial context and call context save to prepare for
356;       vectored ISR execution.  */
357;
358;    STMDB   sp!, {r0-r3}                        ; Save some scratch registers
359;    MRS     r0, SPSR                            ; Pickup saved SPSR
360;    SUB     lr, lr, #4                          ; Adjust point of interrupt
361;    STMDB   sp!, {r0, r10, r12, lr}             ; Store other scratch registers
362;    BL      _tx_thread_vectored_context_save    ; Vectored context save
363;
364;    /* At this point execution is still in the IRQ mode.  The CPSR, point of
365;       interrupt, and all C scratch registers are available for use.  In
366;       addition, IRQ interrupts may be re-enabled - with certain restrictions -
367;       if nested IRQ interrupts are desired.  Interrupts may be re-enabled over
368;       small code sequences where lr is saved before enabling interrupts and
369;       restored after interrupts are again disabled.  */
370;
371;
372;    /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start
373;       from IRQ mode with interrupts disabled.  This routine switches to the
374;       system mode and returns with IRQ interrupts enabled.
375;
376;       NOTE:  It is very important to ensure all IRQ interrupts are cleared
377;       prior to enabling nested IRQ interrupts.  */
378;    IF :DEF:TX_ENABLE_IRQ_NESTING
379;    BL      _tx_thread_irq_nesting_start
380;    ENDIF
381;
382;    /* Application IRQ handlers can be called here!  */
383;
384;    /* If interrupt nesting was started earlier, the end of interrupt nesting
385;       service must be called before returning to _tx_thread_context_restore.
386;       This routine returns in processing in IRQ mode with interrupts disabled.  */
387;    IF :DEF:TX_ENABLE_IRQ_NESTING
388;    BL      _tx_thread_irq_nesting_end
389;    ENDIF
390;
391;    /* Jump to context restore to restore system context.  */
392;    B       _tx_thread_context_restore
393;
394;
395    IF  :DEF:TX_ENABLE_FIQ_SUPPORT
396    EXPORT  __tx_fiq_handler
397    EXPORT  __tx_fiq_processing_return
398__tx_fiq_handler
399;
400;    /* Jump to fiq context save to save system context.  */
401    B       _tx_thread_fiq_context_save
402__tx_fiq_processing_return
403;
404;    /* At this point execution is still in the FIQ mode.  The CPSR, point of
405;       interrupt, and all C scratch registers are available for use.  */
406;
407;    /* Interrupt nesting is allowed after calling _tx_thread_fiq_nesting_start
408;       from FIQ mode with interrupts disabled.  This routine switches to the
409;       system mode and returns with FIQ interrupts enabled.
410;
411;       NOTE:  It is very important to ensure all FIQ interrupts are cleared
412;       prior to enabling nested FIQ interrupts.  */
413    IF  :DEF:TX_ENABLE_FIQ_NESTING
414    BL      _tx_thread_fiq_nesting_start
415    ENDIF
416;
417;    /* Application FIQ handlers can be called here!  */
418;
419;    /* If interrupt nesting was started earlier, the end of interrupt nesting
420;       service must be called before returning to _tx_thread_fiq_context_restore.  */
421    IF  :DEF:TX_ENABLE_FIQ_NESTING
422    BL      _tx_thread_fiq_nesting_end
423    ENDIF
424;
425;    /* Jump to fiq context restore to restore system context.  */
426    B       _tx_thread_fiq_context_restore
427;
428;
429    ELSE
430    EXPORT  __tx_fiq_handler
431__tx_fiq_handler
432    B       __tx_fiq_handler                    ; FIQ interrupt handler
433    ENDIF
434;
435;    /* Reference build options and version ID to ensure they come in.  */
436;
437    LDR     r2, =_tx_build_options              ; Pickup build options variable address
438    LDR     r0, [r2, #0]                        ; Pickup build options content
439    LDR     r2, =_tx_version_id                 ; Pickup version ID variable address
440    LDR     r0, [r2, #0]                        ; Pickup version ID content
441;
442;
443    END
444
445