diff options
| author | Tiejun Zhou <[email protected]> | 2022-10-26 23:41:13 +0000 |
|---|---|---|
| committer | Tiejun Zhou <[email protected]> | 2022-10-26 23:41:13 +0000 |
| commit | 3e8e85cdc1e51f9de577457377a4f9a4f6b9b82f (patch) | |
| tree | 861c0ab74e5dc5de7509b4b85f5e75dd74457117 /ports_smp | |
| parent | b871c33620f9b58a83e92a33f4ca00025e850c7f (diff) | |
Release 6.2.0v6.2.0_rel
Diffstat (limited to 'ports_smp')
43 files changed, 6351 insertions, 0 deletions
diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/.cproject b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/.cproject new file mode 100644 index 00000000..cb9aa7c8 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/.cproject @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage"> + <storageModule moduleId="org.eclipse.cdt.core.settings"> + <cconfiguration id="com.arm.eclipse.build.config.baremetal.exe.debug.base.1803240871"> + <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.arm.eclipse.build.config.baremetal.exe.debug.base.1803240871" moduleId="org.eclipse.cdt.core.settings" name="Debug"> + <externalSettings/> + <extensions> + <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="com.arm.eclipse.builder.armcc.error" point="org.eclipse.cdt.core.ErrorParser"/> + </extensions> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <configuration artifactExtension="axf" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="clean" description="" id="com.arm.eclipse.build.config.baremetal.exe.debug.base.1803240871" name="Debug" parent="com.arm.eclipse.build.config.baremetal.exe.debug.base"> + <folderInfo id="com.arm.eclipse.build.config.baremetal.exe.debug.base.1803240871." name="/" resourcePath=""> + <toolChain id="com.arm.toolchain.baremetal.374109035" name="Arm Compiler 5 (DS-5 built-in)" superClass="com.arm.toolchain.baremetal"> + <option id="com.arm.toolchain.ac5.option.target.cpu_fpu.1442008928" superClass="com.arm.toolchain.ac5.option.target.cpu_fpu" useByScannerDiscovery="false" value="Cortex-R8.VFPv3_D16_FP16" valueType="string"/> + <option id="com.arm.toolchain.ac5.option.fppcs.1860512958" name="Floating-point PCS" superClass="com.arm.toolchain.ac5.option.fppcs" useByScannerDiscovery="false" value="com.arm.tool.c.compiler.option.fppcs.hard" valueType="enumerated"/> + <option id="com.arm.toolchain.ac5.option.inst.1449330817" name="Instruction set" superClass="com.arm.toolchain.ac5.option.inst" useByScannerDiscovery="false" value="com.arm.tool.c.compiler.option.inst.arm" valueType="enumerated"/> + <targetPlatform id="com.arm.toolchain.baremetal.374109035.836409078" name=""/> + <builder buildPath="${workspace_loc:/demo_threadx}/Debug" id="com.arm.toolchain.baremetal.builder.987677285" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="8" superClass="com.arm.toolchain.baremetal.builder"/> + <tool id="com.arm.tool.c.compiler.502732960" name="Arm C Compiler 5" superClass="com.arm.tool.c.compiler"> + <option defaultValue="com.arm.tool.c.compiler.option.optlevel.min" id="com.arm.tool.c.compiler.option.optlevel.2147390479" name="Optimization level" superClass="com.arm.tool.c.compiler.option.optlevel" useByScannerDiscovery="true" valueType="enumerated"/> + <option id="com.arm.tool.c.compiler.option.targetcpu.340427204" name="Target CPU (--cpu)" superClass="com.arm.tool.c.compiler.option.targetcpu" useByScannerDiscovery="true" value="Cortex-R8" valueType="string"/> + <option id="com.arm.tool.c.compiler.option.fppcs.577495892" name="Floating-point PCS (--apcs)" superClass="com.arm.tool.c.compiler.option.fppcs" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.fppcs.hard" valueType="enumerated"/> + <option id="com.arm.tool.c.compiler.option.inst.1235707985" name="Instruction set" superClass="com.arm.tool.c.compiler.option.inst" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.inst.arm" valueType="enumerated"/> + <option id="com.arm.tool.c.compiler.option.incpath.1124000016" name="Include path (-I)" superClass="com.arm.tool.c.compiler.option.incpath" useByScannerDiscovery="false" valueType="includePath"> + <listOptionValue builtIn="false" value=""${workspace_loc:/tx/inc_port}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/tx/inc_generic}""/> + </option> + <inputType id="com.arm.tool.c.compiler.input.1480260868" superClass="com.arm.tool.c.compiler.input"/> + <inputType id="com.arm.tool.cpp.compiler.input.97641973" superClass="com.arm.tool.cpp.compiler.input"/> + </tool> + <tool id="com.arm.tool.cpp.compiler.1547990840" name="Arm C++ Compiler 5" superClass="com.arm.tool.cpp.compiler"> + <option defaultValue="com.arm.tool.c.compiler.option.optlevel.min" id="com.arm.tool.c.compiler.option.optlevel.505573824" name="Optimization level" superClass="com.arm.tool.c.compiler.option.optlevel" valueType="enumerated"/> + </tool> + <tool id="com.arm.tool.assembler.1832506761" name="Arm Assembler 5" superClass="com.arm.tool.assembler"> + <option id="com.arm.tool.assembler.option.cpu.1024239032" name="Target CPU (--cpu)" superClass="com.arm.tool.assembler.option.cpu" useByScannerDiscovery="true" value="Cortex-R8" valueType="string"/> + <option id="com.arm.tool.assembler.option.fppcs.390080950" name="Floating-point PCS (--apcs)" superClass="com.arm.tool.assembler.option.fppcs" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.fppcs.hard" valueType="enumerated"/> + <option id="com.arm.tool.assembler.option.inst.1329777569" name="Instruction set" superClass="com.arm.tool.assembler.option.inst" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.inst.arm" valueType="enumerated"/> + <option id="com.arm.tool.assembler.option.preproc.1552112760" name="Preprocess input before assembling (--cpreproc)" superClass="com.arm.tool.assembler.option.preproc" useByScannerDiscovery="false" value="true" valueType="boolean"/> + <inputType id="com.arm.tool.assembler.input.568650196" superClass="com.arm.tool.assembler.input"/> + </tool> + <tool id="com.arm.tool.c.linker.1213717379" name="Arm Linker 5" superClass="com.arm.tool.c.linker"> + <option id="com.arm.tool.c.linker.option.cpu.2034204217" name="Target CPU (--cpu)" superClass="com.arm.tool.c.linker.option.cpu" useByScannerDiscovery="true" value="Cortex-R8" valueType="string"/> + <option id="com.arm.tool.c.linker.libs.1039233109" name="User library files" superClass="com.arm.tool.c.linker.libs" useByScannerDiscovery="false" valueType="libs"> + <listOptionValue builtIn="false" value=""${workspace_loc:/tx/Debug/tx.a}""/> + </option> + <option id="com.arm.tool.c.linker.option.scatter.273877226" name="Scatter file (--scatter)" superClass="com.arm.tool.c.linker.option.scatter" useByScannerDiscovery="false" value="../demo_threadx.ld" valueType="string"/> + </tool> + <tool id="com.arm.tool.librarian.929712312" name="Arm Librarian 5" superClass="com.arm.tool.librarian"/> + </toolChain> + </folderInfo> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> + </cconfiguration> + <cconfiguration id="com.arm.eclipse.build.config.baremetal.exe.release.base.1220518793"> + <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.arm.eclipse.build.config.baremetal.exe.release.base.1220518793" moduleId="org.eclipse.cdt.core.settings" name="Release"> + <externalSettings/> + <extensions> + <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> + </extensions> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <configuration artifactExtension="axf" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="clean" description="" id="com.arm.eclipse.build.config.baremetal.exe.release.base.1220518793" name="Release" parent="com.arm.eclipse.build.config.baremetal.exe.release.base"> + <folderInfo id="com.arm.eclipse.build.config.baremetal.exe.release.base.1220518793." name="/" resourcePath=""> + <toolChain id="com.arm.toolchain.baremetal.exe.release.base.var.arm_compiler_5-5.6.7.997372112" name="Arm Compiler 5.06u7"> + <targetPlatform id="com.arm.toolchain.baremetal.exe.release.base.var.arm_compiler_5-5.6.7.997372112.1793920751" name=""/> + <builder autoBuildTarget="all" buildPath="${workspace_loc:/demo_threadx}/Release" cleanBuildTarget="clean" enableAutoBuild="false" enableCleanBuild="true" enabledIncrementalBuild="true" id="com.arm.toolchain.baremetal.builder.1590448126" incrementalBuildTarget="all" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="false" superClass="com.arm.toolchain.baremetal.builder"/> + </toolChain> + </folderInfo> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> + </cconfiguration> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <project id="cortex-r8_demo_threadx.com.arm.eclipse.build.project.baremetal.exe.1823514114" name="Executable"/> + </storageModule> + <storageModule moduleId="scannerConfiguration"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/> + <storageModule moduleId="refreshScope" versionNumber="2"> + <configuration configurationName="Debug"> + <resource resourceType="PROJECT" workspacePath="/cortex-r8_demo_threadx"/> + </configuration> + <configuration configurationName="Release"> + <resource resourceType="PROJECT" workspacePath="/cortex-r8_demo_threadx"/> + </configuration> + </storageModule> + <storageModule moduleId="com.arm.projectSettings" version="6.0.0"/> + <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/> + <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/> +</cproject> diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/.project b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/.project new file mode 100644 index 00000000..29c218ae --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/.project @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>demo_threadx</name> + <comment></comment> + <projects> + <project>cortex-r8_tx</project> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name> + <triggers>clean,full,incremental,</triggers> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name> + <triggers>full,incremental,</triggers> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.cdt.core.cnature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature> + </natures> +</projectDescription> diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_GIC.S b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_GIC.S new file mode 100644 index 00000000..eb1f366e --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_GIC.S @@ -0,0 +1,292 @@ +; ------------------------------------------------------------ +; Cortex-R MPCore - Interrupt Controller functions +; +; Copyright ARM Ltd 2009. All rights reserved. +; ------------------------------------------------------------ + + PRESERVE8 + + AREA MP_GIC, CODE, READONLY + +; ------------------------------------------------------------ +; GIC +; ------------------------------------------------------------ + + ; CPU Interface offset from base of private peripheral space --> 0x0100 + ; Interrupt Distributor offset from base of private peripheral space --> 0x1000 + + ; Typical calls to enable interrupt ID X: + ; enable_irq_id(X) <-- Enable that ID + ; set_irq_priority(X, 0) <-- Set the priority of X to 0 (the max priority) + ; set_priority_mask(0x1F) <-- Set CPU's priority mask to 0x1F (the lowest priority) + ; enable_GIC() <-- Enable the GIC (global) + ; enable_gic_processor_interface() <-- Enable the CPU interface (local to the CPU) + + + EXPORT enable_GIC + ; void enable_GIC(void) + ; Global enable of the Interrupt Distributor +enable_GIC PROC + + ; Get base address of private perpherial space + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + ADD r0, r0, #0x1000 ; Add the GIC offset + + LDR r1, [r0] ; Read the GIC's Enable Register (ICDDCR) + ORR r1, r1, #0x01 ; Set bit 0, the enable bit + STR r1, [r0] ; Write the GIC's Enable Register (ICDDCR) + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT disable_GIC + ; void disable_GIC(void) + ; Global disable of the Interrupt Distributor +disable_GIC PROC + + ; Get base address of private perpherial space + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + ADD r0, r0, #0x1000 ; Add the GIC offset + + LDR r1, [r0] ; Read the GIC's Enable Register (ICDDCR) + BIC r1, r1, #0x01 ; Set bit 0, the enable bit + STR r1, [r0] ; Write the GIC's Enable Register (ICDDCR) + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT enable_irq_id + ; void enable_irq_id(unsigned int ID) + ; Enables the interrupt source number ID +enable_irq_id PROC + + ; Get base address of private perpherial space + MOV r1, r0 ; Back up passed in ID value + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + ; Each interrupt source has an enable bit in the GIC. These + ; are grouped into registers, with 32 sources per register + ; First, we need to identify which 32 bit block the interrupt lives in + MOV r2, r1 ; Make working copy of ID in r2 + MOV r2, r2, LSR #5 ; LSR by 5 places, affective divide by 32 + ; r2 now contains the 32 bit block this ID lives in + MOV r2, r2, LSL #2 ; Now multiply by 4, to covert offset into an address offset (four bytes per reg) + + ; Now work out which bit within the 32 bit block the ID is + AND r1, r1, #0x1F ; Mask off to give offset within 32bit block + MOV r3, #1 ; Move enable value into r3 + MOV r3, r3, LSL r1 ; Shift it left to position of ID + + ADD r2, r2, #0x1100 ; Add the base offset of the Enable Set registers to the offset for the ID + STR r3, [r0, r2] ; Store out (ICDISER) + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT disable_irq_id + ; void disable_irq_id(unsigned int ID) + ; Disables the interrupt source number ID +disable_irq_id PROC + + ; Get base address of private perpherial space + MOV r1, r0 ; Back up passed in ID value + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + ; First, we need to identify which 32 bit block the interrupt lives in + MOV r2, r1 ; Make working copy of ID in r2 + MOV r2, r2, LSR #5 ; LSR by 5 places, affective divide by 32 + ; r2 now contains the 32 bit block this ID lives in + MOV r2, r2, LSL #2 ; Now multiply by 4, to covert offset into an address offset (four bytes per reg) + + ; Now work out which bit within the 32 bit block the ID is + AND r1, r1, #0x1F ; Mask off to give offset within 32bit block + MOV r3, #1 ; Move enable value into r3 + MOV r3, r3, LSL r1 ; Shift it left to position of ID in 32 bit block + + ADD r2, r2, #0x1180 ; Add the base offset of the Enable Clear registers to the offset for the ID + STR r3, [r0, r2] ; Store out (ICDICER) + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT set_irq_priority + ; void set_irq_priority(unsigned int ID, unsigned int priority) + ; Sets the priority of the specifed ID + ; r0 = ID + ; r1 = priority +set_irq_priority PROC + + ; Get base address of private perpherial space + MOV r2, r0 ; Back up passed in ID value + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + ; r0 = base addr + ; r1 = priority + ; r2 = ID + + ; Make sure that priority value is only 5 bits, and convert to expected format + AND r1, r1, #0x1F + MOV r1, r1, LSL #3 + + ; Find which priority register this ID lives in + BIC r3, r2, #0x03 ; Make a copy of the ID, clearing off the bottom two bits + ; There are four IDs per reg, by clearing the bottom two bits we get an address offset + ADD r3, r3, #0x1400 ; Now add the offset of the Priority Level registers from the base of the private peripheral space + ADD r0, r0, r3 ; Now add in the base address of the private peripheral space, giving us the absolute address + + + ; Now work out which ID in the register it is + AND r2, r2, #0x03 ; Clear all but the bottom four bits, leaves which ID in the reg it is (which byte) + MOV r2, r2, LSL #3 ; Multiply by 8, this gives a bit offset + + ; Read -> Modify -> Write + MOV r12, #0xFF ; Mask (8 bits) + MOV r12, r12, LSL r2 ; Move mask into correct bit position + MOV r1, r1, LSL r2 ; Also, move passed in priority value into correct bit position + + LDR r3, [r0] ; Read current value of the Priority Level register (ICDIPR) + BIC r3, r3, r12 ; Clear appropiate field + ORR r3, r3, r1 ; Now OR in the priority value + STR r3, [r0] ; And store it back again (ICDIPR) + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT enable_gic_processor_interface + ; void enable_gic_processor_interface(void) + ; Enables the processor interface + ; Must been done one each CPU seperately +enable_gic_processor_interface PROC + + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + LDR r1, [r0, #0x100] ; Read the Processor Interface Control register (ICCICR/ICPICR) + ORR r1, r1, #0x03 ; Bit 0: Enables secure interrupts, Bit 1: Enables Non-Secure interrupts + STR r1, [r0, #0x100] ; Write the Processor Interface Control register (ICCICR/ICPICR) + + BX lr + ENDP + + +; ------------------------------------------------------------ + + EXPORT disable_gic_processor_interface + ; void disable_gic_processor_interface(void) + ; Disables the processor interface + ; Must been done one each CPU seperately +disable_gic_processor_interface PROC + + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + LDR r1, [r0, #0x100] ; Read the Processor Interface Control register (ICCICR/ICPICR) + BIC r1, r1, #0x03 ; Bit 0: Enables secure interrupts, Bit 1: Enables Non-Secure interrupts + STR r1, [r0, #0x100] ; Write the Processor Interface Control register (ICCICR/ICPICR) + + BX lr + ENDP + + +; ------------------------------------------------------------ + + EXPORT set_priority_mask + ; void set_priority_mask(unsigned int priority) + ; Sets the Priority mask register for the CPU run on + ; The reset value masks ALL interrupts! +set_priority_mask PROC + + ; Get base address of private perpherial space + MOV r1, r0 ; Back up passed in ID value + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + STR r1, [r0, #0x0104] ; Write the Priority Mask register (ICCPMR/ICCIPMR) + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT set_binary_port + ; void set_binary_port(unsigned int priority) + ; Sets the Binary Point Register for the CPU run on +set_binary_port PROC + + ; Get base address of private perpherial space + MOV r1, r0 ; Back up passed in ID value + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + STR r1, [r0, #0x0108] ; Write the Binary register (ICCBPR/ICCBPR) + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT read_irq_ack + ; unsigned int read_irq_ack(void) + ; Returns the value of the Interrupt Acknowledge Register +read_irq_ack PROC + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + LDR r0, [r0, #0x010C] ; Read the Interrupt Acknowledge Register (ICCIAR) + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT write_end_of_irq + ; void write_end_of_irq(unsigned int ID) + ; Writes ID to the End Of Interrupt register +write_end_of_irq PROC + + ; Get base address of private perpherial space + MOV r1, r0 ; Back up passed in ID value + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + STR r1, [r0, #0x0110] ; Write ID to the End of Interrupt register (ICCEOIR) + + BX lr + ENDP + +; ------------------------------------------------------------ +; SGI +; ------------------------------------------------------------ + + EXPORT send_sgi + ; void send_sgi(unsigned int ID, unsigned int target_list, unsigned int filter_list); + ; Send a software generate interrupt +send_sgi PROC + + AND r3, r0, #0x0F ; Mask off unused bits of ID, and move to r3 + AND r1, r1, #0x0F ; Mask off unused bits of target_filter + AND r2, r2, #0x0F ; Mask off unused bits of filter_list + + ORR r3, r3, r1, LSL #16 ; Combine ID and target_filter + ORR r3, r3, r2, LSL #24 ; and now the filter list + + ; Get the address of the GIC + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + ADD r0, r0, #0x1F00 ; Add offset of the sgi_trigger reg + + STR r3, [r0] ; Write to the Software Generated Interrupt Register (ICDSGIR) + + BX lr + ENDP + +; ------------------------------------------------------------ +; End of code +; ------------------------------------------------------------ + + END + +; ------------------------------------------------------------ +; End of MP_GIC.s +; ------------------------------------------------------------ diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_GIC.h b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_GIC.h new file mode 100644 index 00000000..81551bee --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_GIC.h @@ -0,0 +1,80 @@ +// ------------------------------------------------------------ +// Cortex-R MPCore - Interrupt Controller functions +// Header File +// +// Copyright ARM Ltd 2009. All rights reserved. +// ------------------------------------------------------------ + +#ifndef _CORTEXA_GIC_ +#define _CORTEXA_GIC_ + +// ------------------------------------------------------------ +// GIC +// ------------------------------------------------------------ + +// Typical calls to enable interrupt ID X: +// enable_irq_id(X) <-- Enable that ID +// set_irq_priority(X, 0) <-- Set the priority of X to 0 (the max priority) +// set_priority_mask(0x1F) <-- Set Core's priority mask to 0x1F (the lowest priority) +// enable_GIC() <-- Enable the GIC (global) +// enable_gic_processor_interface() <-- Enable the CPU interface (local to the core) +// +// OR +// +// Use init_GIC() which is a simple switch everything on function! :-) +// + +// Global enable of the Interrupt Distributor +void enable_GIC(void); + +// Global disable of the Interrupt Distributor +void disable_GIC(void); + +// Enables the interrupt source number ID +void enable_irq_id(unsigned int ID); + +// Disables the interrupt source number ID +void disable_irq_id(unsigned int ID); + +// Sets the priority of the specifed ID +void set_irq_priority(unsigned int ID, unsigned int priority); + +// Enables the processor interface +// Must been done one each core seperately +void enable_gic_processor_interface(void); + +// Disables the processor interface +void disable_gic_processor_interface(void); + +// Sets the Priority mask register for the core run on +// The reset value masks ALL interrupts! +void set_priority_mask(unsigned int priority); + +// Sets the Binary Point Register for the core run on +void set_binary_port(unsigned int priority); + +// Returns the value of the Interrupt Acknowledge Register +unsigned int read_irq_ack(void); + +// Writes ID to the End Of Interrupt register +void write_end_of_irq(unsigned int ID); + +// Lazy Init function, a quick way of enabling interrupts +// * Enables the GIC (global) and CPU Interface (just for this core) +// * Enables interrupt sources 0->31, and sets their priority to 0x0 +// * Sets the CPU's Priority mask to 0x1F +// * Clears the CPSR I bit +void init_GIC(void); + +// ------------------------------------------------------------ +// SGI +// ------------------------------------------------------------ + +// Send a software generate interrupt +void send_sgi(unsigned int ID, unsigned int core_list, unsigned int filter_list); + +#endif + +// ------------------------------------------------------------ +// End of MP_GIC.h +// ------------------------------------------------------------ diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_GlobalTimer.h b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_GlobalTimer.h new file mode 100644 index 00000000..7a272b3e --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_GlobalTimer.h @@ -0,0 +1,42 @@ +// ------------------------------------------------------------ +// Cortex-R MPCore - Global timer functions +// Header Filer +// +// Copyright ARM Ltd 2009. All rights reserved. +// ------------------------------------------------------------ + +#ifndef _CORTEXA_GLOBAL_TIMER_ +#define _CORTEXA_GLOBAL_TIMER_ + +// Typical set of calls to enable Timer: +// init_global_timer( AUTO_INCREMENT>, INCREMENT_VALUE ); +// set_global_timer_comparator( UPPER_32_BITS, LOWER_32_BITS ); +// start_global_timer(); + + +// Sets up the private timer +// r0: IF 0 (AutoIncrement) ELSE (SingleShot) +// r1: Increment value (ignored if auto_increment != 0) +void init_global_timer(unsigned int auto_increment, unsigned int increment_value) + +// Sets the comparator value for this CPU +void set_global_timer_comparator(unsigned int top, unsigned int bottom); + +// Starts the private timer +void start_global_timer(void); + +// Stops the private timer +void stop_global_timer(void); + +// Reads the current value of the timer count register +// Returns bits 63:32 in *top, and bits 31:0 in *bottom +void read_global_timer(unsigned int* top, unsigned int* bottom); + +// Clears the private timer interrupt +void clear_global_timer_irq(void); + +#endif + +// ------------------------------------------------------------ +// End of MP_PrivateTimer.h +// ------------------------------------------------------------ diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_GlobalTimer.s b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_GlobalTimer.s new file mode 100644 index 00000000..04245587 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_GlobalTimer.s @@ -0,0 +1,169 @@ +; ------------------------------------------------------------ +; Cortex-R MPCore - Global timer functions +; +; Copyright ARM Ltd 2009. All rights reserved. +; ------------------------------------------------------------ + + PRESERVE8 + + AREA MP_PrivateTimer, CODE, READONLY + + ; PPI ID 27 + + + ; Typical set of calls to enable Timer: + ; init_global_timer() + ; set_global_timer_comparator() + ; start_global_timer() + +; ------------------------------------------------------------ + + EXPORT init_global_timer + ; void init_global_timer(unsigned int auto_increment, unsigned int increment_value) + ; Initializes the Global Timer, but does NOT set the enable bit + ; r0: IF 0 (AutoIncrement) ELSE (SingleShot) + ; r1: increment value +init_global_timer PROC + + ; Get base address of private perpherial space + MRC p15, 4, r2, c15, c0, 0 ; Read periph base address + + ; Control register bit layout + ; Bit 0 - Timer enable + ; Bit 1 - Comp enable + ; Bit 2 - IRQ enable + ; Bit 3 - Auto-increment enable + + ; Ensure the timer is disabled + LDR r3, [r2, #0x208] ; Read control reg + BIC r3, r3, #0x01 ; Clear enable bit + STR r3, [r2, #0x208] ; Write control reg + + ; Form control reg value + CMP r0, #0 ; Check whether to enable auto-reload + MOVNE r0, #0x00 ; No auto-reload + MOVEQ r0, #0x04 ; With auto-reload + STR r0, [r2, #0x208] ; Store to control register + + ; Store increment value + STREQ r1, [r2, #0x218] + + ; Clear timer value + MOV r0, #0x0 + STR r0, [r2, #0x0] + STR r0, [r2, #0x4] + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT set_global_timer_comparator + ; void set_global_timer_comparator(unsigned int top, unsigned int bottom); + ; Writes the comparator registers, and enable the comparator bit in the control register + ; r0: 63:32 of the comparator value + ; r1: 31:0 of the comparator value +set_global_timer_comparator PROC + + MRC p15, 4, r2, c15, c0, 0 ; Read periph base address + + ; Disable comparator before updating register + LDR r1, [r2, #0x208] ; Read control reg + BIC r3, r3, #0x02 ; Clear comparator enable bit + STR r3, [r2, #0x208] ; Write modified value back + + ; Write the comparator registers + STR r1, [r2, #0x210] ; Write lower 32 bits + STR r0, [r2, #0x214] ; Write upper 32 bits + DMB + + ; Re-enable the comparator + ORR r3, r3, #0x02 ; Set comparator enable bit + STR r3, [r2, #0x208] ; Write modified value back + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT start_global_timer + ; void start_global_timer(void) + ; Starts the global timer +start_global_timer PROC + + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + LDR r1, [r0, #0x208] ; Read control reg + ORR r1, r1, #0x01 ; Set enable bit + STR r1, [r0, #0x208] ; Write modified value back + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT stop_global_timer + ; void stop_private_timer(void) + ; Stops the private timer +;stop_private_timer PROC +stop_global_timer PROC + + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + LDR r1, [r0, #0x208] ; Read control reg + BIC r1, r1, #0x01 ; Clear enable bit + STR r1, [r0, #0x208] ; Write modified value back + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT get_global_timer_count + ; void read_global_timer(unsigned int* top, unsigned int* bottom) + ; Reads the current value of the timer count register + ; r0: Address of unsigned int for bits 63:32 + ; r1: Address of unsigned int for bits 31:0 +get_global_timer_count PROC + +get_global_timer_count_loop + MRC p15, 4, r2, c15, c0, 0 ; Read periph base address + + LDR r12,[r2, #0x04] ; Read bits 63:32 + LDR r3, [r2, #0x00] ; Read bits 31:0 + LDR r2, [r2, #0x04] ; Re-read bits 63:32 + + CMP r2, r12 ; Have the top bits changed? + BNE get_global_timer_count_loop + + ; Store result out to pointers + STR r2, [r0] + STR r3, [r1] + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT clear_global_timer_irq + ; void clear_global_timer_irq(void) + ; Clears the global timer interrupt +clear_global_timer_irq PROC + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + ; Clear the interrupt by writing 0x1 to the Timer's Interrupt Status register + MOV r1, #1 + STR r1, [r0, #0x20C] + + BX lr + ENDP + +; ------------------------------------------------------------ +; End of code +; ------------------------------------------------------------ + + END + +; ------------------------------------------------------------ +; End of MP_GlobalTimer.s +; ------------------------------------------------------------ diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_Mutexes.h b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_Mutexes.h new file mode 100644 index 00000000..2a613b7e --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_Mutexes.h @@ -0,0 +1,42 @@ +// ------------------------------------------------------------ +// Cortex-R MPCore - Mutex +// Header File +// +// Copyright ARM Ltd 2009. All rights reserved. +// ------------------------------------------------------------ + +#ifndef _CORTEXA_MUTEX_ +#define _CORTEXA_MUTEX_ + +// Struct +// 0xFF=unlocked 0x0 = Locked by CPU 0, +// 0x1 = Locked by CPU 1, +// 0x2 = Locked by CPU 2, +// 0x3 = Locked by CPU 3 +typedef struct +{ + unsigned int lock; +}mutex_t; + +// Places mutex into a known state +// r0 = address of mutex_t +void init_mutex(mutex_t* pMutex); + +// Blocking call, returns once successfully locked a mutex +// r0 = address of mutex_t +void lock_mutex(mutex_t* pMutex); + +// Releases (unlock) mutex. Fails if CPU not owner of mutex. +// returns 0x0 for success, and 0x1 for failure +// r0 = address of mutex_t +unsigned int unlock_mutex(mutex_t* pMutex); + +// Returns 0x0 if mutex unlocked, 0x1 is locked +// r0 = address of mutex_t +void is_mutex_locked(mutex_t* pMutex); + +#endif + +// ------------------------------------------------------------ +// End of MP_Mutexes.h +// ------------------------------------------------------------ diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_Mutexes.s b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_Mutexes.s new file mode 100644 index 00000000..3c20b253 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_Mutexes.s @@ -0,0 +1,123 @@ +; ------------------------------------------------------------ +; Cortex-R MPCore - Mutex Code +; +; Copyright ARM Ltd 2009. All rights reserved. +; ------------------------------------------------------------ + + PRESERVE8 + + AREA MP_Mutexes, CODE, READONLY + + ;NOTES + ; struct mutex_t defined in A9MP_Mutexes.h + ; typedef struct mutex_t + ; { + ; unsigned int lock; <-- offset 0 + ; } + ; + ; lock: 0xFF=unlocked 0x0 = Locked by CPU 0, 0x1 = Locked by CPU 1, 0x2 = Locked by CPU 2, 0x3 = Locked by CPU 3 + ; + +UNLOCKED EQU 0xFF + +; ------------------------------------------------------------ + + EXPORT init_mutex + ; void init_mutex(mutex_t* pMutex) + ; Places mutex into a known state + ; r0 = address of mutex_t +init_mutex PROC + + MOV r1, #UNLOCKED ; Mark as unlocked + STR r1, [r0] + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT lock_mutex + ; void lock_mutex(mutex_t* pMutex) + ; Blocking call, returns once successfully locked a mutex + ; r0 = address of mutex_t +lock_mutex PROC + + ; Is mutex locked? + ; ----------------- + LDREX r1, [r0] ; Read lock field + CMP r1, #UNLOCKED ; Compare with "unlocked" + + WFENE ; If mutex is locked, go into standby + BNE lock_mutex ; On waking re-check the mutex + + ; Attempt to lock mutex + ; ----------------------- + MRC p15, 0, r1, c0, c0, 5 ; Read CPU ID register + AND r1, r1, #0x03 ; Mask off, leaving the CPU ID field. + STREX r2, r1, [r0] ; Attempt to lock mutex, by write CPU's ID to lock field + CMP r2, #0x0 ; Check wether store completed successfully (0=succeeded) + BNE lock_mutex ; If store failed, go back to beginning and try again + + DMB + + BX lr ; Return as mutex is now locked by this cpu + ENDP + +; ------------------------------------------------------------ + + EXPORT unlock_mutex + ; unsigned int unlock_mutex(mutex_t* pMutex) + ; Releases mutex, returns 0x0 for success and 0x1 for failure + ; r0 = address of mutex_t +unlock_mutex PROC + + ; Does this CPU own the mutex? + ; ----------------------------- + MRC p15, 0, r1, c0, c0, 5 ; Read CPU ID register + AND r1, r1, #0x03 ; Mask off, leaving the CPU ID in r1 + LDR r2, [r0] ; Read the lock field of the mutex + CMP r1, r2 ; Compare ID of this CPU with the lock owner + MOVNE r0, #0x1 ; If ID doesn't match, return "fail" + BXNE lr + + + ; Unlock mutex + ; ------------- + DMB ; Ensure that accesses to shared resource have completed + + MOV r1, #UNLOCKED ; Write "unlocked" into lock field + STR r1, [r0] + + DMB ; To ensure update of the mutex occurs before other CPUs awake + + SEV ; Send event to other CPUs, wakes anyone waiting on a mutex (using WFE) + + MOV r0, #0x0 ; Return "success" + BX lr + + ENDP + +; ------------------------------------------------------------ + + EXPORT is_mutex_locked + ; void is_mutex_locked(mutex_t* pMutex) + ; Returns 0x0 if mutex unlocked, 0x1 is locked + ; r0 = address of mutex_t +is_mutex_locked PROC + LDR r0, [r0] + CMP r0, #UNLOCKED + MOVEQ r0, #0x0 + MOVNE r0, #0x1 + BX lr + ENDP + + +; ------------------------------------------------------------ +; End of code +; ------------------------------------------------------------ + + END + +; ------------------------------------------------------------ +; End of MP_Mutexes.s +; ------------------------------------------------------------ diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_PrivateTimer.h b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_PrivateTimer.h new file mode 100644 index 00000000..cd0d37f8 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_PrivateTimer.h @@ -0,0 +1,36 @@ +// ------------------------------------------------------------ +// Cortex-R MPCore - Private timer functions +// Header Filer +// +// Copyright ARM Ltd 2009. All rights reserved. +// ------------------------------------------------------------ + +#ifndef _CORTEXA_PRIVATE_TIMER_ +#define _CORTEXA_PRIVATE_TIMER_ + +// Typical set of calls to enable Timer: +// init_private_timer(0xXXXX, 0) <-- Counter down value of 0xXXXX, with auto-reload +// start_private_timer() + +// Sets up the private timer +// r0: initial load value +// r1: IF 0 (AutoReload) ELSE (SingleShot) +void init_private_timer(unsigned int load_value, unsigned int auto_reload); + +// Starts the private timer +void start_private_timer(void); + +// Stops the private timer +void stop_private_timer(void); + +// Reads the current value of the timer count register +unsigned int get_private_timer_count(void); + +// Clears the private timer interrupt +void clear_private_timer_irq(void); + +#endif + +// ------------------------------------------------------------ +// End of MP_PrivateTimer.h +// ------------------------------------------------------------ diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_PrivateTimer.s b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_PrivateTimer.s new file mode 100644 index 00000000..3be7249b --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_PrivateTimer.s @@ -0,0 +1,121 @@ +; ------------------------------------------------------------ +; Cortex-R MPCore - Private timer functions +; +; Copyright ARM Ltd 2009. All rights reserved. +; ------------------------------------------------------------ + + PRESERVE8 + + AREA MP_PrivateTimer, CODE, READONLY + + ; PPI ID 29 + + + ; Typical set of calls to enable Timer: + ; init_private_timer(0xXXXX, 0) <-- Counter down value of 0xXXXX, with auto-reload + ; start_private_timer() + + ; Timer offset from base of private peripheral space --> 0x600 + +; ------------------------------------------------------------ + + EXPORT init_private_timer + ; void init_private_timer(unsigned int load_value, unsigned int auto_reload) + ; Sets up the private timer + ; r0: initial load value + ; r1: IF 0 (AutoReload) ELSE (SingleShot) +init_private_timer PROC + + ; Get base address of private perpherial space + MOV r2, r0 ; Make a copy of r0 before corrupting + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + ; Set the load value + STR r2, [r0, #0x600] + + ; Control register bit layout + ; Bit 0 - Enable + ; Bit 1 - Auto-Reload ; see DE681117 + ; Bit 2 - IRQ Generation + + ; Form control reg value + CMP r1, #0 ; Check whether to enable auto-reload + MOVNE r2, #0x04 ; No auto-reload + MOVEQ r2, #0x06 ; With auto-reload + + ; Store to control register + STR r2, [r0, #0x608] + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT start_private_timer + ; void start_private_timer(void) + ; Starts the private timer +start_private_timer PROC + + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + LDR r1, [r0, #0x608] ; Read control reg + ORR r1, r1, #0x01 ; Set enable bit + STR r1, [r0, #0x608] ; Write modified value back + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT stop_private_timer + ; void stop_private_timer(void) + ; Stops the private timer +stop_private_timer PROC + + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + LDR r1, [r0, #0x608] ; Read control reg + BIC r1, r1, #0x01 ; Clear enable bit + STR r1, [r0, #0x608] ; Write modified value back + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT get_private_timer_count + ; unsigned int read_private_timer(void) + ; Reads the current value of the timer count register +get_private_timer_count PROC + + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + LDR r0, [r0, #0x604] ; Read count register + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT clear_private_timer_irq + ; void clear_private_timer_irq(void) + ; Clears the private timer interrupt +clear_private_timer_irq PROC + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + ; Clear the interrupt by writing 0x1 to the Timer's Interrupt Status register + MOV r1, #1 + STR r1, [r0, #0x60C] + + BX lr + ENDP + +; ------------------------------------------------------------ +; End of code +; ------------------------------------------------------------ + + END + +; ------------------------------------------------------------ +; End of MP_PrivateTimer.s +; ------------------------------------------------------------ diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_SCU.h b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_SCU.h new file mode 100644 index 00000000..c9fe4da6 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_SCU.h @@ -0,0 +1,67 @@ +// ------------------------------------------------------------ +// Cortex-R MPCore - Snoop Control Unit +// Header File +// +// Copyright ARM Ltd 2009. All rights reserved. +// ------------------------------------------------------------ + +#ifndef _CORTEXA_SCU_ +#define _CORTEXA_SCU_ + +// ------------------------------------------------------------ +// SCU +// ------------------------------------------------------------ + +// Returns the base address of the private peripheral memory space +unsigned int get_base_addr(void); + +// Returns the CPU ID (0 to 3) of the CPU executed on +unsigned int get_cpu_id(void); + +// Returns the number of cores in the A9 Cluster +// NOTE: +// returns 0 = 1 core +// 1 = 2 cores etc... +// This is the format of the register, decided to leave it unchanged. +unsigned int get_num_cpus(void); + +// Go to sleep, never returns +void go_to_sleep(void); + +// ------------------------------------------------------------ +// SCU +// ------------------------------------------------------------ + +// Enables the SCU +void enable_scu(void); + +// Set this core as participating in SMP +void join_smp(void); + +// Set this core as NOT participating in SMP +void leave_smp(void); + +// The return value is 1 bit per core: +// bit 0 - CPU 0 +// bit 1 - CPU 1 +// etc... +unsigned int get_cpus_in_smp(void); + + //Enable the broadcasting of cache & TLB maintenance operations +// When enabled AND in SMP, broadcast all "inner sharable" +// cache and TLM maintenance operations to other SMP cores +void enable_maintenance_broadcast(void); + +// Disable the broadcasting of cache & TLB maintenance operations +void disable_maintenance_broadcast(void); + +// cpu: 0x0=CPU 0 0x1=CPU 1 etc... +// This function invalidates the SCU copy of the tag rams +// for the specified core. +void secure_SCU_invalidate(unsigned int cpu, unsigned int ways); + +#endif + +// ------------------------------------------------------------ +// End of MP_SCU.h +// ------------------------------------------------------------ diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_SCU.s b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_SCU.s new file mode 100644 index 00000000..cfed344f --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/MP_SCU.s @@ -0,0 +1,193 @@ +; ------------------------------------------------------------ +; Cortex-R MPCore - SCU functions +; +; Copyright ARM Ltd 2009. All rights reserved. +; ------------------------------------------------------------ + + PRESERVE8 + + AREA MP_SCU, CODE, READONLY + +; ------------------------------------------------------------ +; Misc +; ------------------------------------------------------------ + + EXPORT get_base_addr + ; unsigned int get_base_addr(void) + ; Returns the base address of the private peripheral memory space +get_base_addr PROC + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address (see DE593076) + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT get_cpu_id + ; unsigned int get_cpu_id(void) + ; Returns the CPU ID (0 to 3) of the CPU executed on +get_cpu_id PROC + MRC p15, 0, r0, c0, c0, 5 ; Read CPU ID register + AND r0, r0, #0x03 ; Mask off, leaving the CPU ID field + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT get_num_cpus + ; unsigned int get_num_cpus(void) + ; Returns the number of CPUs in the A9 Cluster +get_num_cpus PROC + + ; Get base address of private perpherial space + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + LDR r0, [r0, #0x004] ; Read SCU Configuration register + AND r0, r0, #0x3 ; Bits 1:0 gives the number of cores + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT go_to_sleep + ; void go_to_sleep(void) +go_to_sleep PROC + WFI ; Go into standby + B go_to_sleep ; Catch in case of rogue events + BX lr + ENDP + +; ------------------------------------------------------------ +; SCU +; ------------------------------------------------------------ + + ; SCU offset from base of private peripheral space --> 0x000 + + EXPORT enable_scu + ; void enable_scu(void) + ; Enables the SCU +enable_scu PROC + + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + LDR r1, [r0, #0x0] ; Read the SCU Control Register + ORR r1, r1, #0x1 ; Set bit 0 (The Enable bit) + STR r1, [r0, #0x0] ; Write back modifed value + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT join_smp + ; void join_smp(void) + ; Set this CPU as participating in SMP +join_smp PROC + + ; SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 ; Read ACTLR + ORR r0, r0, #0x040 ; Set bit 6 + MCR p15, 0, r0, c1, c0, 1 ; Write ACTLR + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT leave_smp + ; void leave_smp(void) + ; Set this CPU as NOT participating in SMP +leave_smp PROC + + ; SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 ; Read ACTLR + BIC r0, r0, #0x040 ; Clear bit 6 + MCR p15, 0, r0, c1, c0, 1 ; Write ACTLR + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT get_cpus_in_smp + ; unsigned int get_cpus_in_smp(void) + ; The return value is 1 bit per core: + ; bit 0 - CPU 0 + ; bit 1 - CPU 1 + ; etc... +get_cpus_in_smp PROC + + MRC p15, 4, r0, c15, c0, 0 ; Read periph base address + + LDR r0, [r0, #0x004] ; Read SCU Configuration register + MOV r0, r0, LSR #4 ; Bits 7:4 gives the cores in SMP mode, shift then mask + AND r0, r0, #0x0F + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT enable_maintenance_broadcast + ; void enable_maintenance_broadcast(void) + ; Enable the broadcasting of cache & TLB maintenance operations + ; When enabled AND in SMP, broadcast all "inner sharable" + ; cache and TLM maintenance operations to other SMP cores +enable_maintenance_broadcast PROC + MRC p15, 0, r0, c1, c0, 1 ; Read Aux Ctrl register + ORR r0, r0, #0x01 ; Set the FW bit (bit 0) + MCR p15, 0, r0, c1, c0, 1 ; Write Aux Ctrl register + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT disable_maintenance_broadcast + ; void disable_maintenance_broadcast(void) + ; Disable the broadcasting of cache & TLB maintenance operations +disable_maintenance_broadcast PROC + MRC p15, 0, r0, c1, c0, 1 ; Read Aux Ctrl register + BIC r0, r0, #0x01 ; Clear the FW bit (bit 0) + MCR p15, 0, r0, c1, c0, 1 ; Write Aux Ctrl register + + BX lr + ENDP + +; ------------------------------------------------------------ + + EXPORT secure_SCU_invalidate + ; void secure_SCU_invalidate(unsigned int cpu, unsigned int ways) + ; cpu: 0x0=CPU 0 0x1=CPU 1 etc... + ; This function invalidates the SCU copy of the tag rams + ; for the specified core. Typically only done at start-up. + ; Possible flow: + ; - Invalidate L1 caches + ; - Invalidate SCU copy of TAG RAMs + ; - Join SMP +secure_SCU_invalidate PROC + AND r0, r0, #0x03 ; Mask off unused bits of CPU ID + MOV r0, r0, LSL #2 ; Convert into bit offset (four bits per core) + + AND r1, r1, #0x0F ; Mask off unused bits of ways + MOV r1, r1, LSL r0 ; Shift ways into the correct CPU field + + MRC p15, 4, r2, c15, c0, 0 ; Read periph base address + + STR r1, [r2, #0x0C] ; Write to SCU Invalidate All in Secure State + + BX lr + + ENDP + +; ------------------------------------------------------------ +; End of code +; ------------------------------------------------------------ + + END + +; ------------------------------------------------------------ +; End of MP_SCU.s +; ------------------------------------------------------------ diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/demo_threadx.c b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/demo_threadx.c new file mode 100644 index 00000000..70f1c840 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/demo_threadx.c @@ -0,0 +1,444 @@ +/* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight + threads of different priorities, using a message queue, semaphore, mutex, event flags group, + byte pool, and block pool. */ + +#include "tx_api.h" + +#define DEMO_STACK_SIZE 1024 +#define DEMO_BYTE_POOL_SIZE 9120 +#define DEMO_BLOCK_POOL_SIZE 100 +#define DEMO_QUEUE_SIZE 100 + + +/* Define the ThreadX object control blocks... */ + +TX_THREAD thread_0; +TX_THREAD thread_1; +TX_THREAD thread_2; +TX_THREAD thread_3; +TX_THREAD thread_4; +TX_THREAD thread_5; +TX_THREAD thread_6; +TX_THREAD thread_7; +TX_TIMER timer_0; +TX_QUEUE queue_0; +TX_SEMAPHORE semaphore_0; +TX_MUTEX mutex_0; +TX_EVENT_FLAGS_GROUP event_flags_0; +TX_BYTE_POOL byte_pool_0; +TX_BLOCK_POOL block_pool_0; + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG thread_1_messages_sent; +ULONG thread_2_counter; +ULONG thread_2_messages_received; +ULONG thread_3_counter; +ULONG thread_4_counter; +ULONG thread_5_counter; +ULONG thread_6_counter; +ULONG thread_7_counter; + + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void thread_2_entry(ULONG thread_input); +void thread_3_and_4_entry(ULONG thread_input); +void thread_5_entry(ULONG thread_input); +void thread_6_and_7_entry(ULONG thread_input); + + +#ifdef TX_ENABLE_EVENT_TRACE + +UCHAR event_buffer[65536]; + +#endif + + + +int main(void) +{ + + /* Enter ThreadX. */ + tx_kernel_enter(); + + return 0; +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer; + + +#ifdef TX_ENABLE_EVENT_TRACE + + tx_trace_enable(event_buffer, sizeof(event_buffer), 32); +#endif + + /* Create a byte memory pool from which to allocate the thread stacks. */ + tx_byte_pool_create(&byte_pool_0, "byte pool 0", first_unused_memory, DEMO_BYTE_POOL_SIZE); + + /* Allocate the stack for thread 0. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 1. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 1 and 2. These threads pass information through a ThreadX + message queue. It is also interesting to note that these threads have a time + slice. */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 2. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 3. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore. + An interesting thing here is that both threads share the same instruction area. */ + tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 4. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 5. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create thread 5. This thread simply pends on an event flag which will be set + by thread_0. */ + tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 6. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 6 and 7. These threads compete for a ThreadX mutex. */ + tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 7. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the message queue. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT); + + /* Create the message queue shared by threads 1 and 2. */ + tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG)); + + /* Create the semaphore used by threads 3 and 4. */ + tx_semaphore_create(&semaphore_0, "semaphore 0", 1); + + /* Create the event flags group used by threads 1 and 5. */ + tx_event_flags_create(&event_flags_0, "event flags 0"); + + /* Create the mutex used by thread 6 and 7 without priority inheritance. */ + tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT); + + /* Allocate the memory for a small block pool. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT); + + /* Create a block memory pool to allocate a message buffer from. */ + tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE); + + /* Allocate a block and release the block memory. */ + tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT); + + /* Release the block back to the pool. */ + tx_block_release(pointer); +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sits in while-forever-sleep loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_0_counter++; + + /* Sleep for 10 ticks. */ + tx_thread_sleep(10); + + /* Set event flag 0 to wakeup thread 5. */ + status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sends messages to a queue shared by thread 2. */ + while(1) + { + + /* Increment the thread counter. */ + thread_1_counter++; + + /* Send message to queue 0. */ + status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER); + + /* Check completion status. */ + if (status != TX_SUCCESS) + break; + + /* Increment the message sent. */ + thread_1_messages_sent++; + } +} + + +void thread_2_entry(ULONG thread_input) +{ + +ULONG received_message; +UINT status; + + /* This thread retrieves messages placed on the queue by thread 1. */ + while(1) + { + + /* Increment the thread counter. */ + thread_2_counter++; + + /* Retrieve a message from the queue. */ + status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER); + + /* Check completion status and make sure the message is what we + expected. */ + if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received)) + break; + + /* Otherwise, all is okay. Increment the received message count. */ + thread_2_messages_received++; + } +} + + +void thread_3_and_4_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 3 and thread 4. As the loop + below shows, these function compete for ownership of semaphore_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 3) + thread_3_counter++; + else + thread_4_counter++; + + /* Get the semaphore with suspension. */ + status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the semaphore. */ + tx_thread_sleep(2); + + /* Release the semaphore. */ + status = tx_semaphore_put(&semaphore_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_5_entry(ULONG thread_input) +{ + +UINT status; +ULONG actual_flags; + + + /* This thread simply waits for an event in a forever loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_5_counter++; + + /* Wait for event flag 0. */ + status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR, + &actual_flags, TX_WAIT_FOREVER); + + /* Check status. */ + if ((status != TX_SUCCESS) || (actual_flags != 0x1)) + break; + } +} + + +void thread_6_and_7_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 6 and thread 7. As the loop + below shows, these function compete for ownership of mutex_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 6) + thread_6_counter++; + else + thread_7_counter++; + + /* Get the mutex with suspension. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Get the mutex again with suspension. This shows + that an owning thread may retrieve the mutex it + owns multiple times. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the mutex. */ + tx_thread_sleep(2); + + /* Release the mutex. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Release the mutex again. This will actually + release ownership since it was obtained twice. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +#if 0 +#include <stdio.h> + +#include "v7.h" +#include "MP_GIC.h" +#include "MP_Mutexes.h" + + +// compile-time control for the number of CPUs in the cluster +#define nCPUs 4 + +// per-thread space for each CPU for use by the Arm C libraries - will be zero-initialized on start-up +char user_perthread_libspace[ nCPUs ][96]; + + +// Called by the C library to get the address of the per-thread libspace +// Return a separate space for each CPU +void * __user_perthread_libspace(void) +{ + return user_perthread_libspace[ getCPUID() ]; +} + + +// Called by the C library to initialize the mutex to an unlocked state. +// Return a nonzero value to indicate to the C library that it is being used in a multithreaded environment. +int _mutex_initialize(mutex_t *m) +{ + initMutex(m); + return 1; +} + +// Called by the C library to obtain a lock on the mutex. +void _mutex_acquire(mutex_t *m) +{ + lockMutex(m); +} + +// Called by the C library to release the lock on the mutex previously acquired +void _mutex_release(mutex_t *m) +{ + unlockMutex(m); +} + + +/* +The C library startup routine __rt_entry() is called after scatterloading has been performed by __scatterload(). +__rt_entry() attempts a mutex lock call-out as part of its startup. To avoid possible lock-up in systems with +no global exclusive monitors in their memory system, rely on the local monitor provided within MPCore instead. +The local monitor becomes active when the L1 D cache is enabled. So the L1 cache should be enabled after +scatterloading has finished to avoid cache incoherency, but before __rt_entry() executes. This can be achieved +by using the 'wrapper' function which enables the caches then calls the original __rt_entry(). +*/ + +extern void $Super$$__rt_entry(void); + +void $Sub$$__rt_entry(void) +{ + enableBranchPrediction(); + enableCaches(); + + $Super$$__rt_entry(); +} +#endif diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/demo_threadx.ld b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/demo_threadx.ld new file mode 100644 index 00000000..c2add4f2 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/demo_threadx.ld @@ -0,0 +1,69 @@ +;LOAD 0x0000 0x00100000 +;{ +; STARTUP 0x0000 +; { +; startup.o(StartUp, +FIRST) +; * (InRoot$$Sections) ; Selects all sections that must be in a root region +; * (+RO) +; } +; +; SHARED_DATA +0x0 +; { +; * (+RW,+ZI) +; } +; +; IRQ_STACK 0x001FE000 EMPTY 0x1000 {} +; ARM_LIB_STACKHEAP 0x001FC000 EMPTY 0x2000 {} +;} +; +; +;PAGETABLES 0x00500000 0x00100000 +;{ +; PAGETABLES 0x00500000 EMPTY 0x00100000 +; { +; } +;} + +LOAD_ROOT 0x0 +{ + Root +0 0x10000 + { + startup.o (StartUp, +FIRST) ;startup code + * (InRoot$$Sections) ;All library sections that must be in a root region + + } +} +LOAD 0x48000000 +{ + INIT +0 0x10000 + { + demo_threadx.o (+RO) ; Place main() in a root region for the benefit of software breakpoints + } + + ; increased from 32k to 64k + CODE +0 0x10000 + { + * (+RO) ; Application code, including C library + } + + SHARED_DATA +0 0x4000 + { + * (+RW,+ZI) ; All RW and ZI Data + } + ; App heap for all CPUs + ARM_LIB_HEAP +0 ALIGN 8 EMPTY 0x2000 {} + + ; App stacks for all CPUs - see startup.S + ARM_LIB_STACK +0 ALIGN 8 EMPTY 4*0x1000 {} + + ; IRQ stacks for all CPUs - see startup.s + IRQ_STACK +0 ALIGN 8 EMPTY 4*256 {} + +} + +PAGETABLES 0x00500000 0x00100000 +{ + PAGETABLES 0x00500000 EMPTY 0x00100000 + { + } +} diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/retarget.c b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/retarget.c new file mode 100644 index 00000000..9d3c2cdc --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/retarget.c @@ -0,0 +1,11 @@ +// Copyright ARM Ltd 2009. All rights reserved. + +extern void $Super$$main(void); +extern void enable_caches(void); + +void $Sub$$main(void) +{ + enable_caches(); // enables caches + $Super$$main(); // calls original main() +} + diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/startup.S b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/startup.S new file mode 100644 index 00000000..58c39a90 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/startup.S @@ -0,0 +1,610 @@ +; ------------------------------------------------------------ +; Cortex-R8 MPCore SMP Prime Number Generator Example +; +; Copyright (c) 2011-2018 Arm Limited (or its affiliates). All rights reserved. +; Use, modification and redistribution of this file is subject to your possession of a +; valid End User License Agreement for the Arm Product of which these examples are part of +; and your compliance with all applicable terms and conditions of such licence agreement. +; ------------------------------------------------------------ + +; MPU region defines + + PRESERVE8 + + AREA StartUp,CODE,READONLY + + +; Region size <256 bytes is unpredictable + +Region_256B EQU 0x07 +Region_512B EQU 0x08 +Region_1K EQU 0x09 +Region_2K EQU 0x0a +Region_4K EQU 0x0b +Region_8K EQU 0x0c +Region_16K EQU 0x0d +Region_32K EQU 0x0e +Region_64K EQU 0x0f +Region_128K EQU 0x10 +Region_256K EQU 0x11 +Region_512K EQU 0x12 +Region_1M EQU 0x13 +Region_2M EQU 0x14 +Region_4M EQU 0x15 +Region_8M EQU 0x16 +Region_16M EQU 0x17 +Region_32M EQU 0x18 +Region_64M EQU 0x19 +Region_128M EQU 0x1a +Region_256M EQU 0x1b +Region_512M EQU 0x1c +Region_1G EQU 0x1d +Region_2G EQU 0x1e +Region_4G EQU 0x1f + +Region_Enable EQU 0x01 +Execute_Never EQU 0x1000 + +Normal_nShared EQU 0x03 ; Outer and Inner write-back, no write-allocate +Device_Shared EQU (0x0<<0x3 :OR: 0x1) +Device_nShared EQU 0x10 + +Full_Access EQU 0x03 +Read_Only EQU 0x06 + +Shared EQU 0x04 + + +; Standard definitions of mode bits and interrupt (I&F) flags in PSRs + +Mode_USR EQU 0x10 +Mode_FIQ EQU 0x11 +Mode_IRQ EQU 0x12 +Mode_SVC EQU 0x13 +Mode_ABT EQU 0x17 +Mode_UND EQU 0x1B +Mode_SYS EQU 0x1F + +I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled +F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled + + +; ------------------------------------------------------------ +; Porting defines +; ------------------------------------------------------------ + +L1_COHERENT EQU 0x00014c06 ; Template descriptor for coherent memory +L1_NONCOHERENT EQU 0x00000c1e ; Template descriptor for non-coherent memory +L1_DEVICE EQU 0x00000c16 ; Template descriptor for device memory + +; ------------------------------------------------------------ + + ENTRY + + EXPORT Vectors + +Vectors + B Reset_Handler + B Undefined_Handler + B SVC_Handler + B Prefetch_Handler + B Abort_Handler + B . ;Reserved vector + B IRQ_Handler + B FIQ_Handler + +; ------------------------------------------------------------ +; Handlers for unused exceptions +; ------------------------------------------------------------ + +Undefined_Handler + B Undefined_Handler +SVC_Handler + B SVC_Handler +Prefetch_Handler + B Prefetch_Handler +Abort_Handler + B Abort_Handler +FIQ_Handler + B FIQ_Handler + +; ------------------------------------------------------------ +; Imports +; ------------------------------------------------------------ + + IMPORT read_irq_ack + IMPORT write_end_of_irq + IMPORT enable_GIC + IMPORT enable_gic_processor_interface + IMPORT set_priority_mask + IMPORT enable_irq_id + IMPORT set_irq_priority + IMPORT enable_scu + IMPORT join_smp + IMPORT secure_SCU_invalidate + IMPORT enable_maintenance_broadcast + IMPORT init_private_timer + IMPORT start_private_timer + IMPORT clear_private_timer_irq + IMPORT __main + + IMPORT __use_two_region_memory + IMPORT ||Image$$IRQ_STACK$$ZI$$Limit|| + +; [EL Change Start] + IMPORT _tx_thread_smp_initialize_wait + IMPORT _tx_thread_smp_release_cores_flag + IMPORT _tx_thread_context_save + IMPORT _tx_thread_context_restore + IMPORT _tx_timer_interrupt + IMPORT _tx_thread_smp_inter_core_interrupts +; [EL Change End] + + +; ------------------------------------------------------------ +; Interrupt Handler +; ------------------------------------------------------------ + + EXPORT IRQ_Handler + EXPORT __tx_irq_processing_return +IRQ_Handler PROC +; [EL Change Start] +; SUB lr, lr, #4 ; Pre-adjust lr +; SRSFD sp!, #Mode_IRQ ; Save lr and SPRS to IRQ mode stack +; PUSH {r0-r4, r12} ; Sace APCS corruptable registers to IRQ mode stack (and maintain 8 byte alignment) +; +; /* Jump to context save to save system context. */ + B _tx_thread_context_save +__tx_irq_processing_return + PUSH {r4, r5} ; Save some preserved registers (r5 is saved just for 8-byte alignment) +; [EL Change End] + + ; Acknowledge the interrupt + BL read_irq_ack + MOV r4, r0 + + ; + ; This example only uses (and enables) one. At this point + ; you would normally check the ID, and clear the source. + ; + + ; + ; Additonal code to handler private timer interrupt on CPU0 + ; + + CMP r0, #29 ; If not Private Timer interrupt (ID 29), by pass + BNE by_pass + +; [EL Change Start] +; MOV r0, #0x04 ; Code for SYS_WRITE0 +; LDR r1, =irq_handler_message0 +; SVC 0x123456 +; [EL Change End] + + ; Clear timer interrupt + BL clear_private_timer_irq + DSB +; [EL Change Start] + BL _tx_timer_interrupt ; Timer interrupt handler +; [EL Change End] + + B by_pass2 + +by_pass + +; [EL Change Start] + ; + ; Additional code to handle SGI on CPU0 + ; +; +; MRC p15, 0, r0, c0, c0, 5 ; Read CPU ID register +; ANDS r0, r0, #0x03 ; Mask off, leaving the CPU ID field +; BNE by_pass2 +; +; MOV r0, #0x04 ; Code for SYS_WRITE0 +; LDR r1, =irq_handler_message1 +; SVC 0x123456 +; +; /* Just increment the per-thread interrupt count for analysis purposes. */ +; + MRC p15, 0, r0, c0, c0, 5 ; Read CPU ID register + AND r0, r0, #0x03 ; Mask off, leaving the CPU ID field + LSL r0, r0, #2 ; Build offset to array indexes + LDR r1,=_tx_thread_smp_inter_core_interrupts ; Pickup base address of core interrupt counter array + ADD r1, r1, r0 ; Build array index + LDR r0, [r1] ; Pickup counter + ADD r0, r0, #1 ; Increment counter + STR r0, [r1] ; Store back counter +; +; [EL Change End] + + +by_pass2 + ; Write end of interrupt reg + MOV r0, r4 + BL write_end_of_irq + +; [EL Change Start] + +; +; /* Jump to context restore to restore system context. */ + POP {r4, r5} ; Recover preserved registers + B _tx_thread_context_restore + +; POP {r0-r4, r12} ; Restore stacked APCS registers +; MOV r2, #0x01 ; Set r2 so CPU leaves holding pen +; RFEFD sp! ; Return from exception +; [EL Change End] + + ENDP + + +; ------------------------------------------------------------ +; Reset Handler - Generic initialization, run by all CPUs +; ------------------------------------------------------------ + + IMPORT ||Image$$IRQ_STACK$$ZI$$Limit|| + IMPORT ||Image$$ARM_LIB_STACK$$ZI$$Limit|| + IMPORT enable_branch_prediction + IMPORT invalidate_caches + + EXPORT Reset_Handler ; Exported for callgraph purposes! +Reset_Handler PROC + +;---------------------------------------------------------------- +; Disable MPU and caches +;---------------------------------------------------------------- + +; Disable MPU and cache in case it was left enabled from an earlier run +; This does not need to be done from a cold reset + + MRC p15, 0, r0, c1, c0, 0 ; Read System Control Register + BIC r0, r0, #0x05 ; Disable MPU (M bit) and data cache (C bit) + BIC r0, r0, #0x800 ; Disable branch prediction (Z bit) + BIC r0, r0, #0x1000 ; Disable instruction cache (I bit) + DSB ; Ensure all previous loads/stores have completed + MCR p15, 0, r0, c1, c0, 0 ; Write System Control Register + ISB ; Ensure subsequent insts execute wrt new MPU settings + +; [EL Change Start] + ; + ; Setup stacks + ;--------------- +;; MSR CPSR_c, #Mode_IRQ :OR: I_Bit :OR: F_Bit +;; LDR sp, =||Image$$IRQ_STACK$$ZI$$Limit|| +; +;; MSR CPSR_c, #Mode_SYS :OR: I_Bit :OR :F_Bit ; No interrupts +;; LDR sp, =||Image$$ARM_LIB_STACK$$ZI$$Limit|| + + MSR CPSR_c, #Mode_IRQ :OR: I_Bit :OR: F_Bit + LDR sp, =||Image$$IRQ_STACK$$ZI$$Limit|| + + MSR CPSR_c, #Mode_SVC :OR: I_Bit :OR: F_Bit ; No interrupts + LDR sp, =||Image$$ARM_LIB_STACK$$ZI$$Limit|| + + MRC p15, 0, r1, c0, c0, 5 ; Read Multiprocessor Affinity Register + ANDS r1, r1, #0x03 ; Mask off, leaving the CPU ID field + CMP r1,#0 ; Is it core 0? + BEQ _stacks_setup ; +_core_1 + MSR CPSR_c, #Mode_IRQ :OR: I_Bit :OR: F_Bit + MOV r1, #0x800 + SUB sp, sp, r1 + + MSR CPSR_c, #Mode_SVC :OR: I_Bit :OR: F_Bit ; No interrupts + MOV r1, #0x1000 + SUB sp, sp, r1 +_stacks_setup +; [EL Change End] + + ; + ; Invalidate caches + ; ------------------ + BL invalidate_caches + + + ; Clear Branch Prediction Array + ; ------------------------------ + MOV r0, #0x0 + MCR p15, 0, r0, c7, c5, 6 ; BPIALL - Invalidate entire branch predictor array + + + ; + ; Activate VFP/NEON, if required + ;------------------------------- + + IF {TARGET_FPU_VFP} = {TRUE} + + ; Enable access to NEON/VFP by enabling access to Coprocessors 10 and 11. + ; Enables Full Access i.e. in both privileged and non privileged modes + MRC p15, 0, r0, c1, c0, 2 ; Read Coprocessor Access Control Register (CPACR) + ORR r0, r0, #(0xF << 20) ; Enable access to CP 10 & 11 + MCR p15, 0, r0, c1, c0, 2 ; Write Coprocessor Access Control Register (CPACR) + ISB + + ; Switch on the VFP and NEON hardware + MOV r0, #0x40000000 + VMSR FPEXC, r0 ; Write FPEXC register, EN bit set + + ENDIF + +; [EL Change Start] - we don't use the MPU + ;BL configMPU +; [EL Change End] + + ; + ; SMP initialization + ; ------------------- + MRC p15, 0, r0, c0, c0, 5 ; Read CPU ID register + ANDS r0, r0, #0x03 ; Mask off, leaving the CPU ID field + BEQ primaryCPUInit + BNE secondaryCPUsInit + + ENDP + + +;---------------------------------------------------------------- +; MPU Configuration +;---------------------------------------------------------------- + + ; Notes: + ; * Regions apply to both instruction and data accesses. + ; * Each region base address must be a multiple of its size + ; * Any address range not covered by an enabled region will abort + ; * The region at 0x0 over the Vector table is needed to support semihosting + + ; Region 0: Init Base = 0x48000000 Size = 64KB Normal Non-shared Full access Executable + ; Region 1: Code Base = 0x48010000 Size = 32KB Normal Non-shared Full access Executable + ; Region 1: Data Base = 0x48018000 Size = 16KB Normal Non-shared Full access Not Executable + ; Region 2: Stack/Heap Base = 0x4801C000 Size = 8KB Normal Non-shared Full access Not Executable + ; Region 4: Vectors Base = 0x0000 Size = 64KB Normal Nonshared Full access Executable + ; Region 5: GIC Base = 0xAE000000 Size = 8KB Device shared Full access Not Executable + + EXPORT +configMPU PROC + + MRC p15, 0, r0, c0, c0, 5 ; Read CPU ID register + ANDS r0, r0, #0x03 ; Mask off, leaving the CPU ID field + ; Import linker symbols to get region base addresses + IMPORT ||Image$$INIT$$Base|| + IMPORT ||Image$$CODE$$Base|| + IMPORT ||Image$$SHARED_DATA$$Base|| + IMPORT ||Image$$ARM_LIB_STACK$$Base|| + + ;; Region 0 - Init + MOV r1, #0 + MCR p15, 0, r1, c6, c2, 0 ; Set memory region number register + ISB ; Ensure subsequent insts execute wrt this region + LDR r2, =||Image$$INIT$$Base|| + MCR p15, 0, r2, c6, c1, 0 ; Set region base address register + LDR r2, =0x0 :OR: (Region_64K << 1) :OR: Region_Enable + MCR p15, 0, r2, c6, c1, 2 ; Set region size & enable register + LDR r2, =0x0 :OR: (Full_Access << 8) :OR: Normal_nShared + MCR p15, 0, r2, c6, c1, 4 ; Set region access control register + + ; Region 1 - Code + ADD r1, r1, #1 + MCR p15, 0, r1, c6, c2, 0 ; Set memory region number register + ISB ; Ensure subsequent insts execute wrt this region + LDR r2, =||Image$$CODE$$Base|| + MCR p15, 0, r2, c6, c1, 0 ; Set region base address register + LDR r2, =0x0 :OR: (Region_64K << 1) :OR: Region_Enable + MCR p15, 0, r2, c6, c1, 2 ; Set region size & enable register + LDR r2, =0x0 :OR: (Full_Access << 8) :OR: Normal_nShared + MCR p15, 0, r2, c6, c1, 4 ; Set region access control register + + ; Region 2 - Data + ADD r1, r1, #1 + MCR p15, 0, r1, c6, c2, 0 ; Set memory region number register + ISB ; Ensure subsequent insts execute wrt this region + LDR r2, =||Image$$SHARED_DATA$$Base|| + MCR p15, 0, r2, c6, c1, 0 ; Set region base address register + LDR r2, =0x0 :OR: (Region_16K << 1) :OR: Region_Enable + MCR p15, 0, r2, c6, c1, 2 ; Set region size & enable register + LDR r2, =0x0 :OR: (Full_Access << 8) :OR: Normal_nShared :OR: Execute_Never + MCR p15, 0, r2, c6, c1, 4 ; Set region access control register + + ; Region 3 - Stack/heap + ADD r1, r1, #1 + MCR p15, 0, r1, c6, c2, 0 ; Set memory region number register + ISB ; Ensure subsequent insts execute wrt this region + LDR r2, =||Image$$ARM_LIB_STACK$$Base|| + MCR p15, 0, r2, c6, c1, 0 ; Set region base address register + LDR r2, =0x0 :OR: (Region_16K << 1) :OR: Region_Enable + MCR p15, 0, r2, c6, c1, 2 ; Set region size & enable register + LDR r2, =0x0 :OR: (Full_Access << 8) :OR: Normal_nShared :OR: Execute_Never + MCR p15, 0, r2, c6, c1, 4 ; Set region access control register + + ; Region 4 - Vectors + ADD r1, r1, #1 + MCR p15, 0, r1, c6, c2, 0 ; Set memory region number register + ISB ; Ensure subsequent insts execute wrt this region + LDR r2, =0 + MCR p15, 0, r2, c6, c1, 0 ; Set region base address register + LDR r2, =0x0 :OR: (Region_64K << 1) :OR: Region_Enable + MCR p15, 0, r2, c6, c1, 2 ; Set region size & enable register + LDR r2, =0x0 :OR: (Full_Access << 8) :OR:Normal_nShared :OR: Shared + MCR p15, 0, r2, c6, c1, 4 ; Set region access control register + + ; Region 5 - GIC + ADD r1, r1, #1 + MCR p15, 0, r1, c6, c2, 0 ; Set memory region number register + ISB ; Ensure subsequent insts execute wrt this region + LDR r2, =0xAE000000 + MCR p15, 0, r2, c6, c1, 0 ; Set region base address register + LDR r2, =0x0 :OR: (Region_8K << 1):OR: Region_Enable + MCR p15, 0, r2, c6, c1, 2 ; Set region size & enable register + LDR r2, =0x0 :OR: (Full_Access << 8) :OR: Device_Shared :OR: Execute_Never + MCR p15, 0, r2, c6, c1, 4 ; Set region access control register + + + ; Disable all higher priority regions (assumes unified regions, which is always true for Cortex-R8) + MRC p15, 0, r0, c0, c0, 4 ; Read MPU Type register (MPUIR) + LSR r0, r0, #8 + AND r0, r0, #0xff ; r0 = Number of MPU regions (12, 16, 20, or 24 for Cortex-R8) + MOV r2, #0 ; Value to write to disable region +region_loop + ADD r1, r1, #1 + CMP r0, r1 + BLS regions_done + MCR p15, 0, r1, c6, c2, 0 ; Set memory region number register (RGNR) + MCR p15, 0, r2, c6, c1, 2 ; Set region size & enable register (DRSR) + B region_loop +regions_done + BX lr + + ENDP + +; ------------------------------------------------------------ +; Initialization for PRIMARY CPU +; ------------------------------------------------------------ + + EXPORT primaryCPUInit +primaryCPUInit PROC + + ; Enable the SCU + ; --------------- + BL enable_scu + + ; + ; Join SMP + ; --------- + MOV r0, #0x0 ; Move CPU ID into r0 + MOV r1, #0xF ; Move 0xF (represents all four ways) into r1 + BL join_smp + + ; + ; GIC Init + ; --------- + BL enable_GIC + BL enable_gic_processor_interface + +; [EL Change Start] +; /* Leave MPU disabled */ +; ; Enable MPU +; ; ----------- +; ; Leave the caches disabled until after scatter loading. +; MRC p15, 0, r0, c1, c0, 0 ; Read System Control Register +; ORR r0, r0, #0x1 ; Set M bit 0 to enable MMU before scatter loading +; MCR p15, 0, r0, c1, c0, 0 ; Write System Control Register + + ; + ; Enable Private Timer for periodic IRQ + ; -------------------------------------- + MOV r0, #0x1F + BL set_priority_mask ; Set priority mask (local) + + ; [EL] Change start - don't enable interrupts here! + ;CPSIE i ; Clear CPSR I bit + ; [EL] Change end + + ; Enable the Private Timer Interrupt Source + MOV r0, #29 + MOV r1, #0 + BL enable_irq_id + + ; Set the priority + MOV r0, #29 + MOV r1, #0 + BL set_irq_priority + + ; Configure Timer + MOV r0, #0xF0000 + MOV r1, #0x0 + BL init_private_timer + BL start_private_timer + + ; + ; Enable receipt of SGI 0 + ; ------------------------ + MOV r0, #0x0 ; ID + BL enable_irq_id + + MOV r0, #0x0 ; ID + MOV r1, #0x0 ; Priority + BL set_irq_priority +; [EL Change End] + + ; + ; Branch to C lib code + ; ---------------------- + B __main + + ENDP + + + +; ------------------------------------------------------------ +; Initialization for SECONDARY CPUs +; ------------------------------------------------------------ + + EXPORT secondaryCPUsInit +secondaryCPUsInit PROC + +; [EL Change Start] - Don't configure MPU + ;BL configMPU +; [EL Change End] + + ; + ; GIC Init + ; --------- + BL enable_gic_processor_interface + + MOV r0, #0x1F ; Priority + BL set_priority_mask + + MOV r0, #0x0 ; ID + BL enable_irq_id + + MOV r0, #0x0 ; ID + MOV r1, #0x0 ; Priority + BL set_irq_priority + + ; + ; Join SMP + ; --------- + MRC p15, 0, r0, c0, c0, 5 ; Read CPU ID register + ANDS r0, r0, #0x03 ; Mask off, leaving the CPU ID field + MOV r1, #0xF ; Move 0xF (represents all four ways) into r1 + BL secure_SCU_invalidate + + BL join_smp + BL enable_maintenance_broadcast + +; [EL Change Start] +; /* Leave MPU disabled */ +; ; Enable MPU +; ; ----------- +; ; Leave the caches disabled until after scatter loading. +; MRC p15, 0, r0, c1, c0, 0 ; Read System Control Register +; ORR r0, r0, #0x1 ; Set M bit 0 to enable MMU before scatter loading +; MCR p15, 0, r0, c1, c0, 0 ; Write System Control Register +; ISB + + ; + ; Holding Pen + ; ------------ +; MOV r2, #0x00 ; Clear r2 +; CPSIE i ; Enable interrupts +;holding_pen +; CMP r2, #0x0 ; r2 will be set to 0x1 by IRQ handler on receiving SGI +; WFIEQ +; BEQ holding_pen +; CPSID i ; IRQs not used in reset of example, so mask out interrupts +;skip +; + ; + ; Branch to C lib code + ; ---------------------- +; B __main + + B _tx_thread_smp_initialize_wait +; [EL Change End] + + ENDP + + END + +; ------------------------------------------------------------ +; End of startup.s +; ------------------------------------------------------------ diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/v7.S b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/v7.S new file mode 100644 index 00000000..dfd65a2c --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/v7.S @@ -0,0 +1,381 @@ +; ------------------------------------------------------------ +; v7 Cache and Branch Prediction Maintenance Operations +; ------------------------------------------------------------ + + PRESERVE8 + + AREA v7CacheOpp,CODE,READONLY + +; ------------------------------------------------------------ +; Cache Maintenance +; ------------------------------------------------------------ + + EXPORT enable_caches + ; void enable_caches(void); +enable_caches PROC + MRC p15, 0, r0, c1, c0, 0 ; Read System Control Register configuration data + ORR r0, r0, #(1 << 2) ; Set C bit + ORR r0, r0, #(1 << 12) ; Set I bit + MCR p15, 0, r0, c1, c0, 0 ; Write System Control Register configuration data + BX lr + ENDP + + + EXPORT disable_caches + ; void disable_caches(void) +disable_caches PROC + MRC p15, 0, r0, c1, c0, 0 ; Read System Control Register configuration data + BIC r0, r0, #(1 << 2) ; Clear C bit + BIC r0, r0, #(1 << 12) ; Clear I bit + MCR p15, 0, r0, c1, c0, 0 ; Write System Control Register configuration data + BX lr + ENDP + + + EXPORT clean_dcache + ; void clean_dcache(void); +clean_dcache PROC + PUSH {r4-r12} + + ; + ; Based on code example given in section 11.2.4 of ARM DDI 0406B + ; + + MRC p15, 1, r0, c0, c0, 1 ; Read CLIDR + ANDS r3, r0, #&7000000 + MOV r3, r3, LSR #23 ; Cache level value (naturally aligned) + BEQ clean_dcache_finished + MOV r10, #0 + +clean_dcache_loop1 + ADD r2, r10, r10, LSR #1 ; Work out 3xcachelevel + MOV r1, r0, LSR r2 ; bottom 3 bits are the Cache type for this level + AND r1, r1, #7 ; get those 3 bits alone + CMP r1, #2 + BLT clean_dcache_skip ; no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 ; write the Cache Size selection register + ISB ; ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 ; reads current Cache Size ID register + AND r2, r1, #&7 ; extract the line length field + ADD r2, r2, #4 ; add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 ; R4 is the max number on the way size (right aligned) + CLZ r5, r4 ; R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 ; R7 is the max number of the index size (right aligned) + +clean_dcache_loop2 + MOV r9, R4 ; R9 working copy of the max way size (right aligned) + +clean_dcache_loop3 + ORR r11, r10, r9, LSL r5 ; factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 ; factor in the index number + MCR p15, 0, r11, c7, c10, 2 ; DCCSW - clean by set/way + SUBS r9, r9, #1 ; decrement the way number + BGE clean_dcache_loop3 + SUBS r7, r7, #1 ; decrement the index + BGE clean_dcache_loop2 + +clean_dcache_skip + ADD r10, r10, #2 ; increment the cache number + CMP r3, r10 + BGT clean_dcache_loop1 + +clean_dcache_finished + POP {r4-r12} + + BX lr + ENDP + + EXPORT clean_invalidate_dcache + ; void clean_invalidate_dcache(void); +clean_invalidate_dcache PROC + PUSH {r4-r12} + + ; + ; Based on code example given in section 11.2.4 of ARM DDI 0406B + ; + + MRC p15, 1, r0, c0, c0, 1 ; Read CLIDR + ANDS r3, r0, #&7000000 + MOV r3, r3, LSR #23 ; Cache level value (naturally aligned) + BEQ clean_invalidate_dcache_finished + MOV r10, #0 + +clean_invalidate_dcache_loop1 + ADD r2, r10, r10, LSR #1 ; Work out 3xcachelevel + MOV r1, r0, LSR r2 ; bottom 3 bits are the Cache type for this level + AND r1, r1, #7 ; get those 3 bits alone + CMP r1, #2 + BLT clean_invalidate_dcache_skip ; no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 ; write the Cache Size selection register + ISB ; ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 ; reads current Cache Size ID register + AND r2, r1, #&7 ; extract the line length field + ADD r2, r2, #4 ; add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 ; R4 is the max number on the way size (right aligned) + CLZ r5, r4 ; R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 ; R7 is the max number of the index size (right aligned) + +clean_invalidate_dcache_loop2 + MOV r9, R4 ; R9 working copy of the max way size (right aligned) + +clean_invalidate_dcache_loop3 + ORR r11, r10, r9, LSL r5 ; factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 ; factor in the index number + MCR p15, 0, r11, c7, c14, 2 ; DCCISW - clean and invalidate by set/way + SUBS r9, r9, #1 ; decrement the way number + BGE clean_invalidate_dcache_loop3 + SUBS r7, r7, #1 ; decrement the index + BGE clean_invalidate_dcache_loop2 + +clean_invalidate_dcache_skip + ADD r10, r10, #2 ; increment the cache number + CMP r3, r10 + BGT clean_invalidate_dcache_loop1 + +clean_invalidate_dcache_finished + POP {r4-r12} + + BX lr + ENDP + + + EXPORT invalidate_caches + ; void invalidate_caches(void); +invalidate_caches PROC + PUSH {r4-r12} + + ; + ; Based on code example given in section B2.2.4/11.2.4 of ARM DDI 0406B + ; + + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 0 ; ICIALLU - Invalidate entire I Cache, and flushes branch target cache + + MRC p15, 1, r0, c0, c0, 1 ; Read CLIDR + ANDS r3, r0, #&7000000 + MOV r3, r3, LSR #23 ; Cache level value (naturally aligned) + BEQ invalidate_caches_finished + MOV r10, #0 + +invalidate_caches_loop1 + ADD r2, r10, r10, LSR #1 ; Work out 3xcachelevel + MOV r1, r0, LSR r2 ; bottom 3 bits are the Cache type for this level + AND r1, r1, #7 ; get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_skip ; no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 ; write the Cache Size selection register + ISB ; ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 ; reads current Cache Size ID register + AND r2, r1, #&7 ; extract the line length field + ADD r2, r2, #4 ; add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 ; R4 is the max number on the way size (right aligned) + CLZ r5, r4 ; R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 ; R7 is the max number of the index size (right aligned) + +invalidate_caches_loop2 + MOV r9, R4 ; R9 working copy of the max way size (right aligned) + +invalidate_caches_loop3 + ORR r11, r10, r9, LSL r5 ; factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 ; factor in the index number + MCR p15, 0, r11, c7, c6, 2 ; DCISW - invalidate by set/way + SUBS r9, r9, #1 ; decrement the way number + BGE invalidate_caches_loop3 + SUBS r7, r7, #1 ; decrement the index + BGE invalidate_caches_loop2 + +invalidate_caches_skip + ADD r10, r10, #2 ; increment the cache number + CMP r3, r10 + BGT invalidate_caches_loop1 + +invalidate_caches_finished + POP {r4-r12} + BX lr + ENDP + + + EXPORT invalidate_caches_is + ; void invalidate_caches_is(void); +invalidate_caches_is PROC + PUSH {r4-r12} + + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 0 ; ICIALLUIS - Invalidate entire I Cache inner shareable + + MRC p15, 1, r0, c0, c0, 1 ; Read CLIDR + ANDS r3, r0, #&7000000 + MOV r3, r3, LSR #23 ; Cache level value (naturally aligned) + BEQ invalidate_caches_is_finished + MOV r10, #0 + +invalidate_caches_is_loop1 + ADD r2, r10, r10, LSR #1 ; Work out 3xcachelevel + MOV r1, r0, LSR r2 ; bottom 3 bits are the Cache type for this level + AND r1, r1, #7 ; get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_is_skip ; no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 ; write the Cache Size selection register + ISB ; ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 ; reads current Cache Size ID register + AND r2, r1, #&7 ; extract the line length field + ADD r2, r2, #4 ; add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 ; R4 is the max number on the way size (right aligned) + CLZ r5, r4 ; R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 ; R7 is the max number of the index size (right aligned) + +invalidate_caches_is_loop2 + MOV r9, R4 ; R9 working copy of the max way size (right aligned) + +invalidate_caches_is_loop3 + ORR r11, r10, r9, LSL r5 ; factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 ; factor in the index number + MCR p15, 0, r11, c7, c6, 2 ; DCISW - clean by set/way + SUBS r9, r9, #1 ; decrement the way number + BGE invalidate_caches_is_loop3 + SUBS r7, r7, #1 ; decrement the index + BGE invalidate_caches_is_loop2 + +invalidate_caches_is_skip + ADD r10, r10, #2 ; increment the cache number + CMP r3, r10 + BGT invalidate_caches_is_loop1 + +invalidate_caches_is_finished + POP {r4-r12} + BX lr + ENDP + +; ------------------------------------------------------------ +; TLB +; ------------------------------------------------------------ + + EXPORT invalidate_unified_tlb + ; void invalidate_unified_tlb(void); +invalidate_unified_tlb PROC + MOV r0, #1 + MCR p15, 0, r0, c8, c7, 0 ; TLBIALL - Invalidate entire unified TLB + BX lr + ENDP + + EXPORT invalidate_unified_tlb_is + ; void invalidate_unified_tlb_is(void); +invalidate_unified_tlb_is PROC + MOV r0, #1 + MCR p15, 0, r0, c8, c3, 0 ; TLBIALLIS - Invalidate entire unified TLB Inner Shareable + BX lr + ENDP + +; ------------------------------------------------------------ +; Branch Prediction +; ------------------------------------------------------------ + + EXPORT enable_branch_prediction + ; void enable_branch_prediction(void) +enable_branch_prediction PROC + MRC p15, 0, r0, c1, c0, 0 ; Read SCTLR + ORR r0, r0, #(1 << 11) ; Set the Z bit (bit 11) + MCR p15, 0,r0, c1, c0, 0 ; Write SCTLR + BX lr + ENDP + + EXPORT disable_branch_prediction + ; void disable_branch_prediction(void) +disable_branch_prediction PROC + MRC p15, 0, r0, c1, c0, 0 ; Read SCTLR + BIC r0, r0, #(1 << 11) ; Clear the Z bit (bit 11) + MCR p15, 0,r0, c1, c0, 0 ; Write SCTLR + BX lr + ENDP + + EXPORT invalidate_branch_target_cache + ; void invalidate_branch_target_cache(void) +invalidate_branch_target_cache PROC + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 6 ; BPIALL - Invalidate entire branch predictor array + BX lr + ENDP + + EXPORT invalidate_branch_target_cache_is + ; void invalidate_branch_target_cache_is(void) +invalidate_branch_target_cache_is PROC + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 6 ; BPIALLIS - Invalidate entire branch predictor array Inner Shareable + BX lr + ENDP + +; ------------------------------------------------------------ +; High Vecs +; ------------------------------------------------------------ + + EXPORT enable_highvecs + ; void enable_highvecs(void); +enable_highvecs PROC + MRC p15, 0, r0, c1, c0, 0 ; Read Control Register + ORR r0, r0, #(1 << 13) ; Set the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 ; Write Control Register + BX lr + ENDP + + EXPORT disable_highvecs + ; void disable_highvecs(void); +disable_highvecs PROC + MRC p15, 0, r0, c1, c0, 0 ; Read Control Register + BIC r0, r0, #(1 << 13) ; Clear the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 ; Write Control Register + BX lr + ENDP + +; ------------------------------------------------------------ +; Context ID +; ------------------------------------------------------------ + + EXPORT get_context_id + ; uint32_t get_context_id(void); +get_context_id PROC + MRC p15, 0, r0, c13, c0, 1 ; Read Context ID Register + BX lr + ENDP + + EXPORT set_context_id + ; void set_context_id(uint32_t); +set_context_id PROC + MCR p15, 0, r0, c13, c0, 1 ; Write Context ID Register + BX lr + ENDP + +; ------------------------------------------------------------ +; ID registers +; ------------------------------------------------------------ + + EXPORT get_MIDR + ; uint32_t get_MIDR(void); +get_MIDR PROC + MRC p15, 0, r0, c0, c0, 0 ; Read Main ID Register (MIDR) + BX lr + ENDP + + EXPORT get_MPIDR + ; uint32_t get_MPIDR(void); +get_MPIDR PROC + MRC p15, 0, r0, c0 ,c0, 5; Read Multiprocessor ID register (MPIDR) + BX lr + ENDP + +; ------------------------------------------------------------ +; End of code +; ------------------------------------------------------------ + + END + +; ------------------------------------------------------------ +; End of v7.s +; ------------------------------------------------------------ diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/v7.h b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/v7.h new file mode 100644 index 00000000..52a3c679 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/sample_threadx/v7.h @@ -0,0 +1,117 @@ +// ------------------------------------------------------------ +// v7-A Cache, TLB and Branch Prediction Maintenance Operations +// Header File +// +// Copyright ARM Ltd 2009. All rights reserved. +// ------------------------------------------------------------ + +#ifndef _SEE_V7_h +#define _SEE_V7_h + +#include "kernel.h" + +// +// Note: +// *_is() stands for "inner shareable" +// + +// ------------------------------------------------------------ +// Caches + +void enable_caches(void); +void disable_caches(void); + +void clean_dcache(void); +void clean_invalidate_dcache(void); + +void invalidate_caches(void); +void invalidate_caches_is(void); + +// ------------------------------------------------------------ +// TLBs + +void invalidate_unified_tlb(void); +void invalidate_unified_tlb_is(void); + +// ------------------------------------------------------------ +// Branch prediction + +void enable_branch_prediction(void); +void disable_branch_prediction(void); + +void invalidate_branch_target_cache(void); +void invalidate_branch_target_cache_is(void); + +// ------------------------------------------------------------ +// High Vecs + +void enable_highvecs(void); +void disable_highvecs(void); + +// ------------------------------------------------------------ +// ID Registers + +uint32_t get_MIDR(void); + +#define MIDR_IMPL_SHIFT 24 +#define MIDR_IMPL_MASK 0xFF +#define MIDR_VAR_SHIFT 20 +#define MIDR_VAR_MASK 0xF +#define MIDR_ARCH_SHIFT 16 +#define MIDR_ARCH_MASK 0xF +#define MIDR_PART_SHIFT 4 +#define MIDR_PART_MASK 0xFFF +#define MIDR_REV_SHIFT 0 +#define MIDR_REV_MASK 0xF + +// tmp = get_MIDR(); +// implementor = (tmp >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; +// variant = (tmp >> MIDR_VAR_SHIFT) & MIDR_VAR_MASK; +// architecture= (tmp >> MIDR_ARCH_SHIFT) & MIDR_ARCH_MASK; +// part_number = (tmp >> MIDR_PART_SHIFT) & MIDR_PART_MASK; +// revision = tmp & MIDR_REV_MASK; + +#define MIDR_PART_CA5 0xC05 +#define MIDR_PART_CA8 0xC08 +#define MIDR_PART_CA9 0xC09 + +uint32_t get_MPIDR(void); + +#define MPIDR_FORMAT_SHIFT 31 +#define MPIDR_FORMAT_MASK 0x1 +#define MPIDR_UBIT_SHIFT 30 +#define MPIDR_UBIT_MASK 0x1 +#define MPIDR_CLUSTER_SHIFT 7 +#define MPIDR_CLUSTER_MASK 0xF +#define MPIDR_CPUID_SHIFT 0 +#define MPIDR_CPUID_MASK 0x3 + +#define MPIDR_CPUID_CPU0 0x0 +#define MPIDR_CPUID_CPU1 0x1 +#define MPIDR_CPUID_CPU2 0x2 +#define MPIDR_CPUID_CPU3 0x3 + +#define MPIDR_UNIPROCESSPR 0x1 + +#define MPDIR_NEW_FORMAT 0x1 + +// ------------------------------------------------------------ +// Context ID + +uint32_t get_context_id(void); +void set_context_id(uint32_t); + +#define CONTEXTID_ASID_SHIFT 0 +#define CONTEXTID_ASID_MASK 0xFF +#define CONTEXTID_PROCID_SHIFT 8 +#define CONTEXTID_PROCID_MASK 0x00FFFFFF + +// tmp = get_context_id(); +// ASID = tmp & CONTEXTID_ASID_MASK; +// PROCID = (tmp >> CONTEXTID_PROCID_SHIFT) & CONTEXTID_PROCID_MASK; + +#endif + +// ------------------------------------------------------------ +// End of v7.h +// ------------------------------------------------------------ diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/tx/.cproject b/ports_smp/cortex_r8_smp/ac5/example_build/tx/.cproject new file mode 100644 index 00000000..5aaf33a1 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/tx/.cproject @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage"> + <storageModule moduleId="org.eclipse.cdt.core.settings"> + <cconfiguration id="com.arm.eclipse.build.config.v6.lib.debug.base.1507005551"> + <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.arm.eclipse.build.config.v6.lib.debug.base.1507005551" moduleId="org.eclipse.cdt.core.settings" name="Debug"> + <externalSettings/> + <extensions> + <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="com.arm.eclipse.builder.armcc.error" point="org.eclipse.cdt.core.ErrorParser"/> + </extensions> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <configuration artifactExtension="a" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.staticLib" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.staticLib,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="clean" description="" id="com.arm.eclipse.build.config.v6.lib.debug.base.1507005551" name="Debug" parent="com.arm.eclipse.build.config.v6.lib.debug.base"> + <folderInfo id="com.arm.eclipse.build.config.v6.lib.debug.base.1507005551." name="/" resourcePath=""> + <toolChain id="com.arm.toolchain.baremetal.169423023" name="Arm Compiler 5 (DS-5 built-in)" superClass="com.arm.toolchain.baremetal"> + <option id="com.arm.toolchain.ac5.option.target.cpu_fpu.626869623" superClass="com.arm.toolchain.ac5.option.target.cpu_fpu" useByScannerDiscovery="false" value="Cortex-R8.VFPv3_D16_FP16" valueType="string"/> + <option id="com.arm.toolchain.ac5.option.fppcs.792119847" name="Floating-point PCS" superClass="com.arm.toolchain.ac5.option.fppcs" useByScannerDiscovery="false" value="com.arm.tool.c.compiler.option.fppcs.hard" valueType="enumerated"/> + <option id="com.arm.toolchain.ac5.option.inst.503868103" name="Instruction set" superClass="com.arm.toolchain.ac5.option.inst" useByScannerDiscovery="false" value="com.arm.tool.c.compiler.option.inst.arm" valueType="enumerated"/> + <targetPlatform id="com.arm.toolchain.baremetal.169423023.1240534128" name=""/> + <builder buildPath="${workspace_loc:/tx}/Debug" id="com.arm.toolchain.baremetal.builder.95096803" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="8" superClass="com.arm.toolchain.baremetal.builder"/> + <tool id="com.arm.tool.c.compiler.1278650727" name="Arm C Compiler 5" superClass="com.arm.tool.c.compiler"> + <option defaultValue="com.arm.tool.c.compiler.option.optlevel.min" id="com.arm.tool.c.compiler.option.optlevel.186573719" name="Optimization level" superClass="com.arm.tool.c.compiler.option.optlevel" useByScannerDiscovery="true" valueType="enumerated"/> + <option id="com.arm.tool.c.compiler.option.targetcpu.511690441" name="Target CPU (--cpu)" superClass="com.arm.tool.c.compiler.option.targetcpu" useByScannerDiscovery="true" value="Cortex-R8" valueType="string"/> + <option id="com.arm.tool.c.compiler.option.fppcs.402196819" name="Floating-point PCS (--apcs)" superClass="com.arm.tool.c.compiler.option.fppcs" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.fppcs.hard" valueType="enumerated"/> + <option id="com.arm.tool.c.compiler.option.inst.66626183" name="Instruction set" superClass="com.arm.tool.c.compiler.option.inst" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.inst.arm" valueType="enumerated"/> + <option id="com.arm.tool.c.compiler.option.incpath.1434689289" superClass="com.arm.tool.c.compiler.option.incpath" useByScannerDiscovery="false" valueType="includePath"> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/inc_generic}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/inc_port}""/> + </option> + <inputType id="com.arm.tool.c.compiler.input.1039401648" superClass="com.arm.tool.c.compiler.input"/> + <inputType id="com.arm.tool.cpp.compiler.input.1465176759" superClass="com.arm.tool.cpp.compiler.input"/> + </tool> + <tool id="com.arm.tool.cpp.compiler.638753534" name="Arm C++ Compiler 5" superClass="com.arm.tool.cpp.compiler"> + <option defaultValue="com.arm.tool.c.compiler.option.optlevel.min" id="com.arm.tool.c.compiler.option.optlevel.751811346" name="Optimization level" superClass="com.arm.tool.c.compiler.option.optlevel" valueType="enumerated"/> + </tool> + <tool id="com.arm.tool.assembler.184544494" name="Arm Assembler 5" superClass="com.arm.tool.assembler"> + <option id="com.arm.tool.assembler.option.cpu.2038506892" name="Target CPU (--cpu)" superClass="com.arm.tool.assembler.option.cpu" useByScannerDiscovery="true" value="Cortex-R8" valueType="string"/> + <option id="com.arm.tool.assembler.option.fppcs.1004491031" name="Floating-point PCS (--apcs)" superClass="com.arm.tool.assembler.option.fppcs" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.fppcs.hard" valueType="enumerated"/> + <option id="com.arm.tool.assembler.option.inst.1677679517" name="Instruction set" superClass="com.arm.tool.assembler.option.inst" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.inst.arm" valueType="enumerated"/> + <option id="com.arm.tool.assembler.option.preproc.1236693733" name="Preprocess input before assembling (--cpreproc)" superClass="com.arm.tool.assembler.option.preproc" useByScannerDiscovery="false" value="true" valueType="boolean"/> + <inputType id="com.arm.tool.assembler.input.1190173496" superClass="com.arm.tool.assembler.input"/> + </tool> + <tool id="com.arm.tool.c.linker.1353775702" name="Arm Linker 5" superClass="com.arm.tool.c.linker"/> + <tool id="com.arm.tool.librarian.888842860" name="Arm Librarian 5" superClass="com.arm.tool.librarian"/> + </toolChain> + </folderInfo> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> + </cconfiguration> + <cconfiguration id="com.arm.eclipse.build.config.v6.lib.release.base.1262125868"> + <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.arm.eclipse.build.config.v6.lib.release.base.1262125868" moduleId="org.eclipse.cdt.core.settings" name="Release"> + <externalSettings/> + <extensions> + <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> + </extensions> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <configuration artifactExtension="a" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.staticLib" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.staticLib,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="clean" description="" id="com.arm.eclipse.build.config.v6.lib.release.base.1262125868" name="Release" parent="com.arm.eclipse.build.config.v6.lib.release.base"> + <folderInfo id="com.arm.eclipse.build.config.v6.lib.release.base.1262125868." name="/" resourcePath=""> + <toolChain id="com.arm.toolchain.v6.lib.release.base.var.arm_compiler_6-6.492969017" name="Arm Compiler 6"> + <targetPlatform id="com.arm.toolchain.v6.lib.release.base.var.arm_compiler_6-6.492969017.371110606" name=""/> + <builder autoBuildTarget="all" buildPath="${workspace_loc:/tx}/Release" cleanBuildTarget="clean" enableAutoBuild="false" enableCleanBuild="true" enabledIncrementalBuild="true" id="com.arm.toolchain.v6.builder.1194834518" incrementalBuildTarget="all" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="false" superClass="com.arm.toolchain.v6.builder"/> + </toolChain> + </folderInfo> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> + </cconfiguration> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <project id="tx.com.arm.eclipse.build.project.v6.lib.1408735755" name="Static Library"/> + </storageModule> + <storageModule moduleId="scannerConfiguration"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/> + <storageModule moduleId="refreshScope" versionNumber="2"> + <configuration configurationName="Debug"> + <resource resourceType="PROJECT" workspacePath="/tx"/> + </configuration> + <configuration configurationName="Release"> + <resource resourceType="PROJECT" workspacePath="/tx"/> + </configuration> + </storageModule> + <storageModule moduleId="com.arm.projectSettings" version="6.0.0"/> + <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/> +</cproject> diff --git a/ports_smp/cortex_r8_smp/ac5/example_build/tx/.project b/ports_smp/cortex_r8_smp/ac5/example_build/tx/.project new file mode 100644 index 00000000..10681969 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/example_build/tx/.project @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>tx</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name> + <triggers>clean,full,incremental,</triggers> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name> + <triggers>full,incremental,</triggers> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.cdt.core.cnature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature> + </natures> + <linkedResources> + <link> + <name>inc_generic</name> + <type>2</type> + <locationURI>$%7BPARENT-5-PROJECT_LOC%7D/common_smp/inc</locationURI> + </link> + <link> + <name>inc_port</name> + <type>2</type> + <locationURI>$%7BPARENT-2-PROJECT_LOC%7D/inc</locationURI> + </link> + <link> + <name>src_generic</name> + <type>2</type> + <locationURI>$%7BPARENT-5-PROJECT_LOC%7D/common_smp/src</locationURI> + </link> + <link> + <name>src_port</name> + <type>2</type> + <locationURI>$%7BPARENT-2-PROJECT_LOC%7D/src</locationURI> + </link> + </linkedResources> +</projectDescription> diff --git a/ports_smp/cortex_r8_smp/ac5/inc/tx_port.h b/ports_smp/cortex_r8_smp/ac5/inc/tx_port.h new file mode 100644 index 00000000..1de09e88 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/inc/tx_port.h @@ -0,0 +1,412 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the ThreadX */ +/* real-time kernel function identically on a variety of different */ +/* processor architectures. For example, the size or number of bits */ +/* in an "int" data type vary between microprocessor architectures and */ +/* even C compilers for the same microprocessor. ThreadX does not */ +/* directly use native C data types. Instead, ThreadX creates its */ +/* own special types that can be mapped to actual data types by this */ +/* file to guarantee consistency in the interface and functionality. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ + +#ifndef TX_PORT_H +#define TX_PORT_H + + +/************* Define ThreadX SMP constants. *************/ + +/* Define the ThreadX SMP maximum number of cores. */ + +#ifndef TX_THREAD_SMP_MAX_CORES +#define TX_THREAD_SMP_MAX_CORES 2 +#endif + + +/* Define the ThreadX SMP core mask. */ + +#ifndef TX_THREAD_SMP_CORE_MASK +#define TX_THREAD_SMP_CORE_MASK 0x3 /* Where bit 0 represents Core 0, bit 1 represents Core 1, etc. */ +#endif + + +/* Define INLINE_DECLARE to whitespace for ARM compiler. */ + +#define INLINE_DECLARE + + +/* Define dynamic number of cores option. When commented out, the number of cores is static. */ + +/* #define TX_THREAD_SMP_DYNAMIC_CORE_MAX */ + + +/* Define ThreadX SMP initialization macro. */ + +#define TX_PORT_SPECIFIC_PRE_INITIALIZATION + + +/* Define ThreadX SMP pre-scheduler initialization. */ + +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION + + +/* Enable the inter-core interrupt logic. */ + +#define TX_THREAD_SMP_INTER_CORE_INTERRUPT + + +/* Determine if there is customer-specific wakeup logic needed. */ + +#ifdef TX_THREAD_SMP_WAKEUP_LOGIC + +/* Include customer-specific wakeup code. */ + +#include "tx_thread_smp_core_wakeup.h" +#else + +#ifdef TX_THREAD_SMP_DEFAULT_WAKEUP_LOGIC + +/* Default wakeup code. */ +#define TX_THREAD_SMP_WAKEUP_LOGIC +#define TX_THREAD_SMP_WAKEUP(i) _tx_thread_smp_core_preempt(i) +#endif +#endif + + +/* Ensure that the in-line resume/suspend define is not allowed. */ + +#ifdef TX_INLINE_THREAD_RESUME_SUSPEND +#undef TX_INLINE_THREAD_RESUME_SUSPEND +#endif + + +/************* End ThreadX SMP constants. *************/ + +/* Determine if the optional ThreadX user define file should be used. */ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE + + +/* Yes, include the user defines in tx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "tx_user.h" +#endif + + +/* Define compiler library include files. */ + +#include <stdlib.h> +#include <string.h> + + +/* Define ThreadX basic types for this port. */ + +#define VOID void +typedef char CHAR; +typedef unsigned char UCHAR; +typedef int INT; +typedef unsigned int UINT; +typedef long LONG; +typedef unsigned long ULONG; +typedef short SHORT; +typedef unsigned short USHORT; + + +/* Define the priority levels for ThreadX. Legal values range + from 32 to 1024 and MUST be evenly divisible by 32. */ + +#ifndef TX_MAX_PRIORITIES +#define TX_MAX_PRIORITIES 32 +#endif + + +/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during + thread creation is less than this value, the thread create call will return an error. */ + +#ifndef TX_MINIMUM_STACK +#define TX_MINIMUM_STACK 200 /* Minimum stack size for this port */ +#endif + + +/* Define the system timer thread's default stack size and priority. These are only applicable + if TX_TIMER_PROCESS_IN_ISR is not defined. */ + +#ifndef TX_TIMER_THREAD_STACK_SIZE +#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */ +#endif + +#ifndef TX_TIMER_THREAD_PRIORITY +#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */ +#endif + + +/* Define various constants for the ThreadX ARM port. */ + +#ifdef TX_ENABLE_FIQ_SUPPORT +#define TX_INT_DISABLE 0xC0 /* Disable IRQ & FIQ interrupts */ +#else +#define TX_INT_DISABLE 0x80 /* Disable IRQ interrupts */ +#endif +#define TX_INT_ENABLE 0x00 /* Enable IRQ interrupts */ + + +/* Define the clock source for trace event entry time stamp. The following two item are port specific. + For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock + source constants would be: + +#define TX_TRACE_TIME_SOURCE *((ULONG *) 0x0a800024) +#define TX_TRACE_TIME_MASK 0x0000FFFFUL + +*/ + +#ifndef TX_MISRA_ENABLE +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE _tx_thread_smp_time_get() +#endif +#else +#ifndef TX_TRACE_TIME_SOURCE +ULONG _tx_misra_time_stamp_get(VOID); +#define TX_TRACE_TIME_SOURCE _tx_misra_time_stamp_get() +#endif +#endif +#ifndef TX_TRACE_TIME_MASK +#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL +#endif + + +/* Define the port specific options for the _tx_build_options variable. This variable indicates + how the ThreadX library was built. */ + +#ifdef TX_ENABLE_FIQ_SUPPORT +#define TX_FIQ_ENABLED 1 +#else +#define TX_FIQ_ENABLED 0 +#endif + +#ifdef TX_ENABLE_IRQ_NESTING +#define TX_IRQ_NESTING_ENABLED 2 +#else +#define TX_IRQ_NESTING_ENABLED 0 +#endif + +#ifdef TX_ENABLE_FIQ_NESTING +#define TX_FIQ_NESTING_ENABLED 4 +#else +#define TX_FIQ_NESTING_ENABLED 0 +#endif + +#define TX_PORT_SPECIFIC_BUILD_OPTIONS (TX_FIQ_ENABLED | TX_IRQ_NESTING_ENABLED | TX_FIQ_NESTING_ENABLED) + + +/* Define the in-line initialization constant so that modules with in-line + initialization capabilities can prevent their initialization from being + a function call. */ + +#ifdef TX_MISRA_ENABLE +#define TX_DISABLE_INLINE +#else +#define TX_INLINE_INITIALIZATION +#endif + + +/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is + disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack + checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING + define is negated, thereby forcing the stack fill which is necessary for the stack checking + logic. */ + +#ifndef TX_MISRA_ENABLE +#ifdef TX_ENABLE_STACK_CHECKING +#undef TX_DISABLE_STACK_FILLING +#endif +#endif + + +/* Define the TX_THREAD control block extensions for this port. The main reason + for the multiple macros is so that backward compatibility can be maintained with + existing ThreadX kernel awareness modules. */ + +#define TX_THREAD_EXTENSION_0 +#define TX_THREAD_EXTENSION_1 +#define TX_THREAD_EXTENSION_2 ULONG tx_thread_vfp_enable; +#define TX_THREAD_EXTENSION_3 + + +/* Define the port extensions of the remaining ThreadX objects. */ + +#define TX_BLOCK_POOL_EXTENSION +#define TX_BYTE_POOL_EXTENSION +#define TX_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* Define the user extension field of the thread control block. Nothing + additional is needed for this port so it is defined as white space. */ + +#ifndef TX_THREAD_USER_EXTENSION +#define TX_THREAD_USER_EXTENSION +#endif + + +/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete, + tx_thread_shell_entry, and tx_thread_terminate. */ + + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) + + +/* Define the ThreadX object creation extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr) +#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr) +#define TX_QUEUE_CREATE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr) +#define TX_TIMER_CREATE_EXTENSION(timer_ptr) + + +/* Define the ThreadX object deletion extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr) +#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr) +#define TX_QUEUE_DELETE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr) +#define TX_TIMER_DELETE_EXTENSION(timer_ptr) + +/* Determine if the ARM architecture has the CLZ instruction. This is available on + architectures v5 and above. If available, redefine the macro for calculating the + lowest bit set. */ + +#ifndef TX_DISABLE_INLINE + +#ifndef __thumb + +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) m = m & ((ULONG) (-((LONG) m))); \ + b = (ULONG) __clz((unsigned int) m); \ + b = 31 - b; +#endif +#endif + + +/************* Define ThreadX SMP data types and function prototypes. *************/ + +struct TX_THREAD_STRUCT; + + +/* Define the ThreadX SMP protection structure. */ + +typedef struct TX_THREAD_SMP_PROTECT_STRUCT +{ + ULONG tx_thread_smp_protect_in_force; + struct TX_THREAD_STRUCT * + tx_thread_smp_protect_thread; + ULONG tx_thread_smp_protect_core; + ULONG tx_thread_smp_protect_count; + + /* Implementation specific information follows. */ + + ULONG tx_thread_smp_protect_get_caller; + ULONG tx_thread_smp_protect_sr; + ULONG tx_thread_smp_protect_release_caller; +} TX_THREAD_SMP_PROTECT; + + +/* Define ThreadX interrupt lockout and restore macros for protection on + access of critical kernel information. The restore interrupt macro must + restore the interrupt posture of the running thread prior to the value + present prior to the disable macro. In most cases, the save area macro + is used to define a local function save area for the disable and restore + macros. */ + +#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_smp_protect(); +#define TX_RESTORE _tx_thread_smp_unprotect(interrupt_save); + + +/************* End ThreadX SMP data type and function prototype definitions. *************/ + + +/* Define the interrupt lockout macros for each ThreadX object. */ + +#define TX_BLOCK_POOL_DISABLE TX_DISABLE +#define TX_BYTE_POOL_DISABLE TX_DISABLE +#define TX_EVENT_FLAGS_GROUP_DISABLE TX_DISABLE +#define TX_MUTEX_DISABLE TX_DISABLE +#define TX_QUEUE_DISABLE TX_DISABLE +#define TX_SEMAPHORE_DISABLE TX_DISABLE + + +/* Define VFP extension for the Cortex-A9. Each is assumed to be called in the context of the executing + thread. */ + +void tx_thread_vfp_enable(void); +void tx_thread_vfp_disable(void); + + +/* Define the version ID of ThreadX. This may be utilized by the application. */ + +#ifdef TX_THREAD_INIT +CHAR _tx_version_id[] = + "Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX ARMv7-R SMP Version 6.2.0 *"; +#else +extern CHAR _tx_version_id[]; +#endif + + +#endif + + + + diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_initialize_low_level.s b/ports_smp/cortex_r8_smp/ac5/src/tx_initialize_low_level.s new file mode 100644 index 00000000..86879b01 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_initialize_low_level.s @@ -0,0 +1,99 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IMPORT _tx_thread_system_stack_ptr + IMPORT _tx_initialize_unused_memory + IMPORT _tx_version_id + IMPORT _tx_build_options + IMPORT ||Image$$SHARED_DATA$$ZI$$Limit|| + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level SMP/Cortex-A8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_initialize_low_level(VOID) +// { + EXPORT _tx_initialize_low_level +_tx_initialize_low_level + + /* Save the first available memory address. */ + // _tx_initialize_unused_memory = (VOID_PTR) (||Image$$SHARED_DATA$$ZI$$Limit||); + + LDR r0, =||Image$$SHARED_DATA$$ZI$$Limit|| // Get end of non-initialized RAM area + LDR r2, =_tx_initialize_unused_memory // Pickup unused memory ptr address + STR r0, [r2, #0] // Save first free memory address + + /* Done, return to caller. */ + + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF +// } + + /* Reference build options and version ID to ensure they come in. */ + + LDR r2, =_tx_build_options // Pickup build options variable address + LDR r0, [r2, #0] // Pickup build options content + LDR r2, =_tx_version_id // Pickup version ID variable address + LDR r0, [r2, #0] // Pickup version ID content + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_context_restore.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_context_restore.s new file mode 100644 index 00000000..cdc575f8 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_context_restore.s @@ -0,0 +1,275 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IF :DEF:TX_ENABLE_FIQ_SUPPORT +DISABLE_INTS EQU 0xC0 // Disable IRQ & FIQ interrupts +IRQ_MODE EQU 0xD2 // IRQ mode +SVC_MODE EQU 0xD3 // SVC mode + ELSE +DISABLE_INTS EQU 0x80 // Disable IRQ interrupts +IRQ_MODE EQU 0x92 // IRQ mode +SVC_MODE EQU 0x93 // SVC mode + ENDIF + + IMPORT _tx_thread_system_state + IMPORT _tx_thread_current_ptr + IMPORT _tx_thread_execute_ptr + IMPORT _tx_timer_time_slice + IMPORT _tx_thread_schedule + IMPORT _tx_thread_preempt_disable + IMPORT _tx_timer_interrupt_active + IMPORT _tx_thread_smp_protection + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + IMPORT _tx_execution_isr_exit + ENDIF + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function restores the interrupt context if it is processing a */ +/* nested interrupt. If not, it returns to the interrupt thread if no */ +/* preemption is necessary. Otherwise, if preemption is necessary or */ +/* if no thread was running, the function returns to the scheduler. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling routine */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_restore(VOID) +// { + EXPORT _tx_thread_context_restore +_tx_thread_context_restore + + /* Lockout interrupts. */ + + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSID if // Disable IRQ and FIQ interrupts + ELSE + CPSID i // Disable IRQ interrupts + ENDIF + + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + + /* Call the ISR exit function to indicate an ISR is complete. */ + + BL _tx_execution_isr_exit // Call the ISR exit function + ENDIF + + /* Pickup the CPU ID. */ + + MRC p15, 0, r10, c0, c0, 5 // Read CPU ID register + AND r10, r10, #0x03 // Mask off, leaving the CPU ID field + LSL r12, r10, #2 // Build offset to array indexes + + /* Determine if interrupts are nested. */ + // if (--_tx_thread_system_state[core]) + // { + + LDR r3, =_tx_thread_system_state // Pickup address of system state var + ADD r3, r3, r12 // Build array offset + LDR r2, [r3, #0] // Pickup system state + SUB r2, r2, #1 // Decrement the counter + STR r2, [r3, #0] // Store the counter + CMP r2, #0 // Was this the first interrupt? + BEQ __tx_thread_not_nested_restore // If so, not a nested restore + + /* Interrupts are nested. */ + + /* Just recover the saved registers and return to the point of + interrupt. */ + + LDMIA sp!, {r0, r10, r12, lr} // Recover SPSR, POI, and scratch regs + MSR SPSR_cxsf, r0 // Put SPSR back + LDMIA sp!, {r0-r3} // Recover r0-r3 + MOVS pc, lr // Return to point of interrupt + + // } +__tx_thread_not_nested_restore + + /* Determine if a thread was interrupted and no preemption is required. */ + //else if (((_tx_thread_current_ptr[core]) && (_tx_thread_current_ptr[core] == _tx_thread_execute_ptr[core]) + // || (_tx_thread_preempt_disable)) + // { + + LDR r1, =_tx_thread_current_ptr // Pickup address of current thread ptr + ADD r1, r1, r12 // Build index to this core's current thread ptr + LDR r0, [r1, #0] // Pickup actual current thread pointer + CMP r0, #0 // Is it NULL? + BEQ __tx_thread_idle_system_restore // Yes, idle system was interrupted + + LDR r3, =_tx_thread_smp_protection // Get address of protection structure + LDR r2, [r3, #8] // Pickup owning core + CMP r2, r10 // Is the owning core the same as the protected core? + BNE __tx_thread_skip_preempt_check // No, skip the preempt disable check since this is only valid for the owning core + + LDR r3, =_tx_thread_preempt_disable // Pickup preempt disable address + LDR r2, [r3, #0] // Pickup actual preempt disable flag + CMP r2, #0 // Is it set? + BNE __tx_thread_no_preempt_restore // Yes, don't preempt this thread +__tx_thread_skip_preempt_check + + LDR r3, =_tx_thread_execute_ptr // Pickup address of execute thread ptr + ADD r3, r3, r12 // Build index to this core's execute thread ptr + LDR r2, [r3, #0] // Pickup actual execute thread pointer + CMP r0, r2 // Is the same thread highest priority? + BNE __tx_thread_preempt_restore // No, preemption needs to happen + +__tx_thread_no_preempt_restore + + /* Restore interrupted thread or ISR. */ + + /* Pickup the saved stack pointer. */ + // tmp_ptr = _tx_thread_current_ptr[core] -> tx_thread_stack_ptr; + + /* Recover the saved context and return to the point of interrupt. */ + + LDMIA sp!, {r0, r10, r12, lr} // Recover SPSR, POI, and scratch regs + MSR SPSR_cxsf, r0 // Put SPSR back + LDMIA sp!, {r0-r3} // Recover r0-r3 + MOVS pc, lr // Return to point of interrupt + + // } + // else + // { +__tx_thread_preempt_restore + + LDMIA sp!, {r3, r10, r12, lr} // Recover temporarily saved registers + MOV r1, lr // Save lr (point of interrupt) + MOV r2, #SVC_MODE // Build SVC mode CPSR + MSR CPSR_c, r2 // Enter SVC mode + STR r1, [sp, #-4]! // Save point of interrupt + STMDB sp!, {r4-r12, lr} // Save upper half of registers + MOV r4, r3 // Save SPSR in r4 + MOV r2, #IRQ_MODE // Build IRQ mode CPSR + MSR CPSR_c, r2 // Enter IRQ mode + LDMIA sp!, {r0-r3} // Recover r0-r3 + MOV r5, #SVC_MODE // Build SVC mode CPSR + MSR CPSR_c, r5 // Enter SVC mode + STMDB sp!, {r0-r3} // Save r0-r3 on thread's stack + + MRC p15, 0, r10, c0, c0, 5 // Read CPU ID register + AND r10, r10, #0x03 // Mask off, leaving the CPU ID field + LSL r12, r10, #2 // Build offset to array indexes + LDR r1, =_tx_thread_current_ptr // Pickup address of current thread ptr + ADD r1, r1, r12 // Build index to current thread ptr + LDR r0, [r1, #0] // Pickup current thread pointer + + IF {TARGET_FPU_VFP} = {TRUE} + LDR r2, [r0, #160] // Pickup the VFP enabled flag + CMP r2, #0 // Is the VFP enabled? + BEQ _tx_skip_irq_vfp_save // No, skip VFP IRQ save + VMRS r2, FPSCR // Pickup the FPSCR + STR r2, [sp, #-4]! // Save FPSCR + VSTMDB sp!, {D0-D15} // Save D0-D15 +_tx_skip_irq_vfp_save + ENDIF + + MOV r3, #1 // Build interrupt stack type + STMDB sp!, {r3, r4} // Save interrupt stack type and SPSR + STR sp, [r0, #8] // Save stack pointer in thread control + // block + + /* Save the remaining time-slice and disable it. */ + // if (_tx_timer_time_slice[core]) + // { + + LDR r3, =_tx_timer_interrupt_active // Pickup timer interrupt active flag's address +_tx_wait_for_timer_to_finish + LDR r2, [r3, #0] // Pickup timer interrupt active flag + CMP r2, #0 // Is the timer interrupt active? + BNE _tx_wait_for_timer_to_finish // If timer interrupt is active, wait until it completes + + LDR r3, =_tx_timer_time_slice // Pickup time-slice variable address + ADD r3, r3, r12 // Build index to core's time slice + LDR r2, [r3, #0] // Pickup time-slice + CMP r2, #0 // Is it active? + BEQ __tx_thread_dont_save_ts // No, don't save it + + // _tx_thread_current_ptr[core] -> tx_thread_time_slice = _tx_timer_time_slice[core]; + // _tx_timer_time_slice[core] = 0; + + STR r2, [r0, #24] // Save thread's time-slice + MOV r2, #0 // Clear value + STR r2, [r3, #0] // Disable global time-slice flag + + // } +__tx_thread_dont_save_ts + + /* Clear the current task pointer. */ + // _tx_thread_current_ptr[core] = TX_NULL; + + MOV r2, #0 // NULL value + STR r2, [r1, #0] // Clear current thread pointer + + /* Set bit indicating this thread is ready for execution. */ + + LDR r2, [r0, #152] // Pickup the ready bit + ORR r2, r2, #0x8000 // Set ready bit (bit 15) + DMB // Ensure that accesses to shared resource have completed + STR r2, [r0, #152] // Make this thread ready for executing again + + /* Return to the scheduler. */ + // _tx_thread_schedule(); + + B _tx_thread_schedule // Return to scheduler + // } + +__tx_thread_idle_system_restore + + /* Just return back to the scheduler! */ + + MOV r3, #SVC_MODE // Build SVC mode with interrupts disabled + MSR CPSR_c, r3 // Change to SVC mode + B _tx_thread_schedule // Return to scheduler +// } + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_context_save.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_context_save.s new file mode 100644 index 00000000..96448b4a --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_context_save.s @@ -0,0 +1,191 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IMPORT _tx_thread_system_state + IMPORT _tx_thread_current_ptr + IMPORT __tx_irq_processing_return + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + IMPORT _tx_execution_isr_enter + ENDIF + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_save SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function saves the context of an executing thread in the */ +/* beginning of interrupt processing. The function also ensures that */ +/* the system stack is used upon return to the calling ISR. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_save(VOID) +// { + EXPORT _tx_thread_context_save +_tx_thread_context_save + + /* Upon entry to this routine, it is assumed that IRQ interrupts are locked + out, we are in IRQ mode, and all registers are intact. */ + + /* Check for a nested interrupt condition. */ + // if (_tx_thread_system_state[core]++) + // { + + STMDB sp!, {r0-r3} // Save some working registers + + /* Save the rest of the scratch registers on the stack and return to the + calling ISR. */ + + MRS r0, SPSR // Pickup saved SPSR + SUB lr, lr, #4 // Adjust point of interrupt + STMDB sp!, {r0, r10, r12, lr} // Store other registers + + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSID if // Disable FIQ interrupts + ENDIF + + /* Pickup the CPU ID. */ + + MRC p15, 0, r10, c0, c0, 5 // Read CPU ID register + AND r10, r10, #0x03 // Mask off, leaving the CPU ID field + LSL r12, r10, #2 // Build offset to array indexes + + LDR r3, =_tx_thread_system_state // Pickup address of system state var + ADD r3, r3, r12 // Build index into the system state array + LDR r2, [r3, #0] // Pickup system state + CMP r2, #0 // Is this the first interrupt? + BEQ __tx_thread_not_nested_save // Yes, not a nested context save + + /* Nested interrupt condition. */ + + ADD r2, r2, #1 // Increment the interrupt counter + STR r2, [r3, #0] // Store it back in the variable + + /* Return to the ISR. */ + + MOV r10, #0 // Clear stack limit + + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + + /* Call the ISR enter function to indicate an ISR is executing. */ + + PUSH {r12, lr} // Save ISR lr & r12 + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r12, lr} // Recover ISR lr & r12 + ENDIF + + B __tx_irq_processing_return // Continue IRQ processing + +__tx_thread_not_nested_save + // } + + /* Otherwise, not nested, check to see if a thread was running. */ + // else if (_tx_thread_current_ptr[core]) + // { + + ADD r2, r2, #1 // Increment the interrupt counter + STR r2, [r3, #0] // Store it back in the variable + LDR r1, =_tx_thread_current_ptr // Pickup address of current thread ptr + ADD r1, r1, r12 // Build index into current thread ptr + LDR r0, [r1, #0] // Pickup current thread pointer + CMP r0, #0 // Is it NULL? + BEQ __tx_thread_idle_system_save // If so, interrupt occurred in + // scheduling loop - nothing needs saving! + + /* Save the current stack pointer in the thread's control block. */ + // _tx_thread_current_ptr[core] -> tx_thread_stack_ptr = sp; + + /* Switch to the system stack. */ + // sp = _tx_thread_system_stack_ptr; + + MOV r10, #0 // Clear stack limit + + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + + /* Call the ISR enter function to indicate an ISR is executing. */ + + PUSH {r12, lr} // Save ISR lr & r12 + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r12, lr} // Recover ISR lr & r12 + ENDIF + + B __tx_irq_processing_return // Continue IRQ processing + + // } + // else + // { + +__tx_thread_idle_system_save + + /* Interrupt occurred in the scheduling loop. */ + + /* Not much to do here, just adjust the stack pointer, and return to IRQ + processing. */ + + MOV r10, #0 // Clear stack limit + + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + + /* Call the ISR enter function to indicate an ISR is executing. */ + + PUSH {r12, lr} // Save ISR lr & r12 + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r12, lr} // Recover ISR lr & r12 + ENDIF + + ADD sp, sp, #32 // Recover saved registers + B __tx_irq_processing_return // Continue IRQ processing + + // } +// } + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_interrupt_control.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_interrupt_control.s new file mode 100644 index 00000000..f76bb3a8 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_interrupt_control.s @@ -0,0 +1,91 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IF :DEF:TX_ENABLE_FIQ_SUPPORT +INT_MASK EQU 0xC0 // Interrupt bit mask + ELSE +INT_MASK EQU 0x80 // Interrupt bit mask + ENDIF + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_control(UINT new_posture) +// { + EXPORT _tx_thread_interrupt_control +_tx_thread_interrupt_control + + /* Pickup current interrupt lockout posture. */ + + MRS r3, CPSR // Pickup current CPSR + BIC r1, r3, #INT_MASK // Clear interrupt lockout bits + ORR r1, r1, r0 // Or-in new interrupt lockout bits + + /* Apply the new interrupt posture. */ + + MSR CPSR_c, r1 // Setup new CPSR + AND r0, r3, #INT_MASK // Return previous interrupt mask + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + +// } + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_interrupt_disable.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_interrupt_disable.s new file mode 100644 index 00000000..3197ab46 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_interrupt_disable.s @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_disable SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for disabling interrupts */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_disable(void) +// { + EXPORT _tx_thread_interrupt_disable +_tx_thread_interrupt_disable + + /* Pickup current interrupt lockout posture. */ + + MRS r0, CPSR // Pickup current CPSR + + /* Mask interrupts. */ + + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSID if // Disable IRQ and FIQ + ELSE + CPSID i // Disable IRQ + ENDIF + + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF +// } + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_interrupt_restore.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_interrupt_restore.s new file mode 100644 index 00000000..e1419f01 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_interrupt_restore.s @@ -0,0 +1,74 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_restore SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for restoring interrupts to the state */ +/* returned by a previous _tx_thread_interrupt_disable call. */ +/* */ +/* INPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ + EXPORT _tx_thread_interrupt_restore +_tx_thread_interrupt_restore + + /* Apply the new interrupt posture. */ + + MSR CPSR_c, r0 // Setup new CPSR + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_irq_nesting_end.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_irq_nesting_end.s new file mode 100644 index 00000000..953e8128 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_irq_nesting_end.s @@ -0,0 +1,98 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + IF :DEF:TX_ENABLE_FIQ_SUPPORT +DISABLE_INTS EQU 0xC0 // Disable IRQ & FIQ interrupts + ELSE +DISABLE_INTS EQU 0x80 // Disable IRQ interrupts + ENDIF +MODE_MASK EQU 0x1F // Mode mask +IRQ_MODE_BITS EQU 0x12 // IRQ mode bits + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_irq_nesting_end SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called by the application from IRQ mode after */ +/* _tx_thread_irq_nesting_start has been called and switches the IRQ */ +/* processing from system mode back to IRQ mode prior to the ISR */ +/* calling _tx_thread_context_restore. Note that this function */ +/* assumes the system stack pointer is in the same position after */ +/* nesting start function was called. */ +/* */ +/* This function assumes that the system mode stack pointer was setup */ +/* during low-level initialization (tx_initialize_low_level.s). */ +/* */ +/* This function returns with IRQ interrupts disabled. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_irq_nesting_end(VOID) +// { + EXPORT _tx_thread_irq_nesting_end +_tx_thread_irq_nesting_end + MOV r3,lr // Save ISR return address + MRS r0, CPSR // Pickup the CPSR + ORR r0, r0, #DISABLE_INTS // Build disable interrupt value + MSR CPSR_c, r0 // Disable interrupts + LDMIA sp!, {lr, r1} // Pickup saved lr (and r1 throw-away for + // 8-byte alignment logic) + BIC r0, r0, #MODE_MASK // Clear mode bits + ORR r0, r0, #IRQ_MODE_BITS // Build IRQ mode CPSR + MSR CPSR_c, r0 // Re-enter IRQ mode + IF {INTER} = {TRUE} + BX r3 // Return to caller + ELSE + MOV pc, r3 // Return to caller + ENDIF +// } + END + diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_irq_nesting_start.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_irq_nesting_start.s new file mode 100644 index 00000000..07607ac7 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_irq_nesting_start.s @@ -0,0 +1,92 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +IRQ_DISABLE EQU 0x80 // IRQ disable bit +MODE_MASK EQU 0x1F // Mode mask +SYS_MODE_BITS EQU 0x1F // System mode bits + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_irq_nesting_start SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called by the application from IRQ mode after */ +/* _tx_thread_context_save has been called and switches the IRQ */ +/* processing to the system mode so nested IRQ interrupt processing */ +/* is possible (system mode has its own "lr" register). Note that */ +/* this function assumes that the system mode stack pointer was setup */ +/* during low-level initialization (tx_initialize_low_level.s). */ +/* */ +/* This function returns with IRQ interrupts enabled. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_irq_nesting_start(VOID) +// { + EXPORT _tx_thread_irq_nesting_start +_tx_thread_irq_nesting_start + MOV r3,lr // Save ISR return address + MRS r0, CPSR // Pickup the CPSR + BIC r0, r0, #MODE_MASK // Clear the mode bits + ORR r0, r0, #SYS_MODE_BITS // Build system mode CPSR + MSR CPSR_c, r0 // Enter system mode + STMDB sp!, {lr, r1} // Push the system mode lr on the system mode stack + // and push r1 just to keep 8-byte alignment + BIC r0, r0, #IRQ_DISABLE // Build enable IRQ CPSR + MSR CPSR_c, r0 // Enter system mode + IF {INTER} = {TRUE} + BX r3 // Return to caller + ELSE + MOV pc, r3 // Return to caller + ENDIF +// } + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_schedule.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_schedule.s new file mode 100644 index 00000000..ebb0ca5c --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_schedule.s @@ -0,0 +1,249 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IMPORT _tx_thread_execute_ptr + IMPORT _tx_thread_current_ptr + IMPORT _tx_timer_time_slice + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + IMPORT _tx_execution_thread_enter + ENDIF + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function waits for a thread control block pointer to appear in */ +/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ +/* in the variable, the corresponding thread is resumed. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* _tx_thread_system_return Return to system from thread */ +/* _tx_thread_context_restore Restore thread's context */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_schedule(VOID) +// { + EXPORT _tx_thread_schedule +_tx_thread_schedule + + /* Enable interrupts. */ + + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSIE if // Enable IRQ and FIQ interrupts + ELSE + CPSIE i // Enable IRQ interrupts + ENDIF + + /* Pickup the CPU ID. */ + + MRC p15, 0, r10, c0, c0, 5 // Read CPU ID register + AND r10, r10, #0x03 // Mask off, leaving the CPU ID field + LSL r12, r10, #2 // Build offset to array indexes + + LDR r1, =_tx_thread_execute_ptr // Address of thread execute ptr + ADD r1, r1, r12 // Build offset to execute ptr for this core + + /* Lockout interrupts transfer control to it. */ + + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSID if // Disable IRQ and FIQ interrupts + ELSE + CPSID i // Disable IRQ interrupts + ENDIF + + /* Wait for a thread to execute. */ + // do + // { + + LDR r0, [r1, #0] // Pickup next thread to execute + CMP r0, #0 // Is it NULL? + BEQ _tx_thread_schedule // If so, keep looking for a thread + + // } + // while(_tx_thread_execute_ptr[core] == TX_NULL); + + /* Now make sure the thread's ready bit is set. */ + + LDR r2, [r0, #152] // Pickup the thread ready bit + AND r3, r2, #0x8000 // Isolate the ready bit + CMP r3, #0 // Is it set? + BEQ _tx_thread_schedule // If not, restart the scheduling loop + + /* Yes! We have a thread to execute. ; + + /* Clear the ready bit. */ + + BIC r2, r2, #0x8000 // Clear ready bit + STR r2, [r0, #152] // Store it back in the thread control block + DMB + + /* Setup the current thread pointer. */ + // _tx_thread_current_ptr[core] = _tx_thread_execute_ptr[core]; + + LDR r1, =_tx_thread_current_ptr // Pickup address of current thread + ADD r1, r1, r12 // Build index into the current thread array + STR r0, [r1, #0] // Setup current thread pointer + + /* Increment the run count for this thread. */ + // _tx_thread_current_ptr[core] -> tx_thread_run_count++; + + LDR r2, [r0, #4] // Pickup run counter + LDR r3, [r0, #24] // Pickup time-slice for this thread + ADD r2, r2, #1 // Increment thread run-counter + STR r2, [r0, #4] // Store the new run counter + + /* Setup time-slice, if present. */ + // _tx_timer_time_slice[core] = _tx_thread_current_ptr[core] -> tx_thread_time_slice; + + LDR r2, =_tx_timer_time_slice // Pickup address of time slice + // variable + ADD r2, r2, r12 // Build index into the time-slice array + LDR sp, [r0, #8] // Switch stack pointers + STR r3, [r2, #0] // Setup time-slice + + /* Switch to the thread's stack. */ + // sp = _tx_thread_execute_ptr[core] -> tx_thread_stack_ptr; + + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + + /* Call the thread entry function to indicate the thread is executing. */ + + MOV r5, r0 // Save r0 + BL _tx_execution_thread_enter // Call the thread execution enter function + MOV r0, r5 // Restore r0 + ENDIF + + /* Determine if an interrupt frame or a synchronous task suspension frame + is present. */ + + LDMIA sp!, {r4, r5} // Pickup the stack type and saved CPSR + CMP r4, #0 // Check for synchronous context switch + BEQ _tx_solicited_return + MSR SPSR_cxsf, r5 // Setup SPSR for return + IF {TARGET_FPU_VFP} = {TRUE} + LDR r1, [r0, #160] // Pickup the VFP enabled flag + CMP r1, #0 // Is the VFP enabled? + BEQ _tx_skip_interrupt_vfp_restore // No, skip VFP interrupt restore + VLDMIA sp!, {D0-D15} // Recover D0-D15 + LDR r4, [sp], #4 // Pickup FPSCR + VMSR FPSCR, r4 // Restore FPSCR +_tx_skip_interrupt_vfp_restore + ENDIF + LDMIA sp!, {r0-r12, lr, pc}^ // Return to point of thread interrupt + +_tx_solicited_return + IF {TARGET_FPU_VFP} = {TRUE} + MSR CPSR_cxsf, r5 // Recover CPSR + LDR r1, [r0, #160] // Pickup the VFP enabled flag + CMP r1, #0 // Is the VFP enabled? + BEQ _tx_skip_solicited_vfp_restore // No, skip VFP solicited restore + VLDMIA sp!, {D0-D15} // Recover D0-D15 + LDR r4, [sp], #4 // Pickup FPSCR + VMSR FPSCR, r4 // Restore FPSCR +_tx_skip_solicited_vfp_restore + ENDIF + MSR CPSR_cxsf, r5 // Recover CPSR + LDMIA sp!, {r4-r11, lr} // Return to thread synchronously + BX lr // Return to caller + +// } + + + IF {TARGET_FPU_VFP} = {TRUE} + EXPORT tx_thread_vfp_enable +tx_thread_vfp_enable + MRS r2, CPSR // Pickup the CPSR + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSID if // Disable IRQ and FIQ interrupts + ELSE + CPSID i // Disable IRQ interrupts + ENDIF + MRC p15, 0, r1, c0, c0, 5 // Read CPU ID register + AND r1, r1, #0x03 // Mask off, leaving the CPU ID field + LSL r1, r1, #2 // Build offset to array indexes + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + ADD r0, r0, r1 // Build index into the current thread array + LDR r1, [r0] // Pickup current thread pointer + CMP r1, #0 // Check for NULL thread pointer + BEQ __tx_no_thread_to_enable // If NULL, skip VFP enable + MOV r0, #1 // Build enable value + STR r0, [r1, #160] // Set the VFP enable flag (tx_thread_vfp_enable field in TX_THREAD) +__tx_no_thread_to_enable + MSR CPSR_cxsf, r2 // Recover CPSR + BX LR // Return to caller + + EXPORT tx_thread_vfp_disable +tx_thread_vfp_disable + MRS r2, CPSR // Pickup the CPSR + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSID if // Disable IRQ and FIQ interrupts + ELSE + CPSID i // Disable IRQ interrupts + ENDIF + MRC p15, 0, r1, c0, c0, 5 // Read CPU ID register + AND r1, r1, #0x03 // Mask off, leaving the CPU ID field + LSL r1, r1, #2 // Build offset to array indexes + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + ADD r0, r0, r1 // Build index into the current thread array + LDR r1, [r0] // Pickup current thread pointer + CMP r1, #0 // Check for NULL thread pointer + BEQ __tx_no_thread_to_disable // If NULL, skip VFP disable + MOV r0, #0 // Build disable value + STR r0, [r1, #160] // Clear the VFP enable flag (tx_thread_vfp_enable field in TX_THREAD) +__tx_no_thread_to_disable + MSR CPSR_cxsf, r2 // Recover CPSR + BX LR // Return to caller + ENDIF + +// } + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_core_get.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_core_get.s new file mode 100644 index 00000000..bd917792 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_core_get.s @@ -0,0 +1,72 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_smp_core_get SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the currently running core number and returns it.*/ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* Core ID */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX Source */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ + EXPORT _tx_thread_smp_core_get +_tx_thread_smp_core_get + MRC p15, 0, r0, c0, c0, 5 // Read CPU ID register + AND r0, r0, #0x03 // Mask off, leaving the CPU ID field + + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_core_preempt.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_core_preempt.s new file mode 100644 index 00000000..20a6ab29 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_core_preempt.s @@ -0,0 +1,89 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IMPORT send_sgi + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_smp_core_preempt SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function preempts the specified core in situations where the */ +/* thread corresponding to this core is no longer ready or when the */ +/* core must be used for a higher-priority thread. If the specified is */ +/* the current core, this processing is skipped since the will give up */ +/* control subsequently on its own. */ +/* */ +/* INPUT */ +/* */ +/* core The core to preempt */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX Source */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ + EXPORT _tx_thread_smp_core_preempt +_tx_thread_smp_core_preempt + + STMDB sp!, {lr, r4} // Save the lr and r4 register on the stack + + /* Place call to send inter-processor interrupt here! */ + + DSB // + MOV r1, #1 // Build parameter list + LSL r1, r1, r0 // + MOV r0, #0 // + MOV r2, #0 // + BL send_sgi // Make call to send inter-processor interrupt + + LDMIA sp!, {lr, r4} // Recover lr register and r4 + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_current_state_get.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_current_state_get.s new file mode 100644 index 00000000..32bcb44e --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_current_state_get.s @@ -0,0 +1,91 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IMPORT _tx_thread_system_state + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_smp_current_state_get SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is gets the current state of the calling core. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX Components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ + EXPORT _tx_thread_smp_current_state_get +_tx_thread_smp_current_state_get + + MRS r3, CPSR // Pickup current CPSR + + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSID if // Disable IRQ and FIQ interrupts + ELSE + CPSID i // Disable IRQ interrupts + ENDIF + + /* Pickup the CPU ID. */ + + MRC p15, 0, r2, c0, c0, 5 // Read CPU ID register + AND r2, r2, #0x03 // Mask off, leaving the CPU ID field + LSL r2, r2, #2 // Build offset to array indexes + + LDR r1, =_tx_thread_system_state // Pickup start of the current state array + ADD r1, r1, r2 // Build index into the current state array + LDR r0, [r1] // Pickup state for this core + MSR CPSR_c, r3 // Restore CPSR + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_current_thread_get.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_current_thread_get.s new file mode 100644 index 00000000..0e50c725 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_current_thread_get.s @@ -0,0 +1,90 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + IMPORT _tx_thread_current_ptr + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_smp_current_thread_get SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is gets the current thread of the calling core. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX Components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ + EXPORT _tx_thread_smp_current_thread_get +_tx_thread_smp_current_thread_get + + MRS r3, CPSR // Pickup current CPSR + + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSID if // Disable IRQ and FIQ interrupts + ELSE + CPSID i // Disable IRQ interrupts + ENDIF + + /* Pickup the CPU ID. */ + + MRC p15, 0, r2, c0, c0, 5 // Read CPU ID register + AND r2, r2, #0x03 // Mask off, leaving the CPU ID field + LSL r2, r2, #2 // Build offset to array indexes + + LDR r1, =_tx_thread_current_ptr // Pickup start of the current thread array + ADD r1, r1, r2 // Build index into the current thread array + LDR r0, [r1] // Pickup current thread for this core + MSR CPSR_c, r3 // Restore CPSR + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_initialize_wait.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_initialize_wait.s new file mode 100644 index 00000000..e7befb3d --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_initialize_wait.s @@ -0,0 +1,128 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IMPORT _tx_thread_system_state + IMPORT _tx_thread_current_ptr + IMPORT _tx_thread_smp_release_cores_flag + IMPORT _tx_thread_schedule + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_smp_initialize_wait SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the place where additional cores wait until */ +/* initialization is complete before they enter the thread scheduling */ +/* loop. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* Hardware */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ + EXPORT _tx_thread_smp_initialize_wait +_tx_thread_smp_initialize_wait + + /* Lockout interrupts. */ + + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSID if // Disable IRQ and FIQ interrupts + ELSE + CPSID i // Disable IRQ interrupts + ENDIF + + /* Pickup the CPU ID. */ + + MRC p15, 0, r10, c0, c0, 5 // Read CPU ID register + AND r10, r10, #0x03 // Mask off, leaving the CPU ID field + LSL r10, r10, #2 // Build offset to array indexes + + /* Make sure the system state for this core is TX_INITIALIZE_IN_PROGRESS before we check the release + flag. */ + + LDR r3, =_tx_thread_system_state // Build address of system state variable + ADD r3, r3, r10 // Build index into the system state array + LDR r2, =0xF0F0F0F0 // Build TX_INITIALIZE_IN_PROGRESS flag +wait_for_initialize + LDR r1, [r3] // Pickup system state + CMP r1, r2 // Has initialization completed? + BNE wait_for_initialize // If different, wait here! + + /* Pickup the release cores flag. */ + + LDR r2, =_tx_thread_smp_release_cores_flag // Build address of release cores flag + +wait_for_release + LDR r3, [r2] // Pickup the flag + CMP r3, #0 // Is it set? + BEQ wait_for_release // Wait for the flag to be set + + /* Core 0 has released this core. */ + + /* Clear this core's system state variable. */ + + LDR r3, =_tx_thread_system_state // Build address of system state variable + ADD r3, r3, r10 // Build index into the system state array + MOV r0, #0 // Build clear value + STR r0, [r3] // Clear this core's entry in the system state array + + /* Now wait for core 0 to finish it's initialization. */ + + LDR r3, =_tx_thread_system_state // Build address of system state variable of logical 0 + +core_0_wait_loop + LDR r2, [r3] // Pickup system state for core 0 + CMP r2, #0 // Is it 0? + BNE core_0_wait_loop // No, keep waiting for core 0 to finish its initialization + + /* Initialize is complete, enter the scheduling loop! */ + + B _tx_thread_schedule // Enter scheduling loop for this core! + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_low_level_initialize.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_low_level_initialize.s new file mode 100644 index 00000000..b5edd74b --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_low_level_initialize.s @@ -0,0 +1,72 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_smp_low_level_initialize SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs low-level initialization of the booting */ +/* core. */ +/* */ +/* INPUT */ +/* */ +/* number_of_cores Number of cores */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_high_level ThreadX high-level init */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ + EXPORT _tx_thread_smp_low_level_initialize +_tx_thread_smp_low_level_initialize + + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_protect.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_protect.s new file mode 100644 index 00000000..11b81128 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_protect.s @@ -0,0 +1,127 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IMPORT _tx_thread_current_ptr + IMPORT _tx_thread_smp_protection + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_smp_protect SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets protection for running inside the ThreadX */ +/* source. This is acomplished by a combination of a test-and-set */ +/* flag and periodically disabling interrupts. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* Previous Status Register */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX Source */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ + EXPORT _tx_thread_smp_protect +_tx_thread_smp_protect + + MRS r3, CPSR // Pickup current CPSR + + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSID if // Disable IRQ and FIQ interrupts + ELSE + CPSID i // Disable IRQ interrupts + ENDIF + + /* Pickup the CPU ID. */ + + MRC p15, 0, r2, c0, c0, 5 // Read CPU ID register + AND r2, r2, #0x03 // Mask off, leaving the CPU ID field + LDR r0,=_tx_thread_smp_protection // Build address to protection structure + LDR r1, [r0, #8] // Pickup the owning core + CMP r1, r2 // Is it this core? + BEQ _owned // Yes, the protection is already owned + + LDREX r1, [r0] // Pickup the protection + CMP r1, #0 // Is it available? + BEQ _get_protection // Yes, get the protection + MSR CPSR_c, r3 // Restore CPSR + WFE // Go into standby + B _tx_thread_smp_protect // On waking restart the protection attempt + +_get_protection + MOV r1, #1 // Build lock value + STREX r2, r1, [r0] // Attempt to get protection + CMP r2, #0x0 // Check whether store completed successfully (0=succeeded) + MSRNE CPSR_c, r3 // If unsuccessful, restore CPSR + BNE _tx_thread_smp_protect // If unsuccessful, try the process again! + DMB ; + MRC p15, 0, r2, c0, c0, 5 // Read CPU ID register + AND r2, r2, #0x03 // Mask off, leaving the CPU ID field + STR r2, [r0, #8] // Save owning core + + IF :DEF:TX_MPCORE_DEBUG_ENABLE + LSL r2, r2, #2 // Build offset to array indexes + LDR r1, =_tx_thread_current_ptr // Pickup start of the current thread array + ADD r1, r1, r2 // Build index into the current thread array + LDR r2, [r1] // Pickup current thread for this core + STR r2, [r0, #4] // Save current thread pointer + STR LR, [r0, #16] // Save caller's return address + STR r3, [r0, #20] // Save CPSR + ENDIF +_owned + LDR r1, [r0, #12] // Pickup ownership count + ADD r1, r1, #1 // Increment ownership count + STR r1, [r0, #12] // Store new ownership count + + MOV r0, r3 // Return the CPSR + + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_time_get.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_time_get.s new file mode 100644 index 00000000..fdaab14b --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_time_get.s @@ -0,0 +1,75 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_smp_time_get SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the global time value that is used for debug */ +/* information and event tracing. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* 32-bit time stamp */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX Source */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ + EXPORT _tx_thread_smp_time_get +_tx_thread_smp_time_get + + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + LDR r0, [r0, #0x604] // Read count register + + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_unprotect.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_unprotect.s new file mode 100644 index 00000000..b431e485 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_smp_unprotect.s @@ -0,0 +1,119 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IMPORT _tx_thread_current_ptr + IMPORT _tx_thread_smp_protection + IMPORT _tx_thread_preempt_disable + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_smp_unprotect SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function releases previously obtained protection. The supplied */ +/* previous SR is restored. If the value of _tx_thread_system_state */ +/* and _tx_thread_preempt_disable are both zero, then multithreading */ +/* is enabled as well. */ +/* */ +/* INPUT */ +/* */ +/* Previous Status Register */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX Source */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ + EXPORT _tx_thread_smp_unprotect +_tx_thread_smp_unprotect + + /* Lockout interrupts. */ + + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSID if // Disable IRQ and FIQ interrupts + ELSE + CPSID i // Disable IRQ interrupts + ENDIF + + LDR r1,=_tx_thread_smp_protection // Build address of protection structure + MRC p15, 0, r3, c0, c0, 5 // Read CPU ID register + AND r3, r3, #0x03 // Mask off, leaving the CPU ID field + LDR r2, [r1, #8] // Pickup the owning core + CMP r2, r3 // Is it this core? + BNE _still_protected // If this is not the owning core, protection is in force elsewhere + + LDR r2, [r1, #12] // Pickup the protection count + CMP r2, #0 // Check to see if the protection is still active + BEQ _still_protected // If the protection count is zero, protection has already been cleared + + SUB r2, r2, #1 // Decrement the protection count + STR r2, [r1, #12] // Store the new count back + CMP r2, #0 // Check to see if the protection is still active + BNE _still_protected // If the protection count is non-zero, protection is still in force + LDR r2,=_tx_thread_preempt_disable // Build address of preempt disable flag + LDR r3, [r2] // Pickup preempt disable flag + CMP r3, #0 // Is the preempt disable flag set? + BNE _still_protected // Yes, skip the protection release + MOV r2, #0xFFFFFFFF // Build invalid value + STR r2, [r1, #8] // Mark the protected core as invalid + IF :DEF:TX_MPCORE_DEBUG_ENABLE + STR LR, [r0, #16] // Save caller's return address + ENDIF + DMB // Ensure that accesses to shared resource have completed + MOV r2, #0 // Build release protection value + STR r2, [r1] // Release the protection + DSB // To ensure update of the protection occurs before other CPUs awake + SEV // Send event to other CPUs, wakes anyone waiting on the protection (using WFE) + +_still_protected + MSR CPSR_c, r0 // Restore CPSR + + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_stack_build.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_stack_build.s new file mode 100644 index 00000000..425bc4e9 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_stack_build.s @@ -0,0 +1,159 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +SVC_MODE EQU 0x13 // SVC mode + IF :DEF:TX_ENABLE_FIQ_SUPPORT +CPSR_MASK EQU 0xDF // Mask initial CPSR, IRQ & FIQ ints enabled + ELSE +CPSR_MASK EQU 0x9F // Mask initial CPSR, IRQ ints enabled + ENDIF + +THUMB_BIT EQU 0x20 // Thumb-bit + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a stack frame on the supplied thread's stack. */ +/* The stack frame results in a fake interrupt return to the supplied */ +/* function pointer. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + EXPORT _tx_thread_stack_build +_tx_thread_stack_build + + + /* Build a fake interrupt frame. The form of the fake interrupt stack + on the Cortex-R8 should look like the following after it is built: + + Stack Top: 1 Interrupt stack frame type + CPSR Initial value for CPSR + a1 (r0) Initial value for a1 + a2 (r1) Initial value for a2 + a3 (r2) Initial value for a3 + a4 (r3) Initial value for a4 + v1 (r4) Initial value for v1 + v2 (r5) Initial value for v2 + v3 (r6) Initial value for v3 + v4 (r7) Initial value for v4 + v5 (r8) Initial value for v5 + sb (r9) Initial value for sb + sl (r10) Initial value for sl + fp (r11) Initial value for fp + ip (r12) Initial value for ip + lr (r14) Initial value for lr + pc (r15) Initial value for pc + 0 For stack backtracing + + Stack Bottom: (higher memory address) */ + + LDR r2, [r0, #16] // Pickup end of stack area + BIC r2, r2, #7 // Ensure 8-byte alignment + SUB r2, r2, #76 // Allocate space for the stack frame + + /* Actually build the stack frame. */ + + MOV r3, #1 // Build interrupt stack type + STR r3, [r2, #0] // Store stack type + MOV r3, #0 // Build initial register value + STR r3, [r2, #8] // Store initial r0 + STR r3, [r2, #12] // Store initial r1 + STR r3, [r2, #16] // Store initial r2 + STR r3, [r2, #20] // Store initial r3 + STR r3, [r2, #24] // Store initial r4 + STR r3, [r2, #28] // Store initial r5 + STR r3, [r2, #32] // Store initial r6 + STR r3, [r2, #36] // Store initial r7 + STR r3, [r2, #40] // Store initial r8 + STR r3, [r2, #44] // Store initial r9 + LDR r3, [r0, #12] // Pickup stack starting address + STR r3, [r2, #48] // Store initial r10 (sl) + MOV r3, #0 // Build initial register value + STR r3, [r2, #52] // Store initial r11 + STR r3, [r2, #56] // Store initial r12 + STR r3, [r2, #60] // Store initial lr + STR r1, [r2, #64] // Store initial pc + STR r3, [r2, #68] // 0 for back-trace + + MRS r3, CPSR // Pickup CPSR + BIC r3, r3, #CPSR_MASK // Mask mode bits of CPSR + ORR r3, r3, #SVC_MODE // Build CPSR, SVC mode, interrupts enabled + BIC r3, r3, #THUMB_BIT // Clear Thumb-bit by default + AND r1, r1, #1 // Determine if the entry function is in Thumb mode + CMP r1, #1 // Is the Thumb-bit set? + ORREQ r3, r3, #THUMB_BIT // Yes, set the Thumb-bit + STR r3, [r2, #4] // Store initial CPSR + + /* Setup stack pointer. */ + // thread_ptr -> tx_thread_stack_ptr = r2; + + STR r2, [r0, #8] // Save stack pointer in thread's + // control block + + + /* Set ready bit in thread control block. */ + + LDR r2, [r0, #152] // Pickup word with ready bit + ORR r2, r2, #0x8000 // Build ready bit set + STR r2, [r0, #152] // Set ready bit + + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF +// } + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_system_return.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_system_return.s new file mode 100644 index 00000000..1803e190 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_system_return.s @@ -0,0 +1,193 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IMPORT _tx_thread_current_ptr + IMPORT _tx_timer_time_slice + IMPORT _tx_thread_schedule + IMPORT _tx_thread_preempt_disable + IMPORT _tx_thread_smp_protection + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + IMPORT _tx_execution_thread_exit + ENDIF + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the ThreadX system. Only a */ +/* minimal context is saved since the compiler assumes temp registers */ +/* are going to get slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_system_return(VOID) +// { + EXPORT _tx_thread_system_return +_tx_thread_system_return + + /* Save minimal context on the stack. */ + + STMDB sp!, {r4-r11, lr} // Save minimal context + + /* Pickup the CPU ID. */ + + MRC p15, 0, r10, c0, c0, 5 // Read CPU ID register + AND r10, r10, #0x03 // Mask off, leaving the CPU ID field + LSL r12, r10, #2 // Build offset to array indexes + + LDR r3, =_tx_thread_current_ptr // Pickup address of current ptr + ADD r3, r3, r12 // Build index into current ptr array + LDR r0, [r3, #0] // Pickup current thread pointer + IF {TARGET_FPU_VFP} = {TRUE} + LDR r1, [r0, #160] // Pickup the VFP enabled flag + CMP r1, #0 // Is the VFP enabled? + BEQ _tx_skip_solicited_vfp_save // No, skip VFP solicited save + VMRS r4, FPSCR // Pickup the FPSCR + STR r4, [sp, #-4]! // Save FPSCR + VSTMDB sp!, {D0-D15} // Save D0-D15 +_tx_skip_solicited_vfp_save + ENDIF + MOV r4, #0 // Build a solicited stack type + MRS r5, CPSR // Pickup the CPSR + STMDB sp!, {r4-r5} // Save type and CPSR + + /* Lockout interrupts. */ + + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSID if // Disable IRQ and FIQ interrupts + ELSE + CPSID i // Disable IRQ interrupts + ENDIF + + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + + /* Call the thread exit function to indicate the thread is no longer executing. */ + + MOV r4, r0 // Save r0 + MOV r5, r3 // Save r3 + MOV r6, r12 // Save r12 + BL _tx_execution_thread_exit // Call the thread exit function + MOV r3, r5 // Recover r3 + MOV r0, r4 // Recover r4 + MOV r12,r6 // Recover r12 + ENDIF + + LDR r2, =_tx_timer_time_slice // Pickup address of time slice + ADD r2, r2, r12 // Build index into time-slice array + LDR r1, [r2, #0] // Pickup current time slice + + /* Save current stack and switch to system stack. */ + // _tx_thread_current_ptr[core] -> tx_thread_stack_ptr = sp; + // sp = _tx_thread_system_stack_ptr[core]; + + STR sp, [r0, #8] // Save thread stack pointer + + /* Determine if the time-slice is active. */ + // if (_tx_timer_time_slice[core]) + // { + + MOV r4, #0 // Build clear value + CMP r1, #0 // Is a time-slice active? + BEQ __tx_thread_dont_save_ts // No, don't save the time-slice + + /* Save time-slice for the thread and clear the current time-slice. */ + // _tx_thread_current_ptr[core] -> tx_thread_time_slice = _tx_timer_time_slice[core]; + // _tx_timer_time_slice[core] = 0; + + STR r4, [r2, #0] // Clear time-slice + STR r1, [r0, #24] // Save current time-slice + + // } +__tx_thread_dont_save_ts + + /* Clear the current thread pointer. */ + // _tx_thread_current_ptr[core] = TX_NULL; + + STR r4, [r3, #0] // Clear current thread pointer + + /* Set ready bit in thread control block. */ + + LDR r2, [r0, #152] // Pickup word with ready bit + ORR r2, r2, #0x8000 // Build ready bit set + DMB // Ensure that accesses to shared resource have completed + STR r2, [r0, #152] // Set ready bit + + /* Now clear protection. It is assumed that protection is in force whenever this routine is called. */ + + LDR r3, =_tx_thread_smp_protection // Pickup address of protection structure + + IF :DEF:TX_MPCORE_DEBUG_ENABLE + STR lr, [r3, #24] // Save last caller + LDR r2, [r3, #4] // Pickup owning thread + CMP r0, r2 // Is it the same as the current thread? +__error_loop + BNE __error_loop // If not, we have a problem!! + ENDIF + + LDR r1, =_tx_thread_preempt_disable // Build address to preempt disable flag + MOV r2, #0 // Build clear value + STR r2, [r1, #0] // Clear preempt disable flag + STR r2, [r3, #12] // Clear protection count + MOV r1, #0xFFFFFFFF // Build invalid value + STR r1, [r3, #8] // Set core to an invalid value + DMB // Ensure that accesses to shared resource have completed + STR r2, [r3] // Clear protection + DSB // To ensure update of the shared resource occurs before other CPUs awake + SEV // Send event to other CPUs, wakes anyone waiting on a mutex (using WFE) + + B _tx_thread_schedule // Jump to scheduler! + +// } + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_thread_vectored_context_save.s b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_vectored_context_save.s new file mode 100644 index 00000000..1aa88bcb --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_thread_vectored_context_save.s @@ -0,0 +1,197 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IMPORT _tx_thread_system_state + IMPORT _tx_thread_current_ptr + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + IMPORT _tx_execution_isr_enter + ENDIF + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_vectored_context_save SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function saves the context of an executing thread in the */ +/* beginning of interrupt processing. The function also ensures that */ +/* the system stack is used upon return to the calling ISR. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_vectored_context_save(VOID) +// { + EXPORT _tx_thread_vectored_context_save +_tx_thread_vectored_context_save + + /* Upon entry to this routine, it is assumed that IRQ interrupts are locked + out, we are in IRQ mode, and all registers are intact. */ + + /* Check for a nested interrupt condition. */ + // if (_tx_thread_system_state[core]++) + // { + + IF :DEF:TX_ENABLE_FIQ_SUPPORT + CPSID if // Disable IRQ and FIQ interrupts + ENDIF + + /* Pickup the CPU ID. */ + + MRC p15, 0, r10, c0, c0, 5 // Read CPU ID register + AND r10, r10, #0x03 // Mask off, leaving the CPU ID field + LSL r12, r10, #2 // Build offset to array indexes + + LDR r3, =_tx_thread_system_state // Pickup address of system state var + ADD r3, r3, r12 // Build index into the system state array + LDR r2, [r3, #0] // Pickup system state + CMP r2, #0 // Is this the first interrupt? + BEQ __tx_thread_not_nested_save // Yes, not a nested context save + + /* Nested interrupt condition. */ + + ADD r2, r2, #1 // Increment the interrupt counter + STR r2, [r3, #0] // Store it back in the variable + + /* Note: Minimal context of interrupted thread is already saved. */ + + /* Return to the ISR. */ + + MOV r10, #0 // Clear stack limit + + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + + /* Call the ISR enter function to indicate an ISR is executing. */ + + PUSH {r12, lr} // Save ISR lr & r12 + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r12, lr} // Recover ISR lr & r12 + ENDIF + + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + +__tx_thread_not_nested_save + // } + + /* Otherwise, not nested, check to see if a thread was running. */ + // else if (_tx_thread_current_ptr[core]) + // { + + ADD r2, r2, #1 // Increment the interrupt counter + STR r2, [r3, #0] // Store it back in the variable + LDR r1, =_tx_thread_current_ptr // Pickup address of current thread ptr + ADD r1, r1, r12 // Build index into current thread ptr + LDR r0, [r1, #0] // Pickup current thread pointer + CMP r0, #0 // Is it NULL? + BEQ __tx_thread_idle_system_save // If so, interrupt occurred in + // scheduling loop - nothing needs saving! + + /* Note: Minimal context of interrupted thread is already saved. */ + + /* Save the current stack pointer in the thread's control block. */ + // _tx_thread_current_ptr[core] -> tx_thread_stack_ptr = sp; + + /* Switch to the system stack. */ + // sp = _tx_thread_system_stack_ptr[core]; + + MOV r10, #0 // Clear stack limit + + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + + /* Call the ISR enter function to indicate an ISR is executing. */ + + PUSH {r12, lr} // Save ISR lr & r12 + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r12, lr} // Recover ISR lr & r12 + ENDIF + + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + + // } + // else + // { + +__tx_thread_idle_system_save + + /* Interrupt occurred in the scheduling loop. */ + + /* Not much to do here, just adjust the stack pointer, and return to IRQ + processing. */ + + MOV r10, #0 // Clear stack limit + + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + + /* Call the ISR enter function to indicate an ISR is executing. */ + + PUSH {r12, lr} // Save ISR lr & r12 + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r12, lr} // Recover ISR lr & r12 + ENDIF + + ADD sp, sp, #32 // Recover saved registers + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + + // } +// } + + END diff --git a/ports_smp/cortex_r8_smp/ac5/src/tx_timer_interrupt.s b/ports_smp/cortex_r8_smp/ac5/src/tx_timer_interrupt.s new file mode 100644 index 00000000..87548265 --- /dev/null +++ b/ports_smp/cortex_r8_smp/ac5/src/tx_timer_interrupt.s @@ -0,0 +1,214 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IMPORT _tx_timer_time_slice + IMPORT _tx_timer_system_clock + IMPORT _tx_timer_current_ptr + IMPORT _tx_timer_list_start + IMPORT _tx_timer_list_end + IMPORT _tx_timer_expired_time_slice + IMPORT _tx_timer_expired + IMPORT _tx_thread_time_slice + IMPORT _tx_timer_expiration_process + IMPORT _tx_timer_interrupt_active + IMPORT _tx_thread_smp_protect + IMPORT _tx_thread_smp_unprotect + IMPORT _tx_trace_isr_enter_insert + IMPORT _tx_trace_isr_exit_insert + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt SMP/Cortex-R8/ARM */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* interrupt context save/restore functions are called along with the */ +/* expiration functions. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* _tx_thread_smp_protect Get SMP protection */ +/* _tx_thread_smp_unprotect Releast SMP protection */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Scott Larson Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_timer_interrupt(VOID) +// { + EXPORT _tx_timer_interrupt +_tx_timer_interrupt + + /* Upon entry to this routine, it is assumed that context save has already + been called, and therefore the compiler scratch registers are available + for use. */ + + MRC p15, 0, r0, c0, c0, 5 // Read CPU ID register + AND r0, r0, #0x03 // Mask off, leaving the CPU ID field + CMP r0, #0 // Only process timer interrupts from core 0 (to change this simply change the constant!) + BEQ __tx_process_timer // If the same process the interrupt + BX lr // Return to caller if not matched +__tx_process_timer + + STMDB sp!, {lr, r4} // Save the lr and r4 register on the stack + BL _tx_thread_smp_protect // Get protection + MOV r4, r0 // Save the return value in preserved register + + LDR r1, =_tx_timer_interrupt_active // Pickup address of timer interrupt active count + LDR r0, [r1, #0] // Pickup interrupt active count + ADD r0, r0, #1 // Increment interrupt active count + STR r0, [r1, #0] // Store new interrupt active count + DMB // Ensure that accesses to shared resource have completed + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + + LDR r1, =_tx_timer_system_clock // Pickup address of system clock + LDR r0, [r1, #0] // Pickup system clock + ADD r0, r0, #1 // Increment system clock + STR r0, [r1, #0] // Store new system clock + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CMP r0, #0 // Check for previous timer expiration still active + BNE __tx_timer_done // If so, skip timer processing + LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer addr + LDR r0, [r1, #0] // Pickup current timer + LDR r2, [r0, #0] // Pickup timer list entry + CMP r2, #0 // Is there anything in the list? + BEQ __tx_timer_no_timer // No, just increment the timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + + LDR r3, =_tx_timer_expired // Pickup expiration flag address + MOV r2, #1 // Build expired value + STR r2, [r3, #0] // Set expired flag + B __tx_timer_done // Finished timer processing + + // } + // else + // { +__tx_timer_no_timer + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + ADD r0, r0, #4 // Move to next timer + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + + LDR r3, =_tx_timer_list_end // Pickup addr of timer list end + LDR r2, [r3, #0] // Pickup list end + CMP r0, r2 // Are we at list end? + BNE __tx_timer_skip_wrap // No, skip wrap-around logic + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + + LDR r3, =_tx_timer_list_start // Pickup addr of timer list start + LDR r0, [r3, #0] // Set current pointer to list start + +__tx_timer_skip_wrap + + STR r0, [r1, #0] // Store new current timer pointer + // } + +__tx_timer_done + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CMP r0, #0 // Check for timer expiration + BEQ __tx_timer_dont_activate // If not set, skip timer activation + + /* Process timer expiration. */ + // _tx_timer_expiration_process(); + + BL _tx_timer_expiration_process // Call the timer expiration handling routine + + // } +__tx_timer_dont_activate + + /* Call time-slice processing. */ + // _tx_thread_time_slice(); + + BL _tx_thread_time_slice // Call time-slice processing + + // } + + LDR r1, =_tx_timer_interrupt_active // Pickup address of timer interrupt active count + LDR r0, [r1, #0] // Pickup interrupt active count + SUB r0, r0, #1 // Decrement interrupt active count + STR r0, [r1, #0] // Store new interrupt active count + DMB // Ensure that accesses to shared resource have completed + + /* Release protection. */ + + MOV r0, r4 // Pass the previous status register back + BL _tx_thread_smp_unprotect // Release protection + + LDMIA sp!, {lr, r4} // Recover lr register and r4 + IF {INTER} = {TRUE} + BX lr // Return to caller + ELSE + MOV pc, lr // Return to caller + ENDIF + +// } + END |
