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