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