add SMP, Modules, and more processor/tools releases
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
<?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.exe.debug.base.1025296520">
|
||||
|
||||
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.arm.eclipse.build.config.v6.exe.debug.base.1025296520" 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="com.arm.eclipse.builder.armcc.error" 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.debug" cleanCommand="clean" description="" id="com.arm.eclipse.build.config.v6.exe.debug.base.1025296520" name="Debug" parent="com.arm.eclipse.build.config.v6.exe.debug.base">
|
||||
|
||||
<folderInfo id="com.arm.eclipse.build.config.v6.exe.debug.base.1025296520." name="/" resourcePath="">
|
||||
|
||||
<toolChain id="com.arm.toolchain.baremetal.base.var.arm_compiler_5-5.201893790" name="Arm Compiler 5" superClass="com.arm.toolchain.baremetal.base.var.arm_compiler_5-5">
|
||||
|
||||
<option id="com.arm.toolchain.ac5.option.target.cpu_fpu.1232051978" superClass="com.arm.toolchain.ac5.option.target.cpu_fpu" useByScannerDiscovery="false" value="Cortex-A7.NoFPU" valueType="string"/>
|
||||
|
||||
<option id="com.arm.toolchain.ac5.option.fppcs.2122998228" name="Floating-point PCS" superClass="com.arm.toolchain.ac5.option.fppcs" useByScannerDiscovery="false" value="com.arm.tool.c.compiler.option.fppcs.auto" valueType="enumerated"/>
|
||||
|
||||
<option id="com.arm.toolchain.ac5.option.inst.2112129570" 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.base.var.arm_compiler_5-5.201893790.1642424040" name=""/>
|
||||
|
||||
<builder buildPath="${workspace_loc:/sample_threadx}/Debug" id="com.arm.toolchain.baremetal.builder.912959967" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.arm.toolchain.baremetal.builder"/>
|
||||
|
||||
<tool id="com.arm.tool.c.compiler.base.var.arm_compiler_5-5.243810618" name="Arm C Compiler 5" superClass="com.arm.tool.c.compiler.base.var.arm_compiler_5-5">
|
||||
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.arm.tool.c.compiler.option.incpath.1177646787" name="Include path (-I)" superClass="com.arm.tool.c.compiler.option.incpath" useByScannerDiscovery="false" valueType="includePath">
|
||||
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/tx/inc_generic}""/>
|
||||
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/tx/inc_port}""/>
|
||||
|
||||
</option>
|
||||
|
||||
<option defaultValue="com.arm.tool.c.compiler.option.optlevel.min" id="com.arm.tool.c.compiler.option.optlevel.1483521522" name="Optimization level" superClass="com.arm.tool.c.compiler.option.optlevel" useByScannerDiscovery="true" valueType="enumerated"/>
|
||||
|
||||
<option id="com.arm.tool.c.compiler.option.targetcpu.2009194248" name="Target CPU (--cpu)" superClass="com.arm.tool.c.compiler.option.targetcpu" useByScannerDiscovery="true" value="Cortex-A7.no_neon.no_vfp" valueType="string"/>
|
||||
|
||||
<option id="com.arm.tool.c.compiler.option.fppcs.1026748934" name="Floating-point PCS (--apcs)" superClass="com.arm.tool.c.compiler.option.fppcs" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.fppcs.auto" valueType="enumerated"/>
|
||||
|
||||
<option id="com.arm.tool.c.compiler.option.inst.1690533345" name="Instruction set" superClass="com.arm.tool.c.compiler.option.inst" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.inst.arm" valueType="enumerated"/>
|
||||
|
||||
<inputType id="com.arm.tool.c.compiler.input.355482954" superClass="com.arm.tool.c.compiler.input"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="com.arm.tool.cpp.compiler.base.var.arm_compiler_5-5.1770911209" name="Arm C++ Compiler 5" superClass="com.arm.tool.cpp.compiler.base.var.arm_compiler_5-5">
|
||||
|
||||
<option defaultValue="com.arm.tool.c.compiler.option.optlevel.min" id="com.arm.tool.c.compiler.option.optlevel.944779755" name="Optimization level" superClass="com.arm.tool.c.compiler.option.optlevel" useByScannerDiscovery="true" valueType="enumerated"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="com.arm.tool.assembler.base.var.arm_compiler_5-5.727858060" name="Arm Assembler 5" superClass="com.arm.tool.assembler.base.var.arm_compiler_5-5">
|
||||
|
||||
<option id="com.arm.tool.assembler.option.cpu.1412063110" name="Target CPU (--cpu)" superClass="com.arm.tool.assembler.option.cpu" useByScannerDiscovery="true" value="Cortex-A7.no_neon.no_vfp" valueType="string"/>
|
||||
|
||||
<option id="com.arm.tool.assembler.option.fppcs.2012498237" name="Floating-point PCS (--apcs)" superClass="com.arm.tool.assembler.option.fppcs" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.fppcs.auto" valueType="enumerated"/>
|
||||
|
||||
<option id="com.arm.tool.assembler.option.inst.1719595674" name="Instruction set" superClass="com.arm.tool.assembler.option.inst" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.inst.arm" valueType="enumerated"/>
|
||||
|
||||
<inputType id="com.arm.tool.assembler.input.2116363030" superClass="com.arm.tool.assembler.input"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="com.arm.tool.c.linker.base.var.arm_compiler_5-5.2053914540" name="Arm Linker 5" superClass="com.arm.tool.c.linker.base.var.arm_compiler_5-5">
|
||||
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.arm.tool.c.linker.implicit.libs.822740317" name="Implicit other library files" superClass="com.arm.tool.c.linker.implicit.libs" useByScannerDiscovery="false" valueType="libs">
|
||||
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/tx/Debug/tx.a}""/>
|
||||
|
||||
</option>
|
||||
|
||||
<option id="com.arm.tool.c.linker.option.cpu.1721221991" name="Target CPU (--cpu)" superClass="com.arm.tool.c.linker.option.cpu" useByScannerDiscovery="true" value="Cortex-A7.no_neon.no_vfp" valueType="string"/>
|
||||
|
||||
<option id="com.arm.tool.c.linker.option.scatter.1318048594" name="Scatter file (--scatter)" superClass="com.arm.tool.c.linker.option.scatter" useByScannerDiscovery="false" value="../sample_threadx.scat" valueType="string"/>
|
||||
|
||||
<option id="com.arm.tool.c.linker.option.entry.57880806" name="Image entry point (--entry)" superClass="com.arm.tool.c.linker.option.entry" useByScannerDiscovery="false" value="Vectors" valueType="string"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="com.arm.tool.librarian.base.var.arm_compiler_5-5.148057459" name="Arm Librarian 5" superClass="com.arm.tool.librarian.base.var.arm_compiler_5-5"/>
|
||||
|
||||
</toolChain>
|
||||
|
||||
</folderInfo>
|
||||
|
||||
<sourceEntries>
|
||||
|
||||
<entry excluding="exceptions_old.c|reset.S|crt0.S" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
|
||||
|
||||
</sourceEntries>
|
||||
|
||||
</configuration>
|
||||
|
||||
</storageModule>
|
||||
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
|
||||
</cconfiguration>
|
||||
|
||||
<cconfiguration id="com.arm.eclipse.build.config.v6.exe.release.base.1700101495">
|
||||
|
||||
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.arm.eclipse.build.config.v6.exe.release.base.1700101495" 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="com.arm.eclipse.builder.armcc.error" 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.v6.exe.release.base.1700101495" name="Release" parent="com.arm.eclipse.build.config.v6.exe.release.base">
|
||||
|
||||
<folderInfo id="com.arm.eclipse.build.config.v6.exe.release.base.1700101495." name="/" resourcePath="">
|
||||
|
||||
<toolChain id="com.arm.toolchain.v6.exe.release.base.var.arm_compiler_6-6.93780758" name="Arm Compiler 6" superClass="com.arm.toolchain.v6.exe.release.base.var.arm_compiler_6-6">
|
||||
|
||||
<targetPlatform id="com.arm.toolchain.v6.exe.release.base.var.arm_compiler_6-6.93780758.1638782686" name=""/>
|
||||
|
||||
<builder autoBuildTarget="all" buildPath="${workspace_loc:/sample_threadx}/Release" cleanBuildTarget="clean" enableAutoBuild="false" enableCleanBuild="true" enabledIncrementalBuild="true" id="com.arm.toolchain.v6.builder.387488755" incrementalBuildTarget="all" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="false" superClass="com.arm.toolchain.v6.builder"/>
|
||||
|
||||
<tool id="com.arm.tool.c.compiler.v6.base.var.arm_compiler_6-6.1160612426" name="Arm C Compiler 6" superClass="com.arm.tool.c.compiler.v6.base.var.arm_compiler_6-6">
|
||||
|
||||
<option id="com.arm.tool.c.compiler.v6.base.option.optlevel.1619513859" name="Optimization level" superClass="com.arm.tool.c.compiler.v6.base.option.optlevel" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.v6.base.option.optlevel.high" valueType="enumerated"/>
|
||||
|
||||
<inputType id="com.arm.tool.c.compiler.v6.base.input.1399251123" superClass="com.arm.tool.c.compiler.v6.base.input"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="com.arm.tool.cpp.compiler.v6.base.var.arm_compiler_6-6.980720404" name="Arm C++ Compiler 6" superClass="com.arm.tool.cpp.compiler.v6.base.var.arm_compiler_6-6">
|
||||
|
||||
<option id="com.arm.tool.c.compiler.v6.base.option.optlevel.1556967535" name="Optimization level" superClass="com.arm.tool.c.compiler.v6.base.option.optlevel" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.v6.base.option.optlevel.high" valueType="enumerated"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="com.arm.tool.assembler.v6.base.var.arm_compiler_6-6.1952449360" name="Arm Assembler 6" superClass="com.arm.tool.assembler.v6.base.var.arm_compiler_6-6">
|
||||
|
||||
<inputType id="com.arm.tool.assembler.v6.base.input.623890739" superClass="com.arm.tool.assembler.v6.base.input"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="com.arm.tool.c.linker.v6.base.var.arm_compiler_6-6.892368789" name="Arm Linker 6" superClass="com.arm.tool.c.linker.v6.base.var.arm_compiler_6-6"/>
|
||||
|
||||
<tool id="com.arm.tool.librarian.v6.base.var.arm_compiler_6-6.2131111372" name="Arm Librarian 6" superClass="com.arm.tool.librarian.v6.base.var.arm_compiler_6-6"/>
|
||||
|
||||
</toolChain>
|
||||
|
||||
</folderInfo>
|
||||
|
||||
<sourceEntries>
|
||||
|
||||
<entry excluding="exceptions_old.c|reset.S|crt0.S" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
|
||||
|
||||
</sourceEntries>
|
||||
|
||||
</configuration>
|
||||
|
||||
</storageModule>
|
||||
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
|
||||
</cconfiguration>
|
||||
|
||||
</storageModule>
|
||||
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
|
||||
<project id="sample_threadx.com.arm.eclipse.build.project.v6.exe.836597981" name="Executable"/>
|
||||
|
||||
</storageModule>
|
||||
|
||||
<storageModule moduleId="scannerConfiguration">
|
||||
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
|
||||
</storageModule>
|
||||
|
||||
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||
|
||||
<storageModule moduleId="com.arm.projectSettings" version="6.0.0"/>
|
||||
|
||||
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
|
||||
|
||||
<storageModule moduleId="refreshScope" versionNumber="2">
|
||||
|
||||
<configuration configurationName="Debug">
|
||||
|
||||
<resource resourceType="PROJECT" workspacePath="/sample_threadx"/>
|
||||
|
||||
</configuration>
|
||||
|
||||
<configuration configurationName="Release">
|
||||
|
||||
<resource resourceType="PROJECT" workspacePath="/sample_threadx"/>
|
||||
|
||||
</configuration>
|
||||
|
||||
</storageModule>
|
||||
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
|
||||
</cproject>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>sample_threadx</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>com.arm.debug.ds.nature</nature>
|
||||
<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>
|
||||
@@ -0,0 +1,512 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project>
|
||||
|
||||
<configuration id="com.arm.eclipse.build.config.v6.exe.debug.base.1025296520" name="Debug">
|
||||
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
|
||||
<provider class="com.arm.eclipse.builder.armcc.discovery.ArmCompiler5LanguageSettingsProvider" console="false" env-hash="-283985822963804718" id="com.arm.eclipse.builder.armcc.v5.langprovider" keep-relative-paths="false" name="Arm Compiler 5 Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} --list-macros "${INPUTS}"" prefer-non-shared="true" store-entries-with-project="true">
|
||||
|
||||
<language-scope id="com.arm.eclipse.builder.armcc.lang.c"/>
|
||||
|
||||
<language-scope id="com.arm.eclipse.builder.armcc.lang.cpp"/>
|
||||
|
||||
<language id="com.arm.eclipse.builder.armcc.lang.cpp">
|
||||
|
||||
<entry kind="includePath" name="C:/Program Files/ARM/Development Studio 2020.0/sw/ARMCompiler5.06u6/include">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="_BOOL" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__ARMCC_VERSION" value="5060750">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__ARRAY_OPERATORS" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__CC_ARM" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__EDG_IA64_ABI" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__EDG_IA64_ABI_USE_INT_STATIC_INIT_GUARD" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__EDG_IA64_ABI_VARIANT_CTORS_AND_DTORS_RETURN_THIS" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__EDG_PTRDIFF_TYPE__" value="int">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__EDG_RUNTIME_USES_NAMESPACES" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__EDG_SIZE_TYPE__" value="unsigned int">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__EDG_TYPE_TRAITS_ENABLED" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__EDG_VERSION__" value="407">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__EDG__" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__IMPLICIT_INCLUDE" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__OPTIMISE_LEVEL" value="0">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__OPTIMISE_SPACE" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__RTTI" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__SOFTFP__" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__STDC__" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_ARCH_4T" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_ARCH_A64" value="0">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_ARCH_AARCH32" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_ARCH_ARM" value="4">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_ARCH_THUMB" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_CPU_ARM7TDMI" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_EXTENSION_REGISTER_COUNT" value="0">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_HALFWORD" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_MULTIPLY" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_THUMB" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FPU_SOFTVFP" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__a32__" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__arm" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__arm__" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__cplusplus" value="199711L">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__sizeof_int" value="4">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__sizeof_long" value="4">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__sizeof_ptr" value="4">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
</language>
|
||||
|
||||
<language id="com.arm.eclipse.builder.armcc.lang.c">
|
||||
|
||||
<entry kind="includePath" name="C:/Program Files/ARM/Development Studio 2020.0/sw/ARMCompiler5.06u6/include">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__APCS_INTERWORK" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__ARMCC_VERSION" value="5060750">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__CC_ARM" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__EDG_PTRDIFF_TYPE__" value="int">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__EDG_SIZE_TYPE__" value="unsigned int">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__EDG_VERSION__" value="407">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__EDG__" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__OPTIMISE_LEVEL" value="0">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__OPTIMISE_SPACE" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__SOFTFP__" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__STDC_VERSION__" value="199409L">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__STDC__" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_ARCH_7_A" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_ARCH_A64" value="0">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_ARCH_AARCH32" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_ARCH_ARM" value="7">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_ARCH_THUMB" value="4">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_CPU_CORTEX_A7_NO_NEON_NO_VFP" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_CLZ" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_DIVIDE" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_DMB" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_DOUBLEWORD" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_DSPMUL" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_EXTENSION_REGISTER_COUNT" value="0">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_HALFWORD" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_MULTIPLY" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_MULTIPROCESSING" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_THUMB" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FEATURE_UNALIGNED" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_FPU_SOFTVFP" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__TARGET_PROFILE_A" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__a32__" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__arm" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__arm__" value="1">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__sizeof_int" value="4">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__sizeof_long" value="4">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry kind="macro" name="__sizeof_ptr" value="4">
|
||||
|
||||
<flag value="BUILTIN|READONLY"/>
|
||||
|
||||
</entry>
|
||||
|
||||
</language>
|
||||
|
||||
</provider>
|
||||
|
||||
</extension>
|
||||
|
||||
</configuration>
|
||||
|
||||
<configuration id="com.arm.eclipse.build.config.v6.exe.release.base.1700101495" name="Release">
|
||||
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
|
||||
<provider class="com.arm.eclipse.builder.armcc.discovery.ArmCompiler6LanguageSettingsProvider" console="false" env-hash="697562460423706802" id="com.arm.eclipse.builder.armcc.v6.langprovider" keep-relative-paths="false" name="Arm Compiler 6 Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
|
||||
<language-scope id="com.arm.eclipse.builder.armcc.lang.c.ac6"/>
|
||||
|
||||
<language-scope id="com.arm.eclipse.builder.armcc.lang.cpp.ac6"/>
|
||||
|
||||
</provider>
|
||||
|
||||
</extension>
|
||||
|
||||
</configuration>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,74 @@
|
||||
// ------------------------------------------------------------
|
||||
// Cortex-A5 MPCore - Interrupt Controller functions
|
||||
// Header File
|
||||
//
|
||||
// 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.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#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)
|
||||
//
|
||||
|
||||
|
||||
// Global enable of the Interrupt Distributor
|
||||
void enableGIC(void);
|
||||
|
||||
// Global disable of the Interrupt Distributor
|
||||
void disableGIC(void);
|
||||
|
||||
// Enables the interrupt source number ID
|
||||
void enableIntID(unsigned int ID);
|
||||
|
||||
// Disables the interrupt source number ID
|
||||
void disableIntID(unsigned int ID);
|
||||
|
||||
// Sets the priority of the specified ID
|
||||
void setIntPriority(unsigned int ID, unsigned int priority);
|
||||
|
||||
// Enables the processor interface
|
||||
// Must be done on each core separately
|
||||
void enableGICProcessorInterface(void);
|
||||
|
||||
// Disables the processor interface
|
||||
// Must be done on each core separately
|
||||
void disableGICProcessorInterface(void);
|
||||
|
||||
// Sets the Priority mask register for the core run on
|
||||
// The reset value masks ALL interrupts!
|
||||
void setPriorityMask(unsigned int priority);
|
||||
|
||||
// Sets the Binary Point Register for the core run on
|
||||
void setBinaryPoint(unsigned int priority);
|
||||
|
||||
// Returns the value of the Interrupt Acknowledge Register
|
||||
unsigned int readIntAck(void);
|
||||
|
||||
// Writes ID to the End Of Interrupt register
|
||||
void writeEOI(unsigned int ID);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// SGI
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// Send a software generate interrupt
|
||||
void sendSGI(unsigned int ID, unsigned int core_list, unsigned int filter_list);
|
||||
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// End of MP_GIC.h
|
||||
// ------------------------------------------------------------
|
||||
@@ -0,0 +1,289 @@
|
||||
;----------------------------------------------------------------
|
||||
; Copyright (c) 2005-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.
|
||||
;
|
||||
; Cortex-A5MP SMP example - Startup Code
|
||||
;----------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
AREA MP_GIC, CODE, READONLY
|
||||
|
||||
;----------------------------------------------------------------
|
||||
; GIC. Generic Interrupt Controller Architecture Specification
|
||||
;----------------------------------------------------------------
|
||||
|
||||
; 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:
|
||||
; enableIntID(X) <-- Enable that ID
|
||||
; setIntPriority(X, 0) <-- Set the priority of X to 0 (the max priority)
|
||||
; setPriorityMask(0x1F) <-- Set CPU's priority mask to 0x1F (the lowest priority)
|
||||
; enableGIC() <-- Enable the GIC (global)
|
||||
; enableGICProcessorInterface() <-- Enable the CPU interface (local to the CPU)
|
||||
|
||||
|
||||
EXPORT enableGIC
|
||||
; void enableGIC(void)
|
||||
; Global enable of the Interrupt Distributor
|
||||
enableGIC PROC
|
||||
; Get base address of private peripheral 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 Enable Register (ICDDCR)
|
||||
ORR r1, r1, #0x01 ; Set bit 0, the enable bit
|
||||
STR r1, [r0] ; Write the GIC Enable Register (ICDDCR)
|
||||
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT disableGIC
|
||||
; void disableGIC(void)
|
||||
; Global disable of the Interrupt Distributor
|
||||
disableGIC PROC
|
||||
; Get base address of private peripheral 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 Enable Register (ICDDCR)
|
||||
BIC r1, r1, #0x01 ; Clear bit 0, the enable bit
|
||||
STR r1, [r0] ; Write the GIC Enable Register (ICDDCR)
|
||||
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT enableIntID
|
||||
; void enableIntID(unsigned int ID)
|
||||
; Enables the interrupt source number ID
|
||||
enableIntID PROC
|
||||
; Get base address of private peripheral 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 convert 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 32-bit 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 disableIntID
|
||||
; void disableIntID(unsigned int ID)
|
||||
; Disables the interrupt source number ID
|
||||
disableIntID PROC
|
||||
; Get base address of private peripheral 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 convert 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 32-bit 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 setIntPriority
|
||||
; void setIntPriority(unsigned int ID, unsigned int priority)
|
||||
; Sets the priority of the specified ID
|
||||
; r0 = ID
|
||||
; r1 = priority
|
||||
setIntPriority PROC
|
||||
; Get base address of private peripheral 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 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 two 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 ; 8 bit field mask
|
||||
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 appropriate field
|
||||
ORR r3, r3, r1 ; Now OR in the priority value
|
||||
STR r3, [r0] ; And store it back again (ICDIPR)
|
||||
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT enableGICProcessorInterface
|
||||
; void enableGICProcessorInterface(void)
|
||||
; Enables the processor interface
|
||||
; Must be done on each core separately
|
||||
enableGICProcessorInterface PROC
|
||||
MRC p15, 4, r0, c15, c0, 0 ; Read periph base address
|
||||
ADD r0, r0, #0x2000
|
||||
|
||||
LDR r1, [r0, #0x0] ; Read the Processor Interface Control register (ICCICR/ICPICR)
|
||||
ORR r1, r1, #0x03 ; Bit 0: Enables secure interrupts, Bit 1: Enables Non-Secure interrupts
|
||||
BIC r1, r1, #0x08 ; Bit 3: Ensure Group 0 interrupts are signalled using IRQ, not FIQ
|
||||
STR r1, [r0, #0x0] ; Write the Processor Interface Control register (ICCICR/ICPICR)
|
||||
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT disableGICProcessorInterface
|
||||
; void disableGICProcessorInterface(void)
|
||||
; Disables the processor interface
|
||||
; Must be done on each core separately
|
||||
disableGICProcessorInterface PROC
|
||||
|
||||
MRC p15, 4, r0, c15, c0, 0 ; Read periph base address
|
||||
ADD r0, r0, #0x2000
|
||||
|
||||
LDR r1, [r0, #0x0] ; 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, #0x0] ; Write the Processor Interface Control register (ICCICR/ICPICR)
|
||||
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT setPriorityMask
|
||||
; void setPriorityMask(unsigned int priority)
|
||||
; Sets the Priority mask register for the CPU run on
|
||||
; The reset value masks ALL interrupts!
|
||||
setPriorityMask PROC
|
||||
|
||||
; Get base address of private peripheral space
|
||||
MRC p15, 4, r1, c15, c0, 0 ; Read periph base address
|
||||
ADD r1, r1, #0x2000
|
||||
|
||||
STR r0, [r1, #0x4] ; Write the Priority Mask register (ICCPMR/ICCIPMR)
|
||||
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT setBinaryPoint
|
||||
; void setBinaryPoint(unsigned int priority)
|
||||
; Sets the Binary Point Register for the CPU run on
|
||||
setBinaryPoint PROC
|
||||
|
||||
; Get base address of private peripheral space
|
||||
MRC p15, 4, r1, c15, c0, 0 ; Read periph base address
|
||||
ADD r1, r1, #0x2000
|
||||
|
||||
STR r0, [r1, #0x8] ; Write the Binary register (ICCBPR/ICCBPR)
|
||||
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT readIntAck
|
||||
; unsigned int readIntAck(void)
|
||||
; Returns the value of the Interrupt Acknowledge Register
|
||||
readIntAck PROC
|
||||
MRC p15, 4, r0, c15, c0, 0 ; Read periph base address
|
||||
ADD r0, r0, #0x2000
|
||||
|
||||
LDR r0, [r0, #0xC] ; Read the Interrupt Acknowledge Register (ICCIAR)
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT writeEOI
|
||||
; void writeEOI(unsigned int ID)
|
||||
; Writes ID to the End Of Interrupt register
|
||||
writeEOI PROC
|
||||
|
||||
; Get base address of private peripheral space
|
||||
MRC p15, 4, r1, c15, c0, 0 ; Read periph base address
|
||||
ADD r1, r1, #0x2000
|
||||
|
||||
STR r0, [r1, #0x10] ; Write ID to the End of Interrupt register (ICCEOIR)
|
||||
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
;----------------------------------------------------------------
|
||||
; SGI
|
||||
;----------------------------------------------------------------
|
||||
|
||||
EXPORT sendSGI
|
||||
; void sendSGI(unsigned int ID, unsigned int target_list, unsigned int filter_list);
|
||||
; Send a software generate interrupt
|
||||
sendSGI 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
|
||||
|
||||
;----------------------------------------------------------------
|
||||
; End of MP_GIC.s
|
||||
;----------------------------------------------------------------
|
||||
@@ -0,0 +1,40 @@
|
||||
// ------------------------------------------------------------
|
||||
// MP Mutex Header File
|
||||
//
|
||||
// Copyright (c) 2011-2014 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.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#ifndef MP_MUTEX_H
|
||||
#define MP_MUTEX_H
|
||||
|
||||
// 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 initMutex(mutex_t* pMutex);
|
||||
|
||||
// Blocking call, returns once successfully locked a mutex
|
||||
// r0 = address of mutex_t
|
||||
void lockMutex(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 unlockMutex(mutex_t* pMutex);
|
||||
|
||||
// Returns 0x0 if mutex unlocked, 0x1 is locked
|
||||
// r0 = address of mutex_t
|
||||
unsigned int isMutexLocked(mutex_t* pMutex);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,123 @@
|
||||
; ------------------------------------------------------------
|
||||
; Cortex-A MPCore - Mutex Code
|
||||
;
|
||||
; Copyright (c) 2011-2012 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.
|
||||
; ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
AREA MP_Mutexes, CODE, READONLY
|
||||
|
||||
;NOTES
|
||||
; struct mutex_t defined in MP_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 initMutex
|
||||
; void initMutex(mutex_t* pMutex)
|
||||
; Places mutex into a known state
|
||||
; r0 = address of mutex_t
|
||||
initMutex PROC
|
||||
|
||||
MOV r1, #UNLOCKED ; Mark as unlocked
|
||||
STR r1, [r0]
|
||||
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT lockMutex
|
||||
; void lockMutex(mutex_t* pMutex)
|
||||
; Blocking call, returns once successfully locked a mutex
|
||||
; r0 = address of mutex_t
|
||||
lockMutex 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 lockMutex ; 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 whether store completed successfully (0=succeeded)
|
||||
BNE lockMutex ; If store failed, go back to beginning and try again
|
||||
|
||||
DMB
|
||||
|
||||
BX lr ; Return as mutex is now locked by this cpu
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT unlockMutex
|
||||
; unsigned int unlockMutex(mutex_t* pMutex)
|
||||
; Releases mutex, returns 0x0 for success and 0x1 for failure
|
||||
; r0 = address of mutex_t
|
||||
unlockMutex 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]
|
||||
|
||||
DSB ; Ensure that no instructions following the barrier execute until
|
||||
; all memory accesses prior to the barrier have completed.
|
||||
|
||||
SEV ; Send event to other CPUs, wakes anyone waiting on a mutex (using WFE)
|
||||
|
||||
MOV r0, #0x0 ; Return "success"
|
||||
BX lr
|
||||
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT isMutexLocked
|
||||
; unsigned int isMutexLocked(mutex_t* pMutex)
|
||||
; Returns 0x0 if mutex unlocked, 0x1 is locked
|
||||
; r0 = address of mutex_t
|
||||
isMutexLocked PROC
|
||||
LDR r0, [r0]
|
||||
CMP r0, #UNLOCKED
|
||||
MOVEQ r0, #0x0
|
||||
MOVNE r0, #0x1
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
|
||||
END
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; End of MP_Mutexes.s
|
||||
; ------------------------------------------------------------
|
||||
@@ -0,0 +1,55 @@
|
||||
// ------------------------------------------------------------
|
||||
// Cortex-A9 MPCore - Snoop Control Unit
|
||||
// Header File
|
||||
//
|
||||
// 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.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#ifndef _CORTEXA_SCU_
|
||||
#define _CORTEXA_SCU_
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Misc
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// Returns the number of cores in the cluster
|
||||
// This is the format of the register, decided to leave it unchanged.
|
||||
unsigned int getNumCPUs(void);
|
||||
|
||||
// Go to sleep, never returns
|
||||
void goToSleep(void);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// SCU
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// Enables the SCU
|
||||
void enableSCU(void);
|
||||
|
||||
// The return value is 1 bit per core:
|
||||
// bit 0 - CPU 0
|
||||
// bit 1 - CPU 1
|
||||
// etc...
|
||||
unsigned int getCPUsInSMP(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 enableMaintenanceBroadcast(void);
|
||||
|
||||
// Disable the broadcasting of cache & TLB maintenance operations
|
||||
void disableMaintenanceBroadcast(void);
|
||||
|
||||
// cpu: 0x0=CPU 0 0x1=CPU 1 etc...
|
||||
// This function invalidates the SCU copy of the tag rams
|
||||
// for the specified core.
|
||||
void secureSCUInvalidate(unsigned int cpu, unsigned int ways);
|
||||
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// End of MP_SCU.h
|
||||
// ------------------------------------------------------------
|
||||
@@ -0,0 +1,132 @@
|
||||
;----------------------------------------------------------------
|
||||
; Copyright (c) 2005-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.
|
||||
;
|
||||
; Cortex-A SMP example - Startup Code
|
||||
;----------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
AREA MP_SCU, CODE, READONLY
|
||||
|
||||
;----------------------------------------------------------------
|
||||
; Misc
|
||||
;----------------------------------------------------------------
|
||||
|
||||
EXPORT getNumCPUs
|
||||
; unsigned int getNumCPUs(void)
|
||||
; Returns the number of CPUs in the Cluster
|
||||
getNumCPUs PROC
|
||||
|
||||
; Get base address of private peripheral 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-1
|
||||
ADD r0, r0, #1
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
;----------------------------------------------------------------
|
||||
; SCU
|
||||
;----------------------------------------------------------------
|
||||
|
||||
; SCU offset from base of private peripheral space --> 0x000
|
||||
|
||||
EXPORT enableSCU
|
||||
; void enableSCU(void)
|
||||
; Enables the SCU
|
||||
enableSCU 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 getCPUsInSMP
|
||||
; unsigned int getCPUsInSMP(void)
|
||||
; The return value is 1 bit per core:
|
||||
; bit 0 - CPU 0
|
||||
; bit 1 - CPU 1
|
||||
; etc...
|
||||
getCPUsInSMP 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 enableMaintenanceBroadcast
|
||||
; void enableMaintenanceBroadcast(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
|
||||
enableMaintenanceBroadcast PROC
|
||||
MRC p15, 0, r0, c1, c0, 1 ; Read Aux Ctrl register
|
||||
MOV r1, r0
|
||||
ORR r0, r0, #0x01 ; Set the FW bit (bit 0)
|
||||
CMP r0, r1
|
||||
MCRNE p15, 0, r0, c1, c0, 1 ; Write Aux Ctrl register
|
||||
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT disableMaintenanceBroadcast
|
||||
; void disableMaintenanceBroadcast(void)
|
||||
; Disable the broadcasting of cache & TLB maintenance operations
|
||||
disableMaintenanceBroadcast 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 secureSCUInvalidate
|
||||
; void secureSCUInvalidate(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
|
||||
secureSCUInvalidate 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
|
||||
|
||||
;----------------------------------------------------------------
|
||||
; End of MP_SCU.s
|
||||
;----------------------------------------------------------------
|
||||
@@ -0,0 +1,381 @@
|
||||
/* 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 = TX_NULL;
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="com.arm.debugger.launcher2">
|
||||
<mapAttribute key="AverageDurationTracker">
|
||||
<mapEntry key="*Fetching Data Model" value="3089300"/>
|
||||
<mapEntry key="*list global low level symbols" value="50325749"/>
|
||||
<mapEntry key="*loading values from target" value="4206485"/>
|
||||
<mapEntry key="*updating expressions" value="13677927"/>
|
||||
<mapEntry key="AddEventObserver" value="13189200"/>
|
||||
<mapEntry key="compute execution mode" value="810250"/>
|
||||
<mapEntry key="continue" value="14755693"/>
|
||||
<mapEntry key="get capabilities" value="350300"/>
|
||||
<mapEntry key="get execution addresss" value="553397"/>
|
||||
<mapEntry key="get source lines" value="521294"/>
|
||||
<mapEntry key="initialize command help" value="146662199"/>
|
||||
<mapEntry key="interrupt" value="17832562"/>
|
||||
<mapEntry key="list breakpoint options" value="3818700"/>
|
||||
<mapEntry key="list breakpoints" value="2020701"/>
|
||||
<mapEntry key="list instruction sets" value="3562000"/>
|
||||
<mapEntry key="list signals" value="2717801"/>
|
||||
<mapEntry key="list watchpoint options" value="7474100"/>
|
||||
<mapEntry key="list watchpoints" value="1665400"/>
|
||||
<mapEntry key="loadfile" value="370051799"/>
|
||||
<mapEntry key="set CWD" value="9526000"/>
|
||||
<mapEntry key="set debug-from" value="10212501"/>
|
||||
<mapEntry key="start" value="297199401"/>
|
||||
<mapEntry key="waitForTargetToStop" value="85660000"/>
|
||||
</mapAttribute>
|
||||
<intAttribute key="DEBUG_TAB..RESOURCES.COUNT" value="0"/>
|
||||
<intAttribute key="FILES.CONNECT_TO_GDB_SERVER.RESOURCES.COUNT" value="0"/>
|
||||
<intAttribute key="FILES.DEBUG_EXISTING_ANDROID.RESOURCES.COUNT" value="0"/>
|
||||
<listAttribute key="FILES.DEBUG_RESIDENT_ANDROID"/>
|
||||
<stringAttribute key="FILES.DEBUG_RESIDENT_ANDROID.RESOURCES.0.TYPE" value="TARGET_WORKING_DIR"/>
|
||||
<stringAttribute key="FILES.DEBUG_RESIDENT_ANDROID.RESOURCES.0.VALUE" value=""/>
|
||||
<intAttribute key="FILES.DEBUG_RESIDENT_ANDROID.RESOURCES.COUNT" value="1"/>
|
||||
<listAttribute key="FILES.DEBUG_RESIDENT_APP"/>
|
||||
<stringAttribute key="FILES.DEBUG_RESIDENT_APP.RESOURCES.0.TYPE" value="TARGET_WORKING_DIR"/>
|
||||
<stringAttribute key="FILES.DEBUG_RESIDENT_APP.RESOURCES.0.VALUE" value=""/>
|
||||
<stringAttribute key="FILES.DEBUG_RESIDENT_APP.RESOURCES.1.TYPE" value="APPLICATION_ON_TARGET"/>
|
||||
<stringAttribute key="FILES.DEBUG_RESIDENT_APP.RESOURCES.1.VALUE" value=""/>
|
||||
<intAttribute key="FILES.DEBUG_RESIDENT_APP.RESOURCES.COUNT" value="2"/>
|
||||
<listAttribute key="FILES.DOWNLOAD_AND_DEBUG"/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_AND_DEBUG.RESOURCES.0.OPTION.ALSO_LOAD_SYMBOLS" value="true"/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_AND_DEBUG.RESOURCES.0.OPTION.ON_DEMAND_LOAD" value="true"/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_AND_DEBUG.RESOURCES.0.TYPE" value="APP_ON_HOST_TO_DOWNLOAD"/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_AND_DEBUG.RESOURCES.0.VALUE" value=""/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_AND_DEBUG.RESOURCES.1.TYPE" value="TARGET_WORKING_DIR"/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_AND_DEBUG.RESOURCES.1.VALUE" value=""/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_AND_DEBUG.RESOURCES.2.TYPE" value="TARGET_DOWNLOAD_DIR"/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_AND_DEBUG.RESOURCES.2.VALUE" value=""/>
|
||||
<intAttribute key="FILES.DOWNLOAD_AND_DEBUG.RESOURCES.COUNT" value="3"/>
|
||||
<listAttribute key="FILES.DOWNLOAD_DEBUG"/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_DEBUG.RESOURCES.0.OPTION.ALSO_LOAD_SYMBOLS" value="true"/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_DEBUG.RESOURCES.0.OPTION.ON_DEMAND_LOAD" value="true"/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_DEBUG.RESOURCES.0.TYPE" value="APP_ON_HOST_TO_DOWNLOAD"/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_DEBUG.RESOURCES.0.VALUE" value=""/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_DEBUG.RESOURCES.1.TYPE" value="TARGET_WORKING_DIR"/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_DEBUG.RESOURCES.1.VALUE" value=""/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_DEBUG.RESOURCES.2.TYPE" value="TARGET_DOWNLOAD_DIR"/>
|
||||
<stringAttribute key="FILES.DOWNLOAD_DEBUG.RESOURCES.2.VALUE" value=""/>
|
||||
<intAttribute key="FILES.DOWNLOAD_DEBUG.RESOURCES.COUNT" value="3"/>
|
||||
<intAttribute key="FILES.DOWNLOAD_DEBUG_ANDROID.RESOURCES.COUNT" value="0"/>
|
||||
<listAttribute key="FILES.ICE_DEBUG">
|
||||
<listEntry value="ON_DEMAND_LOAD"/>
|
||||
<listEntry value="ALSO_LOAD_SYMBOLS"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="FILES.ICE_DEBUG.RESOURCES.0.OPTION.ALSO_LOAD_SYMBOLS" value="true"/>
|
||||
<stringAttribute key="FILES.ICE_DEBUG.RESOURCES.0.OPTION.ON_DEMAND_LOAD" value="true"/>
|
||||
<stringAttribute key="FILES.ICE_DEBUG.RESOURCES.0.TYPE" value="APP_ON_HOST_TO_DOWNLOAD"/>
|
||||
<stringAttribute key="FILES.ICE_DEBUG.RESOURCES.0.VALUE" value="${workspace_loc:/sample_threadx/Debug/sample_threadx.axf}"/>
|
||||
<intAttribute key="FILES.ICE_DEBUG.RESOURCES.COUNT" value="1"/>
|
||||
<listAttribute key="FILES.ICE_DEBUG_WITH_ETB_TRACE">
|
||||
<listEntry value="ON_DEMAND_LOAD"/>
|
||||
<listEntry value="ALSO_LOAD_SYMBOLS"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="FILES.ICE_DEBUG_WITH_ETB_TRACE.RESOURCES.0.OPTION.ALSO_LOAD_SYMBOLS" value="true"/>
|
||||
<stringAttribute key="FILES.ICE_DEBUG_WITH_ETB_TRACE.RESOURCES.0.OPTION.ON_DEMAND_LOAD" value="true"/>
|
||||
<stringAttribute key="FILES.ICE_DEBUG_WITH_ETB_TRACE.RESOURCES.0.TYPE" value="APP_ON_HOST_TO_DOWNLOAD"/>
|
||||
<stringAttribute key="FILES.ICE_DEBUG_WITH_ETB_TRACE.RESOURCES.0.VALUE" value=""/>
|
||||
<intAttribute key="FILES.ICE_DEBUG_WITH_ETB_TRACE.RESOURCES.COUNT" value="1"/>
|
||||
<listAttribute key="FILES.ICE_DEBUG_WITH_TRACE">
|
||||
<listEntry value="ON_DEMAND_LOAD"/>
|
||||
<listEntry value="ALSO_LOAD_SYMBOLS"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="FILES.ICE_DEBUG_WITH_TRACE.RESOURCES.0.OPTION.ALSO_LOAD_SYMBOLS" value="true"/>
|
||||
<stringAttribute key="FILES.ICE_DEBUG_WITH_TRACE.RESOURCES.0.OPTION.ON_DEMAND_LOAD" value="true"/>
|
||||
<stringAttribute key="FILES.ICE_DEBUG_WITH_TRACE.RESOURCES.0.TYPE" value="APP_ON_HOST_TO_DOWNLOAD"/>
|
||||
<stringAttribute key="FILES.ICE_DEBUG_WITH_TRACE.RESOURCES.0.VALUE" value=""/>
|
||||
<intAttribute key="FILES.ICE_DEBUG_WITH_TRACE.RESOURCES.COUNT" value="1"/>
|
||||
<stringAttribute key="FILES.SELECTED_DEBUG_OPEATION" value="ICE_DEBUG"/>
|
||||
<stringAttribute key="HOST_WORKING_DIR" value="${workspace_loc}"/>
|
||||
<booleanAttribute key="HOST_WORKING_DIR_USE_DEFAULT" value="true"/>
|
||||
<booleanAttribute key="KEY_COMMANDS_AFTER_CONNECT" value="false"/>
|
||||
<stringAttribute key="KEY_COMMANDS_AFTER_CONNECT_TEXT" value=""/>
|
||||
<booleanAttribute key="KEY_COMMANDS_AS_CONNECT" value="false"/>
|
||||
<booleanAttribute key="RSE_USE_HOSTNAME" value="true"/>
|
||||
<stringAttribute key="TCP_DISABLE_EXTENDED_MODE" value="true"/>
|
||||
<booleanAttribute key="TCP_KILL_ON_EXIT" value="false"/>
|
||||
<booleanAttribute key="VFS_ENABLED" value="true"/>
|
||||
<stringAttribute key="VFS_LOCAL_DIR" value="${workspace_loc}"/>
|
||||
<stringAttribute key="VFS_REMOTE_MOUNT" value="/writeable"/>
|
||||
<stringAttribute key="breakpoints" value="<?xml version="1.0" encoding="UTF-8"?> <breakpoints order="ALPHA"> </breakpoints> "/>
|
||||
<stringAttribute key="config_db_activity_name" value="ARM_Cortex-A7x4 SMP"/>
|
||||
<stringAttribute key="config_db_connection_keys" value="dtsl_config dtsl_tracecapture_option dtsl_config_script model_params config_file setup TCP_KILL_ON_EXIT TCP_DISABLE_EXTENDED_MODE"/>
|
||||
<stringAttribute key="config_db_connection_type" value="Bare Metal Debug"/>
|
||||
<stringAttribute key="config_db_platform_name" value="Arm FVP - VE_Cortex_A7x4"/>
|
||||
<stringAttribute key="config_db_project_type" value="Bare Metal Debug"/>
|
||||
<stringAttribute key="config_db_project_type_id" value="BARE_METAL"/>
|
||||
<stringAttribute key="config_db_taxonomy_id" value="/platform/armfvp/ve_cortex_a7x4"/>
|
||||
<stringAttribute key="config_file" value="CDB://cadi_config.xml"/>
|
||||
<booleanAttribute key="connectOnly" value="false"/>
|
||||
<listAttribute key="debugger.view.ExpressionsView">
|
||||
<listEntry value="thread_0_counter"/>
|
||||
<listEntry value="thread_1_counter"/>
|
||||
<listEntry value="thread_2_counter"/>
|
||||
<listEntry value="thread_3_counter"/>
|
||||
<listEntry value="thread_4_counter"/>
|
||||
<listEntry value="thread_5_counter"/>
|
||||
<listEntry value="thread_6_counter"/>
|
||||
<listEntry value="thread_7_counter"/>
|
||||
</listAttribute>
|
||||
<mapAttribute key="debugger.view.ExpressionsView.ExpressionsData">
|
||||
<mapEntry key="0" value="NODE_TRANSFER_ELEMENT_COUNT,0;NODE_TRANSFER_ELEMENT_SIZE_IN_BYTES,4;NODE_TYPE,VALUE;FORMATTER,Unsigned Decimal"/>
|
||||
<mapEntry key="1" value="NODE_TRANSFER_ELEMENT_COUNT,0;NODE_TRANSFER_ELEMENT_SIZE_IN_BYTES,4;NODE_TYPE,VALUE;FORMATTER,Unsigned Decimal"/>
|
||||
<mapEntry key="2" value="NODE_TRANSFER_ELEMENT_COUNT,0;NODE_TRANSFER_ELEMENT_SIZE_IN_BYTES,4;NODE_TYPE,VALUE;FORMATTER,Unsigned Decimal"/>
|
||||
<mapEntry key="3" value="NODE_TRANSFER_ELEMENT_COUNT,0;NODE_TRANSFER_ELEMENT_SIZE_IN_BYTES,4;NODE_TYPE,VALUE;FORMATTER,Unsigned Decimal"/>
|
||||
<mapEntry key="4" value="NODE_TRANSFER_ELEMENT_COUNT,0;NODE_TRANSFER_ELEMENT_SIZE_IN_BYTES,4;NODE_TYPE,VALUE;FORMATTER,Unsigned Decimal"/>
|
||||
<mapEntry key="5" value="NODE_TRANSFER_ELEMENT_COUNT,0;NODE_TRANSFER_ELEMENT_SIZE_IN_BYTES,4;NODE_TYPE,VALUE;FORMATTER,Unsigned Decimal"/>
|
||||
<mapEntry key="6" value="NODE_TRANSFER_ELEMENT_COUNT,0;NODE_TRANSFER_ELEMENT_SIZE_IN_BYTES,4;NODE_TYPE,VALUE;FORMATTER,Unsigned Decimal"/>
|
||||
<mapEntry key="7" value="NODE_TRANSFER_ELEMENT_COUNT,0;NODE_TRANSFER_ELEMENT_SIZE_IN_BYTES,4;NODE_TYPE,VALUE;FORMATTER,Unsigned Decimal"/>
|
||||
</mapAttribute>
|
||||
<stringAttribute key="debugger.view.ExpressionsView:DebugOutlineColumnState" value="OutlineConfig1	8	0	true	true	187	-1	true	1	false	true	90	-1	true	2	true	true	108	-1	true	3	true	true	57	-1	true	4	true	true	50	-1	true	5	true	true	37	-1	true	6	true	true	87	-1	true	7	true	true	53	-1	true"/>
|
||||
<booleanAttribute key="debugger.view.expression.DrawAsHex" value="false"/>
|
||||
<stringAttribute key="dtsl_config" value="DtslScript"/>
|
||||
<stringAttribute key="dtsl_config_script" value="CDB://dtsl_config_script.py"/>
|
||||
<stringAttribute key="dtsl_options_file" value="default"/>
|
||||
<stringAttribute key="dtsl_tracecapture_option" value="options.traceBuffer.traceCaptureDevice"/>
|
||||
<stringAttribute key="launch_configuration_version" value="2020.0"/>
|
||||
<booleanAttribute key="linuxOS" value="false"/>
|
||||
<stringAttribute key="model_params" value=""/>
|
||||
<booleanAttribute key="runAfterConnect" value="false"/>
|
||||
<listAttribute key="setup">
|
||||
<listEntry value="CDB://Scripts/rtsm_launcher.py"/>
|
||||
<listEntry value="FVP_VE_Cortex-A7x4"/>
|
||||
</listAttribute>
|
||||
<booleanAttribute key="single_platform" value="true"/>
|
||||
<stringAttribute key="stopAtExpression" value="*$ENTRYPOINT"/>
|
||||
<stringAttribute key="watchpoints" value="<?xml version="1.0" encoding="UTF-8"?> <watchpoints> </watchpoints> "/>
|
||||
</launchConfiguration>
|
||||
@@ -0,0 +1,37 @@
|
||||
;**************************************************
|
||||
; Copyright (c) 2012 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.
|
||||
;**************************************************
|
||||
|
||||
; Scatter-file for Cortex-A5 MPCore bare-metal example on Versatile Express
|
||||
|
||||
; This scatter-file places application code, data, stack and heap at suitable addresses in memory map.
|
||||
|
||||
; CoreTile Express A5x2 has 1GB SDRAM at 0x80000000 to 0xBFFFFFFF, which this scatter-file uses.
|
||||
|
||||
LOAD 0x80000000 0x00010000
|
||||
{
|
||||
EXEC +0
|
||||
{
|
||||
startup.o (StartUp, +FIRST)
|
||||
* (+RO)
|
||||
}
|
||||
|
||||
; App heap for all CPUs
|
||||
ARM_LIB_HEAP +0 ALIGN 8 EMPTY 0x8000 {}
|
||||
|
||||
; App stacks for all CPUs - see startup.s
|
||||
ARM_LIB_STACK +0 ALIGN 8 EMPTY 4*0x4000 {}
|
||||
|
||||
; IRQ stacks for all CPUs - see startup.s
|
||||
IRQ_STACKS +0 ALIGN 8 EMPTY 4*1024 {}
|
||||
|
||||
SHARED_DATA +0x0
|
||||
{
|
||||
* (+RW,+ZI)
|
||||
}
|
||||
|
||||
PAGETABLES 0x80500000 EMPTY 0x00100000 {}
|
||||
}
|
||||
@@ -0,0 +1,580 @@
|
||||
; ------------------------------------------------------------
|
||||
; Cortex-A5 MPCore Startup Code
|
||||
;
|
||||
; 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.
|
||||
; ------------------------------------------------------------
|
||||
|
||||
PRESERVE8
|
||||
|
||||
AREA StartUp,CODE,READONLY
|
||||
|
||||
; 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 readIntAck
|
||||
IMPORT writeEOI
|
||||
IMPORT enableGIC
|
||||
IMPORT enableGICProcessorInterface
|
||||
IMPORT setPriorityMask
|
||||
IMPORT enableIntID
|
||||
IMPORT setIntPriority
|
||||
IMPORT enableSCU
|
||||
IMPORT joinSMP
|
||||
IMPORT secureSCUInvalidate
|
||||
IMPORT enableMaintenanceBroadcast
|
||||
IMPORT invalidateCaches
|
||||
IMPORT disableHighVecs
|
||||
IMPORT __main
|
||||
; IMPORT main_app
|
||||
; [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]
|
||||
|
||||
IMPORT __use_two_region_memory
|
||||
IMPORT ||Image$$ARM_LIB_STACK$$ZI$$Limit||
|
||||
IMPORT ||Image$$IRQ_STACKS$$ZI$$Limit||
|
||||
IMPORT ||Image$$PAGETABLES$$ZI$$Base||
|
||||
IMPORT ||Image$$EXEC$$Base||
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; 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 readIntAck
|
||||
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]
|
||||
|
||||
; Set new timeout value for the timer, which clears the interrupt.
|
||||
MOV r0, #0xF0000
|
||||
MCR p15, 0, r0, c14, c2, 0 ; Setup timeout value (CNTP_TVAL)
|
||||
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 writeEOI
|
||||
|
||||
; [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
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT Reset_Handler
|
||||
Reset_Handler PROC {}
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; Disable caches and MMU in case they were 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, #(0x1 << 12) ; Clear I, bit 12, to disable I Cache
|
||||
BIC r0, r0, #(0x1 << 2) ; Clear C, bit 2, to disable D Cache
|
||||
BIC r0, r0, #(0x1 << 1) ; Clear A, bit 1, to disable strict alignment fault checking
|
||||
BIC r0, r0, #0x1 ; Clear M, bit 0, to disable MMU
|
||||
MCR p15, 0, r0, c1, c0, 0 ; Write System Control Register
|
||||
ISB
|
||||
|
||||
; The MMU is enabled later, before calling main(). Caches are enabled inside main(),
|
||||
; after the MMU has been enabled and scatterloading has been performed.
|
||||
|
||||
;
|
||||
; Setup stacks
|
||||
;---------------
|
||||
|
||||
MRC p15, 0, r0, c0, c0, 5 ; Read CPU ID register
|
||||
ANDS r0, r0, #0x03 ; Mask off, leaving the CPU ID field
|
||||
|
||||
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
|
||||
LDR r1, =||Image$$IRQ_STACKS$$ZI$$Limit||
|
||||
SUB r1, r1, r0, LSL #10 ; 1024 bytes of IRQ stack per CPU - see scatter.scat
|
||||
MOV sp, r1
|
||||
|
||||
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit ; Interrupts initially disabled
|
||||
LDR r1, =||Image$$ARM_LIB_STACK$$ZI$$Limit|| ; App stacks for all CPUs
|
||||
SUB r1, r1, r0, LSL #14 ; 0x4000 bytes of App stack per CPU - see scatter.scat
|
||||
MOV sp, r1
|
||||
|
||||
;
|
||||
; Set vector base address
|
||||
; ------------------------
|
||||
LDR r0, =Vectors
|
||||
MCR p15, 0, r0, c12, c0, 0 ; Write Secure or Non-secure Vector Base Address
|
||||
BL disableHighVecs ; Ensure that V-bit is cleared
|
||||
|
||||
;
|
||||
; Invalidate caches
|
||||
; ------------------
|
||||
BL invalidateCaches
|
||||
|
||||
;
|
||||
; Clear Branch Prediction Array
|
||||
; ------------------------------
|
||||
MOV r0, #0x0
|
||||
MCR p15, 0, r0, c7, c5, 6 ; BPIALL - Invalidate entire branch predictor array
|
||||
|
||||
;
|
||||
; Invalidate TLBs
|
||||
;------------------
|
||||
MOV r0, #0x0
|
||||
MCR p15, 0, r0, c8, c7, 0 ; TLBIALL - Invalidate entire Unified TLB
|
||||
|
||||
;
|
||||
; Set up Domain Access Control Reg
|
||||
; ----------------------------------
|
||||
; b00 - No Access (abort)
|
||||
; b01 - Client (respect table entry)
|
||||
; b10 - RESERVED
|
||||
; b11 - Manager (ignore access permissions)
|
||||
|
||||
MRC p15, 0, r0, c3, c0, 0 ; Read Domain Access Control Register
|
||||
LDR r0, =0x55555555 ; Initialize every domain entry to b01 (client)
|
||||
MCR p15, 0, r0, c3, c0, 0 ; Write Domain Access Control Register
|
||||
|
||||
;;
|
||||
;; Enable L1 Preloader - Auxiliary Control
|
||||
;; -----------------------------------------
|
||||
;; Seems to undef on panda?
|
||||
;MRC p15, 0, r0, c1, c0, 1 ; Read ACTLR
|
||||
;ORR r0, r0, #0x4
|
||||
;MCR p15, 0, r0, c1, c0, 1 ; Write ACTLR
|
||||
ISB
|
||||
|
||||
|
||||
;
|
||||
; Set location of level 1 page table
|
||||
;------------------------------------
|
||||
; 31:14 - Base addr
|
||||
; 13:5 - 0x0
|
||||
; 4:3 - RGN 0x0 (Outer Noncachable)
|
||||
; 2 - P 0x0
|
||||
; 1 - S 0x0 (Non-shared)
|
||||
; 0 - C 0x0 (Inner Noncachable)
|
||||
LDR r0, =||Image$$PAGETABLES$$ZI$$Base||
|
||||
MSR TTBR0, r0
|
||||
|
||||
|
||||
;
|
||||
; Activate VFP/NEON, if required
|
||||
;-------------------------------
|
||||
|
||||
IF {TARGET_FEATURE_NEON} || {TARGET_FPU_VFP}
|
||||
|
||||
; 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]
|
||||
|
||||
LDR r0, =_tx_thread_smp_release_cores_flag ; Build address of release cores flag
|
||||
MOV r1, #0
|
||||
STR r1, [r0]
|
||||
|
||||
; [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
|
||||
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; Initialization for PRIMARY CPU
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT primaryCPUInit
|
||||
primaryCPUInit PROC
|
||||
|
||||
; Translation tables
|
||||
; -------------------
|
||||
; The translation tables are generated at boot time.
|
||||
; First the table is zeroed. Then the individual valid
|
||||
; entries are written in
|
||||
;
|
||||
|
||||
LDR r0, =||Image$$PAGETABLES$$ZI$$Base||
|
||||
|
||||
; Fill table with zeros
|
||||
MOV r2, #1024 ; Set r3 to loop count (4 entries per iteration, 1024 iterations)
|
||||
MOV r1, r0 ; Make a copy of the base dst
|
||||
MOV r3, #0
|
||||
MOV r4, #0
|
||||
MOV r5, #0
|
||||
MOV r6, #0
|
||||
ttb_zero_loop
|
||||
STMIA r1!, {r3-r6} ; Store out four entries
|
||||
SUBS r2, r2, #1 ; Decrement counter
|
||||
BNE ttb_zero_loop
|
||||
|
||||
;
|
||||
; STANDARD ENTRIES
|
||||
;
|
||||
|
||||
; Region covering program code and data
|
||||
LDR r1,=||Image$$EXEC$$Base|| ; Base physical address of program code and data
|
||||
LSR r1,#20 ; Shift right to align to 1MB boundaries
|
||||
LDR r3, =L1_COHERENT ; Descriptor template
|
||||
ORR r3, r1, LSL#20 ; Combine address and template
|
||||
STR r3, [r0, r1, LSL#2] ; Store table entry
|
||||
|
||||
; Entry for private address space
|
||||
; Needs to be marked as Device memory
|
||||
MRC p15, 4, r1, c15, c0, 0 ; Get base address of private address space
|
||||
LSR r1, r1, #20 ; Clear bottom 20 bits, to find which 1MB block it is in
|
||||
LSL r2, r1, #2 ; Make a copy, and multiply by four. This gives offset into the page tables
|
||||
LSL r1, r1, #20 ; Put back in address format
|
||||
LDR r3, =L1_DEVICE ; Descriptor template
|
||||
ORR r1, r1, r3 ; Combine address and template
|
||||
STR r1, [r0, r2] ; Store table entry
|
||||
|
||||
;
|
||||
; OPTIONAL ENTRIES
|
||||
; You will need additional translations if:
|
||||
; - No RAM at zero, so cannot use flat mapping
|
||||
; - You wish to retarget
|
||||
;
|
||||
; If you wish to output to stdio to a UART you will need
|
||||
; an additional entry
|
||||
;LDR r1, =PABASE_UART ; Physical address of UART
|
||||
;LSR r1, r1, #20 ; Mask off bottom 20 bits to find which 1MB it is within
|
||||
;LSL r2, r1, #2 ; Make a copy and multiply by 4 to get table offset
|
||||
;LSL r1, r1, #20 ; Put back into address format
|
||||
;LDR r3, =L1_DEVICE ; Descriptor template
|
||||
;ORR r1, r1, r3 ; Combine address and template
|
||||
;STR r1, [r0, r2] ; Store table entry
|
||||
|
||||
DSB
|
||||
|
||||
|
||||
; Enable MMU
|
||||
; -----------
|
||||
; 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
|
||||
|
||||
|
||||
; Enable the SCU
|
||||
; ---------------
|
||||
BL enableSCU
|
||||
|
||||
;
|
||||
; Join SMP
|
||||
; ---------
|
||||
MOV r0, #0x0 ; Move CPU ID into r0
|
||||
MOV r1, #0xF ; Move 0xF (represents all four ways) into r1
|
||||
BL secureSCUInvalidate
|
||||
BL joinSMP
|
||||
BL enableMaintenanceBroadcast
|
||||
|
||||
;
|
||||
; GIC Init
|
||||
; ---------
|
||||
BL enableGIC
|
||||
BL enableGICProcessorInterface
|
||||
|
||||
;
|
||||
; Enable Private Timer for periodic IRQ
|
||||
; --------------------------------------
|
||||
MOV r0, #0x1F
|
||||
BL setPriorityMask ; 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 enableIntID
|
||||
|
||||
; Set the priority
|
||||
MOV r0, #29
|
||||
MOV r1, #0
|
||||
BL setIntPriority
|
||||
|
||||
; Configure Timer
|
||||
MOV r0, #0xF0000
|
||||
MCR p15, 0, r0, c14, c2, 0 ; Setup timeout value (CNTP_TVAL)
|
||||
MOV r0, #0x1
|
||||
MCR p15, 0, r0, c14, c2, 1 ; Enable timer (CNTP_CTL)
|
||||
|
||||
;
|
||||
; Enable receipt of SGI 0
|
||||
; ------------------------
|
||||
MOV r0, #0x0 ; ID
|
||||
BL enableIntID
|
||||
|
||||
MOV r0, #0x0 ; ID
|
||||
MOV r1, #0x0 ; Priority
|
||||
BL setIntPriority
|
||||
|
||||
;
|
||||
; Branch to C lib code
|
||||
; ----------------------
|
||||
B __main
|
||||
|
||||
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; Initialization for SECONDARY CPUs
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT secondaryCPUsInit
|
||||
secondaryCPUsInit PROC
|
||||
|
||||
;
|
||||
; GIC Init
|
||||
; ---------
|
||||
BL enableGICProcessorInterface
|
||||
|
||||
MOV r0, #0x1F ; Priority
|
||||
BL setPriorityMask
|
||||
|
||||
MOV r0, #0x0 ; ID
|
||||
BL enableIntID
|
||||
|
||||
MOV r0, #0x0 ; ID
|
||||
MOV r1, #0x0 ; Priority
|
||||
BL setIntPriority
|
||||
|
||||
;
|
||||
; 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 secureSCUInvalidate
|
||||
|
||||
BL joinSMP
|
||||
BL enableMaintenanceBroadcast
|
||||
|
||||
; [EL Change Start]
|
||||
;
|
||||
; 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]
|
||||
|
||||
;
|
||||
; The translation tables are generated by the primary CPU
|
||||
; The MMU cannot be enabled on the secondary CPUs until
|
||||
; they are released from the holding-pen
|
||||
;
|
||||
|
||||
; Enable MMU
|
||||
; -----------
|
||||
; 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
|
||||
|
||||
|
||||
;
|
||||
; Branch to application
|
||||
; ----------------------
|
||||
; B main_app
|
||||
|
||||
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; Enable caches
|
||||
; This code must be run from a privileged mode
|
||||
; ------------------------------------------------------------
|
||||
|
||||
AREA ENABLECACHES, CODE, READONLY
|
||||
|
||||
EXPORT enable_caches
|
||||
|
||||
enable_caches FUNCTION
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; Enable caches
|
||||
; ------------------------------------------------------------
|
||||
|
||||
MRC p15, 0, r0, c1, c0, 0 ; Read System Control Register
|
||||
ORR r0, r0, #(0x1 << 12) ; Set I bit 12 to enable I Cache
|
||||
ORR r0, r0, #(0x1 << 2) ; Set C bit 2 to enable D Cache
|
||||
MCR p15, 0, r0, c1, c0, 0 ; Write System Control Register
|
||||
ISB
|
||||
|
||||
BX lr
|
||||
|
||||
ENDFUNC
|
||||
|
||||
|
||||
END
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; End of startup.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 */
|
||||
;/** */
|
||||
;/** Initialize */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_initialize.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h"
|
||||
;
|
||||
;
|
||||
;
|
||||
;
|
||||
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-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;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
|
||||
|
||||
155
ports_smp/cortex_a7_smp/ac5/example_build/sample_threadx/v7.h
Normal file
155
ports_smp/cortex_a7_smp/ac5/example_build/sample_threadx/v7.h
Normal file
@@ -0,0 +1,155 @@
|
||||
// ------------------------------------------------------------
|
||||
// v7-A Cache, TLB and Branch Prediction Maintenance Operations
|
||||
// Header File
|
||||
//
|
||||
// Copyright (c) 2011-2016 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.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#ifndef _ARMV7A_GENERIC_H
|
||||
#define _ARMV7A_GENERIC_H
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Memory barrier mnemonics
|
||||
enum MemBarOpt {
|
||||
RESERVED_0 = 0, RESERVED_1 = 1, OSHST = 2, OSH = 3,
|
||||
RESERVED_4 = 4, RESERVED_5 = 5, NSHST = 6, NSH = 7,
|
||||
RESERVED_8 = 8, RESERVED_9 = 9, ISHST = 10, ISH = 11,
|
||||
RESERVED_12 = 12, RESERVED_13 = 13, ST = 14, SY = 15
|
||||
};
|
||||
|
||||
//
|
||||
// Note:
|
||||
// *_IS() stands for "inner shareable"
|
||||
// DO NOT USE THESE FUNCTIONS ON A CORTEX-A8
|
||||
//
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Interrupts
|
||||
// Enable/disables IRQs (not FIQs)
|
||||
void enableInterrupts(void);
|
||||
void disableInterrupts(void);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Caches
|
||||
|
||||
void invalidateCaches_IS(void);
|
||||
void cleanInvalidateDCache(void);
|
||||
void invalidateCaches_IS(void);
|
||||
void enableCaches(void);
|
||||
void disableCaches(void);
|
||||
void invalidateCaches(void);
|
||||
void cleanDCache(void);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// TLBs
|
||||
|
||||
void invalidateUnifiedTLB(void);
|
||||
void invalidateUnifiedTLB_IS(void);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Branch prediction
|
||||
|
||||
void flushBranchTargetCache(void);
|
||||
void flushBranchTargetCache_IS(void);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// High Vecs
|
||||
|
||||
void enableHighVecs(void);
|
||||
void disableHighVecs(void);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// ID Registers
|
||||
|
||||
unsigned int getMIDR(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
|
||||
|
||||
unsigned int getMPIDR(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
|
||||
|
||||
unsigned int getContextID(void);
|
||||
|
||||
void setContextID(unsigned int);
|
||||
|
||||
#define CONTEXTID_ASID_SHIFT 0
|
||||
#define CONTEXTID_ASID_MASK 0xFF
|
||||
#define CONTEXTID_PROCID_SHIFT 8
|
||||
#define CONTEXTID_PROCID_MASK 0x00FFFFFF
|
||||
|
||||
// tmp = getContextID();
|
||||
// ASID = tmp & CONTEXTID_ASID_MASK;
|
||||
// PROCID = (tmp >> CONTEXTID_PROCID_SHIFT) & CONTEXTID_PROCID_MASK;
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// SMP related for Armv7-A MPCore processors
|
||||
//
|
||||
// DO NOT CALL THESE FUNCTIONS ON A CORTEX-A8
|
||||
|
||||
// Returns the base address of the private peripheral memory space
|
||||
unsigned int getBaseAddr(void);
|
||||
|
||||
// Returns the CPU ID (0 to 3) of the CPU executed on
|
||||
#define MP_CPU0 (0)
|
||||
#define MP_CPU1 (1)
|
||||
#define MP_CPU2 (2)
|
||||
#define MP_CPU3 (3)
|
||||
unsigned int getCPUID(void);
|
||||
|
||||
// Set this core as participating in SMP
|
||||
void joinSMP(void);
|
||||
|
||||
// Set this core as NOT participating in SMP
|
||||
void leaveSMP(void);
|
||||
|
||||
// Go to sleep, never returns
|
||||
void goToSleep(void);
|
||||
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// End of v7.h
|
||||
// ------------------------------------------------------------
|
||||
458
ports_smp/cortex_a7_smp/ac5/example_build/sample_threadx/v7.s
Normal file
458
ports_smp/cortex_a7_smp/ac5/example_build/sample_threadx/v7.s
Normal file
@@ -0,0 +1,458 @@
|
||||
; ------------------------------------------------------------
|
||||
; v7-A Cache and Branch Prediction Maintenance Operations
|
||||
;
|
||||
; 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.
|
||||
; ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
AREA v7Opps,CODE,READONLY
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; Interrupt enable/disable
|
||||
; ------------------------------------------------------------
|
||||
|
||||
; Could use intrinsic instead of these
|
||||
|
||||
EXPORT enableInterrupts
|
||||
; void enableInterrupts(void);
|
||||
enableInterrupts PROC
|
||||
CPSIE i
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
EXPORT disableInterrupts
|
||||
; void disableInterrupts(void);
|
||||
disableInterrupts PROC
|
||||
CPSID i
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; Cache Maintenance
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT enableCaches
|
||||
; void enableCaches(void);
|
||||
enableCaches PROC
|
||||
MRC p15, 0, r0, c1, c0, 0 ; Read System Control Register
|
||||
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
|
||||
ISB
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
|
||||
EXPORT disableCaches
|
||||
; void disableCaches(void)
|
||||
disableCaches PROC
|
||||
MRC p15, 0, r0, c1, c0, 0 ; Read System Control Register
|
||||
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
|
||||
ISB
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
|
||||
EXPORT cleanDCache
|
||||
; void cleanDCache(void);
|
||||
cleanDCache PROC
|
||||
PUSH {r4-r12}
|
||||
|
||||
;
|
||||
; Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B)
|
||||
;
|
||||
|
||||
MRC p15, 1, r0, c0, c0, 1 ; Read CLIDR
|
||||
ANDS r3, r0, #0x7000000
|
||||
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 cleanInvalidateDCache
|
||||
; void cleanInvalidateDCache(void);
|
||||
cleanInvalidateDCache PROC
|
||||
PUSH {r4-r12}
|
||||
|
||||
;
|
||||
; Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B)
|
||||
;
|
||||
|
||||
MRC p15, 1, r0, c0, c0, 1 ; Read CLIDR
|
||||
ANDS r3, r0, #0x7000000
|
||||
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 invalidateCaches
|
||||
; void invalidateCaches(void);
|
||||
invalidateCaches PROC
|
||||
PUSH {r4-r12}
|
||||
|
||||
;
|
||||
; Based on code example given in section B2.2.4/11.2.4 of Armv7-A/R Architecture Reference Manual (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, #0x7000000
|
||||
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 invalidateCaches_IS
|
||||
; void invalidateCaches_IS(void);
|
||||
invalidateCaches_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, #0x7000000
|
||||
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 invalidateUnifiedTLB
|
||||
; void invalidateUnifiedTLB(void);
|
||||
invalidateUnifiedTLB PROC
|
||||
MOV r0, #0
|
||||
MCR p15, 0, r0, c8, c7, 0 ; TLBIALL - Invalidate entire unified TLB
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
EXPORT invalidateUnifiedTLB_IS
|
||||
; void invalidateUnifiedTLB_IS(void);
|
||||
invalidateUnifiedTLB_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 flushBranchTargetCache
|
||||
; void flushBranchTargetCache(void)
|
||||
flushBranchTargetCache PROC
|
||||
MOV r0, #0
|
||||
MCR p15, 0, r0, c7, c5, 6 ; BPIALL - Invalidate entire branch predictor array
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
EXPORT flushBranchTargetCache_IS
|
||||
; void flushBranchTargetCache_IS(void)
|
||||
flushBranchTargetCache_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 enableHighVecs
|
||||
; void enableHighVecs(void);
|
||||
enableHighVecs 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
|
||||
ISB
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
EXPORT disableHighVecs
|
||||
; void disable_highvecs(void);
|
||||
disableHighVecs 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
|
||||
ISB
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; Context ID
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT getContextID
|
||||
; uint32_t getContextIDd(void);
|
||||
getContextID PROC
|
||||
MRC p15, 0, r0, c13, c0, 1 ; Read Context ID Register
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
EXPORT setContextID
|
||||
; void setContextID(uint32_t);
|
||||
setContextID PROC
|
||||
MCR p15, 0, r0, c13, c0, 1 ; Write Context ID Register
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; ID registers
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT getMIDR
|
||||
; uint32_t getMIDR(void);
|
||||
getMIDR PROC
|
||||
MRC p15, 0, r0, c0, c0, 0 ; Read Main ID Register (MIDR)
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
EXPORT getMPIDR
|
||||
; uint32_t getMPIDR(void);
|
||||
getMPIDR PROC
|
||||
MRC p15, 0, r0, c0 ,c0, 5; Read Multiprocessor ID register (MPIDR)
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; CP15 SMP related
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT getBaseAddr
|
||||
; uint32_t getBaseAddr(void)
|
||||
; Returns the value CBAR (base address of the private peripheral memory space)
|
||||
getBaseAddr PROC
|
||||
MRC p15, 4, r0, c15, c0, 0 ; Read peripheral base address
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT getCPUID
|
||||
; uint32_t getCPUID(void)
|
||||
; Returns the CPU ID (0 to 3) of the CPU executed on
|
||||
getCPUID 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 goToSleep
|
||||
; void goToSleep(void)
|
||||
goToSleep PROC
|
||||
DSB ; Clear all pending data accesses
|
||||
WFI ; Go into standby
|
||||
B goToSleep ; Catch in case of rogue events
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT joinSMP
|
||||
; void joinSMP(void)
|
||||
; Sets the ACTRL.SMP bit
|
||||
joinSMP PROC
|
||||
|
||||
; SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg
|
||||
|
||||
MRC p15, 0, r0, c1, c0, 1 ; Read ACTLR
|
||||
MOV r1, r0
|
||||
ORR r0, r0, #0x040 ; Set bit 6
|
||||
CMP r0, r1
|
||||
MCRNE p15, 0, r0, c1, c0, 1 ; Write ACTLR
|
||||
ISB
|
||||
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
; ------------------------------------------------------------
|
||||
|
||||
EXPORT leaveSMP
|
||||
; void leaveSMP(void)
|
||||
; Clear the ACTRL.SMP bit
|
||||
leaveSMP 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
|
||||
ISB
|
||||
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
END
|
||||
|
||||
; ------------------------------------------------------------
|
||||
; End of v7.s
|
||||
; ------------------------------------------------------------
|
||||
202
ports_smp/cortex_a7_smp/ac5/example_build/tx/.cproject
Normal file
202
ports_smp/cortex_a7_smp/ac5/example_build/tx/.cproject
Normal file
@@ -0,0 +1,202 @@
|
||||
<?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="com.arm.eclipse.builder.armcc.error" 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.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.base.var.arm_compiler_5-5.2105747536" name="Arm Compiler 5" superClass="com.arm.toolchain.baremetal.base.var.arm_compiler_5-5">
|
||||
|
||||
<option id="com.arm.toolchain.ac5.option.target.cpu_fpu.132684152" superClass="com.arm.toolchain.ac5.option.target.cpu_fpu" useByScannerDiscovery="false" value="Cortex-A5.NoFPU" valueType="string"/>
|
||||
|
||||
<option id="com.arm.toolchain.ac5.option.fppcs.278813204" name="Floating-point PCS" superClass="com.arm.toolchain.ac5.option.fppcs" useByScannerDiscovery="false" value="com.arm.tool.c.compiler.option.fppcs.auto" valueType="enumerated"/>
|
||||
|
||||
<option id="com.arm.toolchain.ac5.option.inst.1012394013" 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.base.var.arm_compiler_5-5.2105747536.514260667" name=""/>
|
||||
|
||||
<builder buildPath="${workspace_loc:/tx}/Debug" id="com.arm.toolchain.baremetal.builder.485038061" 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.base.var.arm_compiler_5-5.653666395" name="Arm C Compiler 5" superClass="com.arm.tool.c.compiler.base.var.arm_compiler_5-5">
|
||||
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.arm.tool.c.compiler.option.incpath.973159258" name="Include path (-I)" 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>
|
||||
|
||||
<option defaultValue="com.arm.tool.c.compiler.option.optlevel.min" id="com.arm.tool.c.compiler.option.optlevel.1668909054" name="Optimization level" superClass="com.arm.tool.c.compiler.option.optlevel" useByScannerDiscovery="true" valueType="enumerated"/>
|
||||
|
||||
<option id="com.arm.tool.c.compiler.option.targetcpu.1163690447" name="Target CPU (--cpu)" superClass="com.arm.tool.c.compiler.option.targetcpu" useByScannerDiscovery="true" value="Cortex-A5" valueType="string"/>
|
||||
|
||||
<option id="com.arm.tool.c.compiler.option.fppcs.671391023" name="Floating-point PCS (--apcs)" superClass="com.arm.tool.c.compiler.option.fppcs" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.fppcs.auto" valueType="enumerated"/>
|
||||
|
||||
<option id="com.arm.tool.c.compiler.option.inst.894914968" name="Instruction set" superClass="com.arm.tool.c.compiler.option.inst" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.inst.arm" valueType="enumerated"/>
|
||||
|
||||
<inputType id="com.arm.tool.c.compiler.input.224727355" superClass="com.arm.tool.c.compiler.input"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="com.arm.tool.cpp.compiler.base.var.arm_compiler_5-5.1160078838" name="Arm C++ Compiler 5" superClass="com.arm.tool.cpp.compiler.base.var.arm_compiler_5-5">
|
||||
|
||||
<option defaultValue="com.arm.tool.c.compiler.option.optlevel.min" id="com.arm.tool.c.compiler.option.optlevel.680725189" name="Optimization level" superClass="com.arm.tool.c.compiler.option.optlevel" useByScannerDiscovery="true" valueType="enumerated"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="com.arm.tool.assembler.base.var.arm_compiler_5-5.1120768997" name="Arm Assembler 5" superClass="com.arm.tool.assembler.base.var.arm_compiler_5-5">
|
||||
|
||||
<option id="com.arm.tool.assembler.option.cpu.175183509" name="Target CPU (--cpu)" superClass="com.arm.tool.assembler.option.cpu" useByScannerDiscovery="true" value="Cortex-A5" valueType="string"/>
|
||||
|
||||
<option id="com.arm.tool.assembler.option.fppcs.200544319" name="Floating-point PCS (--apcs)" superClass="com.arm.tool.assembler.option.fppcs" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.option.fppcs.auto" valueType="enumerated"/>
|
||||
|
||||
<option id="com.arm.tool.assembler.option.inst.248693663" 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.1485288712" 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.675110984" superClass="com.arm.tool.assembler.input"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="com.arm.tool.c.linker.base.var.arm_compiler_5-5.1005913797" name="Arm Linker 5" superClass="com.arm.tool.c.linker.base.var.arm_compiler_5-5"/>
|
||||
|
||||
<tool id="com.arm.tool.librarian.base.var.arm_compiler_5-5.1439970481" name="Arm Librarian 5" superClass="com.arm.tool.librarian.base.var.arm_compiler_5-5"/>
|
||||
|
||||
</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="com.arm.eclipse.builder.armcc.error" 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" superClass="com.arm.toolchain.v6.lib.release.base.var.arm_compiler_6-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"/>
|
||||
|
||||
<tool id="com.arm.tool.c.compiler.v6.base.var.arm_compiler_6-6.1411448201" name="Arm C Compiler 6" superClass="com.arm.tool.c.compiler.v6.base.var.arm_compiler_6-6">
|
||||
|
||||
<option id="com.arm.tool.c.compiler.v6.base.option.optlevel.1844241431" name="Optimization level" superClass="com.arm.tool.c.compiler.v6.base.option.optlevel" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.v6.base.option.optlevel.high" valueType="enumerated"/>
|
||||
|
||||
<inputType id="com.arm.tool.c.compiler.v6.base.input.1030569593" superClass="com.arm.tool.c.compiler.v6.base.input"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="com.arm.tool.cpp.compiler.v6.base.var.arm_compiler_6-6.605804138" name="Arm C++ Compiler 6" superClass="com.arm.tool.cpp.compiler.v6.base.var.arm_compiler_6-6">
|
||||
|
||||
<option id="com.arm.tool.c.compiler.v6.base.option.optlevel.1586474276" name="Optimization level" superClass="com.arm.tool.c.compiler.v6.base.option.optlevel" useByScannerDiscovery="true" value="com.arm.tool.c.compiler.v6.base.option.optlevel.high" valueType="enumerated"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="com.arm.tool.assembler.v6.base.var.arm_compiler_6-6.297367297" name="Arm Assembler 6" superClass="com.arm.tool.assembler.v6.base.var.arm_compiler_6-6">
|
||||
|
||||
<inputType id="com.arm.tool.assembler.v6.base.input.420936661" superClass="com.arm.tool.assembler.v6.base.input"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="com.arm.tool.c.linker.v6.base.var.arm_compiler_6-6.2145383118" name="Arm Linker 6" superClass="com.arm.tool.c.linker.v6.base.var.arm_compiler_6-6"/>
|
||||
|
||||
<tool id="com.arm.tool.librarian.v6.base.var.arm_compiler_6-6.1866033223" name="Arm Librarian 6" superClass="com.arm.tool.librarian.v6.base.var.arm_compiler_6-6"/>
|
||||
|
||||
</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>
|
||||
48
ports_smp/cortex_a7_smp/ac5/example_build/tx/.project
Normal file
48
ports_smp/cortex_a7_smp/ac5/example_build/tx/.project
Normal file
@@ -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>
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project>
|
||||
|
||||
<configuration id="com.arm.eclipse.build.config.v6.lib.debug.base.1507005551" name="Debug">
|
||||
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
|
||||
<provider class="com.arm.eclipse.builder.armcc.discovery.ArmCompiler5LanguageSettingsProvider" console="false" env-hash="-238411086247424924" id="com.arm.eclipse.builder.armcc.v5.langprovider" keep-relative-paths="false" name="Arm Compiler 5 Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} --list-macros "${INPUTS}"" prefer-non-shared="true">
|
||||
|
||||
<language-scope id="com.arm.eclipse.builder.armcc.lang.c"/>
|
||||
|
||||
<language-scope id="com.arm.eclipse.builder.armcc.lang.cpp"/>
|
||||
|
||||
</provider>
|
||||
|
||||
</extension>
|
||||
|
||||
</configuration>
|
||||
|
||||
<configuration id="com.arm.eclipse.build.config.v6.lib.release.base.1262125868" name="Release">
|
||||
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
|
||||
<provider class="com.arm.eclipse.builder.armcc.discovery.ArmCompiler6LanguageSettingsProvider" console="false" env-hash="697562460423706802" id="com.arm.eclipse.builder.armcc.v6.langprovider" keep-relative-paths="false" name="Arm Compiler 6 Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
|
||||
<language-scope id="com.arm.eclipse.builder.armcc.lang.c.ac6"/>
|
||||
|
||||
<language-scope id="com.arm.eclipse.builder.armcc.lang.cpp.ac6"/>
|
||||
|
||||
</provider>
|
||||
|
||||
</extension>
|
||||
|
||||
</configuration>
|
||||
|
||||
</project>
|
||||
406
ports_smp/cortex_a7_smp/ac5/inc/tx_port.h
Normal file
406
ports_smp/cortex_a7_smp/ac5/inc/tx_port.h
Normal file
@@ -0,0 +1,406 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* 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-A7/AC5 */
|
||||
/* 6.0.1 */
|
||||
/* */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, 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 */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#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 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-A7. 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 SMP/Cortex-A7/AC5 Version 6.0.1 *";
|
||||
#else
|
||||
extern CHAR _tx_version_id[];
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
361
ports_smp/cortex_a7_smp/ac5/readme_threadx.txt
Normal file
361
ports_smp/cortex_a7_smp/ac5/readme_threadx.txt
Normal file
@@ -0,0 +1,361 @@
|
||||
Microsoft's Azure RTOS ThreadX SMP for Cortex-A7
|
||||
|
||||
Thumb & 32-bit Mode
|
||||
|
||||
Using the ARM Compiler 5 & DS
|
||||
|
||||
1. Import the ThreadX Projects
|
||||
|
||||
In order to build the ThreadX SMP library and the ThreadX SMP demonstration, first import
|
||||
the 'tx' and 'sample_threadx' projects (located in the "example_build" directory)
|
||||
into your DS workspace.
|
||||
|
||||
|
||||
2. Building the ThreadX SMP run-time Library
|
||||
|
||||
Building the ThreadX SMP library is easy; simply select the Eclipse project file
|
||||
"tx" and then select the build button. You should now observe the compilation
|
||||
and assembly of the ThreadX SMP library. This project build produces the ThreadX SMP
|
||||
library file tx.a.
|
||||
|
||||
|
||||
3. Demonstration System
|
||||
|
||||
The ThreadX SMP demonstration is designed to execute under the DS debugger on the
|
||||
VE_Cortex-A7x4 Bare Metal simulator.
|
||||
|
||||
Building the demonstration is easy; simply open the workspace file, select the
|
||||
sample_threadx project, and select the build button. Next, expand the demo ThreadX
|
||||
project folder in the Project Explorer window, right-click on the 'sample_threadx.launch'
|
||||
file, click 'Debug As', and then click 'sample_threadx' from the submenu. This will cause the
|
||||
debugger to load the sample_threadx.axf ELF file and run to main. You are now ready
|
||||
to execute the ThreadX demonstration.
|
||||
|
||||
|
||||
4. System Initialization
|
||||
|
||||
The entry point in ThreadX for the Cortex-A7 using AC5 tools is at label
|
||||
Reset_Handler in startup.s. After the basic core initialization is complete,
|
||||
control will transfer to __main, which is where all static and global pre-set
|
||||
C variable initialization processing takes place.
|
||||
|
||||
The ThreadX tx_initialize_low_level.s file is responsible for setting up
|
||||
various system data structures, the vector area, and a periodic timer interrupt
|
||||
source. By default, the vector area is defined to be located in the Init area,
|
||||
which is defined at the top of tx_initialize_low_level.s. This area is typically
|
||||
located at 0. In situations where this is impossible, the vectors at the beginning
|
||||
of the Init area should be copied to address 0.
|
||||
|
||||
This is also where initialization of a periodic timer interrupt source
|
||||
should take place.
|
||||
|
||||
In addition, _tx_initialize_low_level determines the first available
|
||||
address for use by the application, which is supplied as the sole input
|
||||
parameter to your application definition function, tx_application_define.
|
||||
|
||||
|
||||
5. Register Usage and Stack Frames
|
||||
|
||||
The AC5 compiler assumes that registers r0-r3 (a1-a4) and r12 (ip) are scratch
|
||||
registers for each function. All other registers used by a C function must
|
||||
be preserved by the function. ThreadX takes advantage of this in situations
|
||||
where a context switch happens as a result of making a ThreadX service call
|
||||
(which is itself a C function). In such cases, the saved context of a thread
|
||||
is only the non-scratch registers.
|
||||
|
||||
The following defines the saved context stack frames for context switches
|
||||
that occur as a result of interrupt handling or from thread-level API calls.
|
||||
All suspended threads have one of these two types of stack frames. The top
|
||||
of the suspended thread's stack is pointed to by tx_thread_stack_ptr in the
|
||||
associated thread control block TX_THREAD.
|
||||
|
||||
|
||||
|
||||
Offset Interrupted Stack Frame Non-Interrupt Stack Frame
|
||||
|
||||
0x00 1 0
|
||||
0x04 CPSR CPSR
|
||||
0x08 r0 (a1) r4 (v1)
|
||||
0x0C r1 (a2) r5 (v2)
|
||||
0x10 r2 (a3) r6 (v3)
|
||||
0x14 r3 (a4) r7 (v4)
|
||||
0x18 r4 (v1) r8 (v5)
|
||||
0x1C r5 (v2) r9 (v6)
|
||||
0x20 r6 (v3) r10 (v7)
|
||||
0x24 r7 (v4) r11 (fp)
|
||||
0x28 r8 (v5) r14 (lr)
|
||||
0x2C r9 (v6)
|
||||
0x30 r10 (v7)
|
||||
0x34 r11 (fp)
|
||||
0x38 r12 (ip)
|
||||
0x3C r14 (lr)
|
||||
0x40 PC
|
||||
|
||||
|
||||
6. Improving Performance
|
||||
|
||||
The distribution version of ThreadX is built without any compiler
|
||||
optimizations. This makes it easy to debug because you can trace or set
|
||||
breakpoints inside of ThreadX itself. Of course, this costs some
|
||||
performance. To make it run faster, you can change the build_threadx.bat file to
|
||||
remove the -g option and enable all compiler optimizations.
|
||||
|
||||
In addition, you can eliminate the ThreadX basic API error checking by
|
||||
compiling your application code with the symbol TX_DISABLE_ERROR_CHECKING
|
||||
defined.
|
||||
|
||||
|
||||
7. Interrupt Handling
|
||||
|
||||
ThreadX provides complete and high-performance interrupt handling for Cortex-A7
|
||||
targets. There are a certain set of requirements that are defined in the
|
||||
following sub-sections:
|
||||
|
||||
|
||||
7.1 Vector Area
|
||||
|
||||
The Cortex-A7 vectors start at address zero. The demonstration system startup
|
||||
Init area contains the vectors and is loaded at address zero. On actual
|
||||
hardware platforms, this area might have to be copied to address 0.
|
||||
|
||||
|
||||
7.2 IRQ ISRs
|
||||
|
||||
ThreadX fully manages standard and vectored IRQ interrupts. ThreadX also supports nested
|
||||
IRQ interrupts. The following sub-sections define the IRQ capabilities.
|
||||
|
||||
|
||||
7.2.1 Standard IRQ ISRs
|
||||
|
||||
The standard ARM IRQ mechanism has a single interrupt vector at address 0x18. This IRQ
|
||||
interrupt is managed by the __tx_irq_handler code in tx_initialize_low_level. The following
|
||||
is the default IRQ handler defined in tx_initialize_low_level.s:
|
||||
|
||||
EXPORT __tx_irq_handler
|
||||
EXPORT __tx_irq_processing_return
|
||||
__tx_irq_handler
|
||||
;
|
||||
; /* Jump to context save to save system context. */
|
||||
B _tx_thread_context_save ; Jump to the context save
|
||||
__tx_irq_processing_return
|
||||
;
|
||||
; /* At this point execution is still in the IRQ mode. The CPSR, point of
|
||||
; interrupt, and all C scratch registers are available for use. Note
|
||||
; that IRQ interrupts are still disabled upon return from the context
|
||||
; save function. */
|
||||
;
|
||||
; /* Application ISR call(s) go here! */
|
||||
;
|
||||
; /* Jump to context restore to restore system context. */
|
||||
B _tx_thread_context_restore
|
||||
|
||||
|
||||
7.2.2 Vectored IRQ ISRs
|
||||
|
||||
The vectored ARM IRQ mechanism has multiple interrupt vectors at addresses specified
|
||||
by the particular implementation. The following is an example IRQ handler defined in
|
||||
tx_initialize_low_level.s:
|
||||
|
||||
EXPORT __tx_irq_example_handler
|
||||
__tx_irq_example_handler
|
||||
;
|
||||
; /* Call context save to save system context. */
|
||||
|
||||
STMDB sp!, {r0-r3} ; Save some scratch registers
|
||||
MRS r0, SPSR ; Pickup saved SPSR
|
||||
SUB lr, lr, #4 ; Adjust point of interrupt
|
||||
STMDB sp!, {r0, r10, r12, lr} ; Store other scratch registers
|
||||
BL _tx_thread_vectored_context_save ; Call the vectored IRQ context save
|
||||
;
|
||||
; /* At this point execution is still in the IRQ mode. The CPSR, point of
|
||||
; interrupt, and all C scratch registers are available for use. Note
|
||||
; that IRQ interrupts are still disabled upon return from the context
|
||||
; save function. */
|
||||
;
|
||||
; /* Application ISR call goes here! */
|
||||
;
|
||||
; /* Jump to context restore to restore system context. */
|
||||
B _tx_thread_context_restore
|
||||
|
||||
|
||||
7.2.3 Nested IRQ Support
|
||||
|
||||
By default, nested IRQ interrupt support is not enabled. To enable nested
|
||||
IRQ support, the entire library should be built with TX_ENABLE_IRQ_NESTING
|
||||
defined. With this defined, two new IRQ interrupt management services are
|
||||
available, namely _tx_thread_irq_nesting_start and _tx_thread_irq_nesting_end.
|
||||
These function should be called between the IRQ context save and restore
|
||||
calls.
|
||||
|
||||
Execution between the calls to _tx_thread_irq_nesting_start and
|
||||
_tx_thread_irq_nesting_end is enabled for IRQ nesting. This is achieved
|
||||
by switching from IRQ mode to SYS mode and enabling IRQ interrupts.
|
||||
The SYS mode stack is used during the SYS mode operation, which was
|
||||
setup in tx_initialize_low_level.s. When nested IRQ interrupts are no longer required,
|
||||
calling the _tx_thread_irq_nesting_end service disables nesting by disabling
|
||||
IRQ interrupts and switching back to IRQ mode in preparation for the IRQ
|
||||
context restore service.
|
||||
|
||||
The following is an example of enabling IRQ nested interrupts in a standard
|
||||
IRQ handler:
|
||||
|
||||
EXPORT __tx_irq_handler
|
||||
EXPORT __tx_irq_processing_return
|
||||
__tx_irq_handler
|
||||
;
|
||||
; /* Jump to context save to save system context. */
|
||||
B _tx_thread_context_save
|
||||
__tx_irq_processing_return
|
||||
;
|
||||
; /* Enable nested IRQ interrupts. NOTE: Since this service returns
|
||||
; with IRQ interrupts enabled, all IRQ interrupt sources must be
|
||||
; cleared prior to calling this service. */
|
||||
BL _tx_thread_irq_nesting_start
|
||||
;
|
||||
; /* Application ISR call(s) go here! */
|
||||
;
|
||||
; /* Disable nested IRQ interrupts. The mode is switched back to
|
||||
; IRQ mode and IRQ interrupts are disable upon return. */
|
||||
BL _tx_thread_irq_nesting_end
|
||||
;
|
||||
; /* Jump to context restore to restore system context. */
|
||||
B _tx_thread_context_restore
|
||||
|
||||
|
||||
7.3 FIQ Interrupts
|
||||
|
||||
By default, Cortex-A7 FIQ interrupts are left alone by ThreadX. Of course, this
|
||||
means that the application is fully responsible for enabling the FIQ interrupt
|
||||
and saving/restoring any registers used in the FIQ ISR processing. To globally
|
||||
enable FIQ interrupts, the application should enable FIQ interrupts at the
|
||||
beginning of each thread or before any threads are created in tx_application_define.
|
||||
In addition, the application must ensure that no ThreadX service calls are made
|
||||
from default FIQ ISRs, which is located in tx_initialize_low_level.s.
|
||||
|
||||
|
||||
7.3.1 Managed FIQ Interrupts
|
||||
|
||||
Full ThreadX management of FIQ interrupts is provided if the ThreadX sources
|
||||
are built with the TX_ENABLE_FIQ_SUPPORT defined. If the library is built
|
||||
this way, the FIQ interrupt handlers are very similar to the IRQ interrupt
|
||||
handlers defined previously. The following is default FIQ handler
|
||||
defined in tx_initialize_low_level.s:
|
||||
|
||||
|
||||
EXPORT __tx_fiq_handler
|
||||
EXPORT __tx_fiq_processing_return
|
||||
__tx_fiq_handler
|
||||
;
|
||||
; /* Jump to fiq context save to save system context. */
|
||||
B _tx_thread_fiq_context_save
|
||||
__tx_fiq_processing_return:
|
||||
;
|
||||
; /* At this point execution is still in the FIQ mode. The CPSR, point of
|
||||
; interrupt, and all C scratch registers are available for use. */
|
||||
;
|
||||
; /* Application FIQ handlers can be called here! */
|
||||
;
|
||||
; /* Jump to fiq context restore to restore system context. */
|
||||
B _tx_thread_fiq_context_restore
|
||||
|
||||
|
||||
7.3.1.1 Nested FIQ Support
|
||||
|
||||
By default, nested FIQ interrupt support is not enabled. To enable nested
|
||||
FIQ support, the entire library should be built with TX_ENABLE_FIQ_NESTING
|
||||
defined. With this defined, two new FIQ interrupt management services are
|
||||
available, namely _tx_thread_fiq_nesting_start and _tx_thread_fiq_nesting_end.
|
||||
These function should be called between the FIQ context save and restore
|
||||
calls.
|
||||
|
||||
Execution between the calls to _tx_thread_fiq_nesting_start and
|
||||
_tx_thread_fiq_nesting_end is enabled for FIQ nesting. This is achieved
|
||||
by switching from FIQ mode to SYS mode and enabling FIQ interrupts.
|
||||
The SYS mode stack is used during the SYS mode operation, which was
|
||||
setup in tx_initialize_low_level.s. When nested FIQ interrupts are no longer required,
|
||||
calling the _tx_thread_fiq_nesting_end service disables nesting by disabling
|
||||
FIQ interrupts and switching back to FIQ mode in preparation for the FIQ
|
||||
context restore service.
|
||||
|
||||
The following is an example of enabling FIQ nested interrupts in the
|
||||
typical FIQ handler:
|
||||
|
||||
|
||||
EXPORT __tx_fiq_handler
|
||||
EXPORT __tx_fiq_processing_return
|
||||
__tx_fiq_handler
|
||||
;
|
||||
; /* Jump to fiq context save to save system context. */
|
||||
B _tx_thread_fiq_context_save
|
||||
__tx_fiq_processing_return
|
||||
;
|
||||
; /* At this point execution is still in the FIQ mode. The CPSR, point of
|
||||
; interrupt, and all C scratch registers are available for use. */
|
||||
;
|
||||
; /* Enable nested FIQ interrupts. NOTE: Since this service returns
|
||||
; with FIQ interrupts enabled, all FIQ interrupt sources must be
|
||||
; cleared prior to calling this service. */
|
||||
BL _tx_thread_fiq_nesting_start
|
||||
;
|
||||
; /* Application FIQ handlers can be called here! */
|
||||
;
|
||||
; /* Disable nested FIQ interrupts. The mode is switched back to
|
||||
; FIQ mode and FIQ interrupts are disable upon return. */
|
||||
BL _tx_thread_fiq_nesting_end
|
||||
;
|
||||
; /* Jump to fiq context restore to restore system context. */
|
||||
B _tx_thread_fiq_context_restore
|
||||
|
||||
|
||||
8. ThreadX Timer Interrupt
|
||||
|
||||
ThreadX requires a periodic interrupt source to manage all time-slicing,
|
||||
thread sleeps, timeouts, and application timers. Without such a timer
|
||||
interrupt source, these services are not functional. However, all other
|
||||
ThreadX services are operational without a periodic timer source.
|
||||
|
||||
To add the timer interrupt processing, simply make a call to
|
||||
_tx_timer_interrupt in the IRQ processing. An example of this can be
|
||||
found in the file tx_initialize_low_level.s in the Integrator sub-directories.
|
||||
|
||||
|
||||
9. Thumb/Cortex-A7 Mixed Mode
|
||||
|
||||
By default, ThreadX is setup for running in Cortex-A7 32-bit mode. This is
|
||||
also true for the demonstration system. It is possible to build any
|
||||
ThreadX file and/or the application in Thumb mode. If any Thumb code
|
||||
is used the entire ThreadX source- both C and assembly - should be built
|
||||
with the "-apcs /interwork" option.
|
||||
|
||||
|
||||
10. VFP Support
|
||||
|
||||
By default, VFP support is disabled for each thread. If saving the context of the VFP registers
|
||||
is needed, the following API call must be made from the context of the application thread - before
|
||||
the VFP usage:
|
||||
|
||||
void tx_thread_vfp_enable(void);
|
||||
|
||||
After this API is called in the application, VFP registers will be saved/restored for this thread if it
|
||||
is preempted via an interrupt. All other suspension of the this thread will not require the VFP registers
|
||||
to be saved/restored.
|
||||
|
||||
To disable VFP register context saving, simply call the following API:
|
||||
|
||||
void tx_thread_vfp_disable(void);
|
||||
|
||||
|
||||
11. Revision History
|
||||
|
||||
For generic code revision information, please refer to the readme_threadx_generic.txt
|
||||
file, which is included in your distribution. The following details the revision
|
||||
information associated with this specific port of ThreadX:
|
||||
|
||||
06/30/2020 Initial ThreadX 6.0.1 version for Cortex-A7 using AC5 tools.
|
||||
|
||||
|
||||
Copyright(c) 1996-2020 Microsoft Corporation
|
||||
|
||||
|
||||
https://azure.com/rtos
|
||||
|
||||
369
ports_smp/cortex_a7_smp/ac5/src/tx_thread_context_restore.s
Normal file
369
ports_smp/cortex_a7_smp/ac5/src/tx_thread_context_restore.s
Normal file
@@ -0,0 +1,369 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h"
|
||||
;
|
||||
;/* Include macros for modifying the wait list. */
|
||||
#include "tx_thread_smp_protection_wait_list_macros.h"
|
||||
|
||||
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
|
||||
IMPORT _tx_thread_smp_protect_wait_counts
|
||||
IMPORT _tx_thread_smp_protect_wait_list
|
||||
IMPORT _tx_thread_smp_protect_wait_list_lock_protect_in_force
|
||||
IMPORT _tx_thread_smp_protect_wait_list_tail
|
||||
IMPORT _tx_thread_smp_protect_wait_list_size
|
||||
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-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;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
|
||||
;
|
||||
; /* Was the thread being preempted waiting for the lock? */
|
||||
; if (_tx_thread_smp_protect_wait_counts[this_core] != 0)
|
||||
; {
|
||||
;
|
||||
LDR r1, =_tx_thread_smp_protect_wait_counts ; Load waiting count list
|
||||
LDR r2, [r1, r10, LSL #2] ; Load waiting value for this core
|
||||
CMP r2, #0
|
||||
BEQ _nobody_waiting_for_lock ; Is the core waiting for the lock?
|
||||
;
|
||||
; /* Do we not have the lock? This means the ISR never got the inter-core lock. */
|
||||
; if (_tx_thread_smp_protection.tx_thread_smp_protect_owned != this_core)
|
||||
; {
|
||||
;
|
||||
LDR r1, =_tx_thread_smp_protection ; Load address of protection structure
|
||||
LDR r2, [r1, #8] ; Pickup the owning core
|
||||
CMP r10, r2 ; Compare our core to the owning core
|
||||
BEQ _this_core_has_lock ; Do we have the lock?
|
||||
;
|
||||
; /* We don't have the lock. This core should be in the list. Remove it. */
|
||||
; _tx_thread_smp_protect_wait_list_remove(this_core);
|
||||
;
|
||||
macro_call0 _tx_thread_smp_protect_wait_list_remove ; Call macro to remove core from the list
|
||||
B _nobody_waiting_for_lock ; Leave
|
||||
;
|
||||
; }
|
||||
; else
|
||||
; {
|
||||
; /* We have the lock. This means the ISR got the inter-core lock, but
|
||||
; never released it because it saw that there was someone waiting.
|
||||
; Note this core is not in the list. */
|
||||
;
|
||||
_this_core_has_lock
|
||||
;
|
||||
; /* We're no longer waiting. Note that this should be zero since this happens during thread preemption. */
|
||||
; _tx_thread_smp_protect_wait_counts[core]--;
|
||||
;
|
||||
LDR r1, =_tx_thread_smp_protect_wait_counts ; Load waiting count list
|
||||
LDR r2, [r1, r10, LSL #2] ; Load waiting value for this core
|
||||
SUB r2, r2, #1 ; Decrement waiting value. Should be zero now
|
||||
STR r2, [r1, r10, LSL #2] ; Store new waiting value
|
||||
;
|
||||
; /* Now release the inter-core lock. */
|
||||
;
|
||||
; /* Set protected core as invalid. */
|
||||
; _tx_thread_smp_protection.tx_thread_smp_protect_core = 0xFFFFFFFF;
|
||||
;
|
||||
LDR r1, =_tx_thread_smp_protection ; Load address of protection structure
|
||||
MOV r2, #0xFFFFFFFF ; Build invalid value
|
||||
STR r2, [r1, #8] ; Mark the protected core as invalid
|
||||
DMB ; Ensure that accesses to shared resource have completed
|
||||
;
|
||||
; /* Release protection. */
|
||||
; _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 0;
|
||||
;
|
||||
MOV r2, #0 ; Build release protection value
|
||||
STR r2, [r1, #0] ; Release the protection
|
||||
DSB ISH ; To ensure update of the protection occurs before other CPUs awake
|
||||
;
|
||||
; /* Wake up waiting processors. Note interrupts are already enabled. */
|
||||
;
|
||||
IF :DEF:TX_ENABLE_WFE
|
||||
SEV ; Send event to other CPUs
|
||||
ENDIF
|
||||
;
|
||||
; }
|
||||
; }
|
||||
;
|
||||
|
||||
_nobody_waiting_for_lock
|
||||
|
||||
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!, {D16-D31} ; Save D16-D31
|
||||
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)
|
||||
STR r2, [r0, #152] ; Make this thread ready for executing again
|
||||
DMB ; Ensure that accesses to shared resource have completed
|
||||
;
|
||||
; /* 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
|
||||
|
||||
203
ports_smp/cortex_a7_smp/ac5/src/tx_thread_context_save.s
Normal file
203
ports_smp/cortex_a7_smp/ac5/src/tx_thread_context_save.s
Normal file
@@ -0,0 +1,203 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;
|
||||
;
|
||||
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-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;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
|
||||
|
||||
102
ports_smp/cortex_a7_smp/ac5/src/tx_thread_interrupt_control.s
Normal file
102
ports_smp/cortex_a7_smp/ac5/src/tx_thread_interrupt_control.s
Normal file
@@ -0,0 +1,102 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;
|
||||
;
|
||||
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-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;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
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;
|
||||
;
|
||||
AREA ||.text||, CODE, READONLY
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_interrupt_disable SMP/Cortex-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;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
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;
|
||||
;
|
||||
AREA ||.text||, CODE, READONLY
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_interrupt_restore SMP/Cortex-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;UINT _tx_thread_interrupt_restore(UINT old_posture)
|
||||
;{
|
||||
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
|
||||
|
||||
110
ports_smp/cortex_a7_smp/ac5/src/tx_thread_irq_nesting_end.s
Normal file
110
ports_smp/cortex_a7_smp/ac5/src/tx_thread_irq_nesting_end.s
Normal file
@@ -0,0 +1,110 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;
|
||||
;
|
||||
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-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;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
|
||||
|
||||
104
ports_smp/cortex_a7_smp/ac5/src/tx_thread_irq_nesting_start.s
Normal file
104
ports_smp/cortex_a7_smp/ac5/src/tx_thread_irq_nesting_start.s
Normal file
@@ -0,0 +1,104 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;
|
||||
;
|
||||
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-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;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
|
||||
|
||||
314
ports_smp/cortex_a7_smp/ac5/src/tx_thread_schedule.s
Normal file
314
ports_smp/cortex_a7_smp/ac5/src/tx_thread_schedule.s
Normal file
@@ -0,0 +1,314 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h"
|
||||
;
|
||||
;
|
||||
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-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;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);
|
||||
;
|
||||
; /* Get the lock for accessing the thread's ready bit. */
|
||||
;
|
||||
MOV r2, #172 ; Build offset to the lock
|
||||
ADD r2, r0, r2 ; Get the address to the lock
|
||||
LDREX r3, [r2] ; Pickup the lock value
|
||||
CMP r3, #0 ; Check if it's available
|
||||
BNE _tx_thread_schedule ; No, lock not available
|
||||
MOV r3, #1 ; Build the lock set value
|
||||
STREX r4, r3, [r2] ; Try to get the lock
|
||||
CMP r4, #0 ; Check if we got the lock
|
||||
BNE _tx_thread_schedule ; No, another core got it first
|
||||
DMB ; Ensure write to lock completes
|
||||
;
|
||||
; /* Now make sure the thread's ready bit is set. */
|
||||
;
|
||||
LDR r3, [r0, #152] ; Pickup the thread ready bit
|
||||
AND r4, r3, #0x8000 ; Isolate the ready bit
|
||||
CMP r4, #0 ; Is it set?
|
||||
BNE _tx_thread_ready_for_execution ; Yes, schedule the thread
|
||||
;
|
||||
; /* The ready bit isn't set. Release the lock and jump back to the scheduler. */
|
||||
;
|
||||
MOV r3, #0 ; Build clear value
|
||||
STR r3, [r2] ; Release the lock
|
||||
DMB ; Ensure write to lock completes
|
||||
B _tx_thread_schedule ; Jump back to the scheduler
|
||||
;
|
||||
_tx_thread_ready_for_execution
|
||||
;
|
||||
; /* We have a thread to execute. */
|
||||
;
|
||||
; /* Clear the ready bit and release the lock. */
|
||||
;
|
||||
BIC r3, r3, #0x8000 ; Clear ready bit
|
||||
STR r3, [r0, #152] ; Store it back in the thread control block
|
||||
DMB
|
||||
MOV r3, #0 ; Build clear value for the lock
|
||||
STR r3, [r2] ; Release the lock
|
||||
DMB
|
||||
;
|
||||
; /* Setup the current thread pointer. */
|
||||
; _tx_thread_current_ptr[core] = _tx_thread_execute_ptr[core];
|
||||
;
|
||||
LDR r2, =_tx_thread_current_ptr ; Pickup address of current thread
|
||||
ADD r2, r2, r12 ; Build index into the current thread array
|
||||
STR r0, [r2, #0] ; Setup current thread pointer
|
||||
;
|
||||
; /* In the time between reading the execute pointer and assigning
|
||||
; it to the current pointer, the execute pointer was changed by
|
||||
; some external code. If the current pointer was still null when
|
||||
; the external code checked if a core preempt was necessary, then
|
||||
; it wouldn't have done it and a preemption will be missed. To
|
||||
; handle this, undo some things and jump back to the scheduler so
|
||||
; it can schedule the new thread. */
|
||||
;
|
||||
LDR r1, [r1, #0] ; Reload the execute pointer
|
||||
CMP r0, r1 ; Did it change?
|
||||
BEQ _execute_pointer_did_not_change ; If not, skip handling
|
||||
|
||||
MOV r1, #0 ; Build clear value
|
||||
STR r1, [r2, #0] ; Clear current thread pointer
|
||||
|
||||
LDR r1, [r0, #152] ; Pickup the ready bit
|
||||
ORR r1, r1, #0x8000 ; Set ready bit (bit 15)
|
||||
STR r1, [r0, #152] ; Make this thread ready for executing again
|
||||
DMB ; Ensure that accesses to shared resource have completed
|
||||
|
||||
B _tx_thread_schedule ; Jump back to the scheduler to schedule the new thread
|
||||
|
||||
_execute_pointer_did_not_change
|
||||
;
|
||||
; /* 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
|
||||
VLDMIA sp!, {D16-D31} ; Recover D16-D31
|
||||
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!, {D8-D15} ; Recover D8-D15
|
||||
VLDMIA sp!, {D16-D31} ; Recover D16-D31
|
||||
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
|
||||
|
||||
85
ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_core_get.s
Normal file
85
ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_core_get.s
Normal file
@@ -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 - Low Level SMP Support */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;#define TX_THREAD_SMP_SOURCE_CODE
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h" */
|
||||
;
|
||||
;
|
||||
AREA ||.text||, CODE, READONLY
|
||||
PRESERVE8
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_smp_core_get SMP/Cortex-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
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
|
||||
|
||||
101
ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_core_preempt.s
Normal file
101
ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_core_preempt.s
Normal file
@@ -0,0 +1,101 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 - Low Level SMP Support */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;#define TX_THREAD_SMP_SOURCE_CODE
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h" */
|
||||
;
|
||||
;
|
||||
IMPORT sendSGI
|
||||
|
||||
AREA ||.text||, CODE, READONLY
|
||||
PRESERVE8
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_smp_core_preempt SMP/Cortex-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
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 sendSGI ; 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
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 - Low Level SMP Support */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;#define TX_THREAD_SMP_SOURCE_CODE
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h" */
|
||||
;
|
||||
;
|
||||
IMPORT _tx_thread_system_state
|
||||
|
||||
AREA ||.text||, CODE, READONLY
|
||||
PRESERVE8
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_smp_current_state_get SMP/Cortex-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
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
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 - Low Level SMP Support */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;#define TX_THREAD_SMP_SOURCE_CODE
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h" */
|
||||
;
|
||||
;
|
||||
IMPORT _tx_thread_current_ptr
|
||||
|
||||
AREA ||.text||, CODE, READONLY
|
||||
PRESERVE8
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_smp_current_thread_get SMP/Cortex-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
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
|
||||
|
||||
140
ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_initialize_wait.s
Normal file
140
ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_initialize_wait.s
Normal file
@@ -0,0 +1,140 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 - Low Level SMP Support */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;#define TX_THREAD_SMP_SOURCE_CODE
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h" */
|
||||
;
|
||||
;
|
||||
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-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
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
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 - Low Level SMP Support */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;#define TX_THREAD_SMP_SOURCE_CODE
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h" */
|
||||
;
|
||||
;
|
||||
AREA ||.text||, CODE, READONLY
|
||||
PRESERVE8
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_smp_low_level_initialize SMP/Cortex-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
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
|
||||
|
||||
370
ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_protect.s
Normal file
370
ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_protect.s
Normal file
@@ -0,0 +1,370 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 - Low Level SMP Support */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;#define TX_THREAD_SMP_SOURCE_CODE
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h" */
|
||||
|
||||
;/* Include macros for modifying the wait list. */
|
||||
#include "tx_thread_smp_protection_wait_list_macros.h"
|
||||
|
||||
IMPORT _tx_thread_current_ptr
|
||||
IMPORT _tx_thread_smp_protection
|
||||
IMPORT _tx_thread_smp_protect_wait_counts
|
||||
IMPORT _tx_thread_smp_protect_wait_list
|
||||
IMPORT _tx_thread_smp_protect_wait_list_lock_protect_in_force
|
||||
IMPORT _tx_thread_smp_protect_wait_list_head
|
||||
IMPORT _tx_thread_smp_protect_wait_list_tail
|
||||
IMPORT _tx_thread_smp_protect_wait_list_size
|
||||
|
||||
AREA ||.text||, CODE, READONLY
|
||||
PRESERVE8
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_smp_protect SMP/Cortex-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
EXPORT _tx_thread_smp_protect
|
||||
_tx_thread_smp_protect
|
||||
;VOID _tx_thread_smp_protect(VOID)
|
||||
;{
|
||||
;
|
||||
PUSH {r4-r6} ; Save registers we'll be using
|
||||
;
|
||||
; /* Disable interrupts so we don't get preempted. */
|
||||
;
|
||||
MRS r0, CPSR ; Pickup current CPSR
|
||||
|
||||
IF :DEF:TX_ENABLE_FIQ_SUPPORT
|
||||
CPSID if ; Disable IRQ and FIQ interrupts
|
||||
ELSE
|
||||
CPSID i ; Disable IRQ interrupts
|
||||
ENDIF
|
||||
;
|
||||
; /* Do we already have protection? */
|
||||
; if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core)
|
||||
; {
|
||||
;
|
||||
MRC p15, 0, r1, c0, c0, 5 ; Read CPU ID register
|
||||
AND r1, r1, #0x03 ; Mask off, leaving the CPU ID field
|
||||
LDR r2, =_tx_thread_smp_protection ; Build address to protection structure
|
||||
LDR r3, [r2, #8] ; Pickup the owning core
|
||||
CMP r1, r3 ; Is it not this core?
|
||||
BNE _protection_not_owned ; No, the protection is not already owned
|
||||
;
|
||||
; /* We already have protection. */
|
||||
;
|
||||
; /* Increment the protection count. */
|
||||
; _tx_thread_smp_protection.tx_thread_smp_protect_count++;
|
||||
;
|
||||
LDR r3, [r2, #12] ; Pickup ownership count
|
||||
ADD r3, r3, #1 ; Increment ownership count
|
||||
STR r3, [r2, #12] ; Store ownership count
|
||||
DMB
|
||||
|
||||
B _return
|
||||
|
||||
_protection_not_owned
|
||||
;
|
||||
; /* Is the lock available? */
|
||||
; if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0)
|
||||
; {
|
||||
;
|
||||
LDREX r3, [r2, #0] ; Pickup the protection flag
|
||||
CMP r3, #0
|
||||
BNE _start_waiting ; No, protection not available
|
||||
;
|
||||
; /* Is the list empty? */
|
||||
; if (_tx_thread_smp_protect_wait_list_head == _tx_thread_smp_protect_wait_list_tail)
|
||||
; {
|
||||
;
|
||||
LDR r3, =_tx_thread_smp_protect_wait_list_head
|
||||
LDR r3, [r3]
|
||||
LDR r4, =_tx_thread_smp_protect_wait_list_tail
|
||||
LDR r4, [r4]
|
||||
CMP r3, r4
|
||||
BNE _list_not_empty
|
||||
;
|
||||
; /* Try to get the lock. */
|
||||
; if (write_exclusive(&_tx_thread_smp_protection.tx_thread_smp_protect_in_force, 1) == SUCCESS)
|
||||
; {
|
||||
;
|
||||
MOV r3, #1 ; Build lock value
|
||||
STREX r4, r3, [r2, #0] ; Attempt to get the protection
|
||||
CMP r4, #0
|
||||
BNE _start_waiting ; Did it fail?
|
||||
;
|
||||
; /* We got the lock! */
|
||||
; _tx_thread_smp_protect_lock_got();
|
||||
;
|
||||
DMB ; Ensure write to protection finishes
|
||||
macro_call0 _tx_thread_smp_protect_lock_got ; Call the lock got function
|
||||
|
||||
B _return
|
||||
|
||||
_list_not_empty
|
||||
;
|
||||
; /* Are we at the front of the list? */
|
||||
; if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head])
|
||||
; {
|
||||
;
|
||||
LDR r3, =_tx_thread_smp_protect_wait_list_head ; Get the address of the head
|
||||
LDR r3, [r3] ; Get the value of the head
|
||||
LDR r4, =_tx_thread_smp_protect_wait_list ; Get the address of the list
|
||||
LDR r4, [r4, r3, LSL #2] ; Get the value at the head index
|
||||
|
||||
CMP r1, r4
|
||||
BNE _start_waiting
|
||||
;
|
||||
; /* Is the lock still available? */
|
||||
; if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0)
|
||||
; {
|
||||
;
|
||||
LDR r3, [r2, #0] ; Pickup the protection flag
|
||||
CMP r3, #0
|
||||
BNE _start_waiting ; No, protection not available
|
||||
;
|
||||
; /* Get the lock. */
|
||||
; _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1;
|
||||
;
|
||||
MOV r3, #1 ; Build lock value
|
||||
STR r3, [r2, #0] ; Store lock value
|
||||
DMB ;
|
||||
;
|
||||
; /* Got the lock. */
|
||||
; _tx_thread_smp_protect_lock_got();
|
||||
;
|
||||
macro_call1 _tx_thread_smp_protect_lock_got
|
||||
;
|
||||
; /* Remove this core from the wait list. */
|
||||
; _tx_thread_smp_protect_remove_from_front_of_list();
|
||||
;
|
||||
macro_call2 _tx_thread_smp_protect_remove_from_front_of_list
|
||||
|
||||
B _return
|
||||
|
||||
_start_waiting
|
||||
;
|
||||
; /* For one reason or another, we didn't get the lock. */
|
||||
;
|
||||
; /* Increment wait count. */
|
||||
; _tx_thread_smp_protect_wait_counts[this_core]++;
|
||||
;
|
||||
LDR r3, =_tx_thread_smp_protect_wait_counts ; Load wait list counts
|
||||
LDR r4, [r3, r1, LSL #2] ; Load waiting value for this core
|
||||
ADD r4, r4, #1 ; Increment wait value
|
||||
STR r4, [r3, r1, LSL #2] ; Store new wait value
|
||||
;
|
||||
; /* Have we not added ourselves to the list yet? */
|
||||
; if (_tx_thread_smp_protect_wait_counts[this_core] == 1)
|
||||
; {
|
||||
;
|
||||
CMP r4, #1
|
||||
BNE _already_in_list0 ; Is this core already waiting?
|
||||
;
|
||||
; /* Add ourselves to the list. */
|
||||
; _tx_thread_smp_protect_wait_list_add(this_core);
|
||||
;
|
||||
macro_call3 _tx_thread_smp_protect_wait_list_add ; Call macro to add ourselves to the list
|
||||
;
|
||||
; }
|
||||
;
|
||||
_already_in_list0
|
||||
;
|
||||
; /* Restore interrupts. */
|
||||
;
|
||||
MSR CPSR_c, r0 ; Restore CPSR
|
||||
IF :DEF:TX_ENABLE_WFE
|
||||
WFE ; Go into standby
|
||||
ENDIF
|
||||
;
|
||||
; /* We do this until we have the lock. */
|
||||
; while (1)
|
||||
; {
|
||||
;
|
||||
_try_to_get_lock
|
||||
;
|
||||
; /* Disable interrupts so we don't get preempted. */
|
||||
;
|
||||
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
|
||||
;
|
||||
; /* Do we already have protection? */
|
||||
; if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core)
|
||||
; {
|
||||
;
|
||||
LDR r3, [r2, #8] ; Pickup the owning core
|
||||
CMP r3, r1 ; Is it this core?
|
||||
BEQ _got_lock_after_waiting ; Yes, the protection is already owned. This means
|
||||
; an ISR preempted us and got protection
|
||||
;
|
||||
; }
|
||||
;
|
||||
; /* Are we at the front of the list? */
|
||||
; if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head])
|
||||
; {
|
||||
;
|
||||
LDR r3, =_tx_thread_smp_protect_wait_list_head ; Get the address of the head
|
||||
LDR r3, [r3] ; Get the value of the head
|
||||
LDR r4, =_tx_thread_smp_protect_wait_list ; Get the address of the list
|
||||
LDR r4, [r4, r3, LSL #2] ; Get the value at the head index
|
||||
|
||||
CMP r1, r4
|
||||
BNE _did_not_get_lock
|
||||
;
|
||||
; /* Is the lock still available? */
|
||||
; if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0)
|
||||
; {
|
||||
;
|
||||
LDR r3, [r2, #0] ; Pickup the protection flag
|
||||
CMP r3, #0
|
||||
BNE _did_not_get_lock ; No, protection not available
|
||||
;
|
||||
; /* Get the lock. */
|
||||
; _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1;
|
||||
;
|
||||
MOV r3, #1 ; Build lock value
|
||||
STR r3, [r2, #0] ; Store lock value
|
||||
DMB ;
|
||||
;
|
||||
; /* Got the lock. */
|
||||
; _tx_thread_smp_protect_lock_got();
|
||||
;
|
||||
macro_call4 _tx_thread_smp_protect_lock_got
|
||||
;
|
||||
; /* Remove this core from the wait list. */
|
||||
; _tx_thread_smp_protect_remove_from_front_of_list();
|
||||
;
|
||||
macro_call5 _tx_thread_smp_protect_remove_from_front_of_list
|
||||
|
||||
B _got_lock_after_waiting
|
||||
|
||||
_did_not_get_lock
|
||||
;
|
||||
; /* For one reason or another, we didn't get the lock. */
|
||||
;
|
||||
; /* Were we removed from the list? This can happen if we're a thread
|
||||
; and we got preempted. */
|
||||
; if (_tx_thread_smp_protect_wait_counts[this_core] == 0)
|
||||
; {
|
||||
;
|
||||
LDR r3, =_tx_thread_smp_protect_wait_counts ; Load wait list counts
|
||||
LDR r4, [r3, r1, LSL #2] ; Load waiting value for this core
|
||||
CMP r4, #0
|
||||
BNE _already_in_list1 ; Is this core already in the list?
|
||||
;
|
||||
; /* Add ourselves to the list. */
|
||||
; _tx_thread_smp_protect_wait_list_add(this_core);
|
||||
;
|
||||
macro_call6 _tx_thread_smp_protect_wait_list_add ; Call macro to add ourselves to the list
|
||||
;
|
||||
; /* Our waiting count was also reset when we were preempted. Increment it again. */
|
||||
; _tx_thread_smp_protect_wait_counts[this_core]++;
|
||||
;
|
||||
LDR r3, =_tx_thread_smp_protect_wait_counts ; Load wait list counts
|
||||
LDR r4, [r3, r1, LSL #2] ; Load waiting value for this core
|
||||
ADD r4, r4, #1 ; Increment wait value
|
||||
STR r4, [r3, r1, LSL #2] ; Store new wait value value
|
||||
;
|
||||
; }
|
||||
;
|
||||
_already_in_list1
|
||||
;
|
||||
; /* Restore interrupts and try again. */
|
||||
;
|
||||
MSR CPSR_c, r0 ; Restore CPSR
|
||||
IF :DEF:TX_ENABLE_WFE
|
||||
WFE ; Go into standby
|
||||
ENDIF
|
||||
B _try_to_get_lock ; On waking, restart the protection attempt
|
||||
|
||||
_got_lock_after_waiting
|
||||
;
|
||||
; /* We're no longer waiting. */
|
||||
; _tx_thread_smp_protect_wait_counts[this_core]--;
|
||||
;
|
||||
LDR r3, =_tx_thread_smp_protect_wait_counts ; Load waiting list
|
||||
LDR r4, [r3, r1, LSL #2] ; Load current wait value
|
||||
SUB r4, r4, #1 ; Decrement wait value
|
||||
STR r4, [r3, r1, LSL #2] ; Store new wait value value
|
||||
|
||||
;
|
||||
; /* Restore link register and return. */
|
||||
;
|
||||
_return
|
||||
|
||||
POP {r4-r6} ; Restore registers
|
||||
|
||||
IF {INTER} = {TRUE}
|
||||
BX lr ; Return to caller
|
||||
ELSE
|
||||
MOV pc, lr ; Return to caller
|
||||
ENDIF
|
||||
|
||||
END
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 - Low Level SMP Support */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
|
||||
MACRO
|
||||
$label _tx_thread_smp_protect_lock_got
|
||||
;
|
||||
; /* Set the currently owned core. */
|
||||
; _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core;
|
||||
;
|
||||
STR r1, [r2, #8] ; Store this core
|
||||
;
|
||||
; /* Increment the protection count. */
|
||||
; _tx_thread_smp_protection.tx_thread_smp_protect_count++;
|
||||
;
|
||||
LDR r3, [r2, #12] ; Pickup ownership count
|
||||
ADD r3, r3, #1 ; Increment ownership count
|
||||
STR r3, [r2, #12] ; Store ownership count
|
||||
DMB
|
||||
|
||||
IF :DEF:TX_MPCORE_DEBUG_ENABLE
|
||||
LSL r3, r1, #2 ; Build offset to array indexes
|
||||
LDR r4, =_tx_thread_current_ptr ; Pickup start of the current thread array
|
||||
ADD r4, r3, r4 ; Build index into the current thread array
|
||||
LDR r3, [r4] ; Pickup current thread for this core
|
||||
STR r3, [r2, #4] ; Save current thread pointer
|
||||
STR LR, [r2, #16] ; Save caller's return address
|
||||
STR r0, [r2, #20] ; Save CPSR
|
||||
ENDIF
|
||||
|
||||
MEND
|
||||
|
||||
MACRO
|
||||
$label _tx_thread_smp_protect_remove_from_front_of_list
|
||||
;
|
||||
; /* Remove ourselves from the list. */
|
||||
; _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head++] = 0xFFFFFFFF;
|
||||
;
|
||||
MOV r3, #0xFFFFFFFF ; Build the invalid core value
|
||||
LDR r4, =_tx_thread_smp_protect_wait_list_head ; Get the address of the head
|
||||
LDR r5, [r4] ; Get the value of the head
|
||||
LDR r6, =_tx_thread_smp_protect_wait_list ; Get the address of the list
|
||||
STR r3, [r6, r5, LSL #2] ; Store the invalid core value
|
||||
ADD r5, r5, #1 ; Increment the head
|
||||
;
|
||||
; /* Did we wrap? */
|
||||
; if (_tx_thread_smp_protect_wait_list_head == TX_THREAD_SMP_MAX_CORES + 1)
|
||||
; {
|
||||
;
|
||||
LDR r3, =_tx_thread_smp_protect_wait_list_size ; Load address of core list size
|
||||
LDR r3, [r3] ; Load the max cores value
|
||||
CMP r5, r3 ; Compare the head to it
|
||||
BNE $label._store_new_head ; Are we at the max?
|
||||
;
|
||||
; _tx_thread_smp_protect_wait_list_head = 0;
|
||||
;
|
||||
EOR r5, r5, r5 ; We're at the max. Set it to zero
|
||||
;
|
||||
; }
|
||||
;
|
||||
$label._store_new_head
|
||||
|
||||
STR r5, [r4] ; Store the new head
|
||||
;
|
||||
; /* We have the lock! */
|
||||
; return;
|
||||
;
|
||||
MEND
|
||||
|
||||
|
||||
MACRO
|
||||
$label _tx_thread_smp_protect_wait_list_lock_get
|
||||
;VOID _tx_thread_smp_protect_wait_list_lock_get()
|
||||
;{
|
||||
; /* We do this until we have the lock. */
|
||||
; while (1)
|
||||
; {
|
||||
;
|
||||
$label._tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock
|
||||
;
|
||||
; /* Is the list lock available? */
|
||||
; _tx_thread_smp_protect_wait_list_lock_protect_in_force = load_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force);
|
||||
;
|
||||
LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force
|
||||
LDREX r2, [r1] ; Pickup the protection flag
|
||||
;
|
||||
; if (protect_in_force == 0)
|
||||
; {
|
||||
;
|
||||
CMP r2, #0
|
||||
BNE $label._tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock ; No, protection not available
|
||||
;
|
||||
; /* Try to get the list. */
|
||||
; int status = store_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force, 1);
|
||||
;
|
||||
MOV r2, #1 ; Build lock value
|
||||
STREX r3, r2, [r1] ; Attempt to get the protection
|
||||
;
|
||||
; if (status == SUCCESS)
|
||||
;
|
||||
CMP r3, #0
|
||||
BNE $label._tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock ; Did it fail? If so, try again.
|
||||
;
|
||||
; /* We have the lock! */
|
||||
; return;
|
||||
;
|
||||
MEND
|
||||
|
||||
|
||||
MACRO
|
||||
$label _tx_thread_smp_protect_wait_list_add
|
||||
;VOID _tx_thread_smp_protect_wait_list_add(UINT new_core)
|
||||
;{
|
||||
;
|
||||
; /* We're about to modify the list, so get the list lock. */
|
||||
; _tx_thread_smp_protect_wait_list_lock_get();
|
||||
;
|
||||
PUSH {r1-r2}
|
||||
|
||||
$label _tx_thread_smp_protect_wait_list_lock_get
|
||||
|
||||
POP {r1-r2}
|
||||
;
|
||||
; /* Add this core. */
|
||||
; _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_tail++] = new_core;
|
||||
;
|
||||
LDR r3, =_tx_thread_smp_protect_wait_list_tail ; Get the address of the tail
|
||||
LDR r4, [r3] ; Get the value of tail
|
||||
LDR r5, =_tx_thread_smp_protect_wait_list ; Get the address of the list
|
||||
STR r1, [r5, r4, LSL #2] ; Store the new core value
|
||||
ADD r4, r4, #1 ; Increment the tail
|
||||
;
|
||||
; /* Did we wrap? */
|
||||
; if (_tx_thread_smp_protect_wait_list_tail == _tx_thread_smp_protect_wait_list_size)
|
||||
; {
|
||||
;
|
||||
LDR r5, =_tx_thread_smp_protect_wait_list_size ; Load max cores address
|
||||
LDR r5, [r5] ; Load max cores value
|
||||
CMP r4, r5 ; Compare max cores to tail
|
||||
BNE $label._tx_thread_smp_protect_wait_list_add__no_wrap ; Did we wrap?
|
||||
;
|
||||
; _tx_thread_smp_protect_wait_list_tail = 0;
|
||||
;
|
||||
MOV r4, #0
|
||||
;
|
||||
; }
|
||||
;
|
||||
$label._tx_thread_smp_protect_wait_list_add__no_wrap
|
||||
|
||||
STR r4, [r3] ; Store the new tail value.
|
||||
;
|
||||
; /* Release the list lock. */
|
||||
; _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0;
|
||||
;
|
||||
MOV r3, #0 ; Build lock value
|
||||
LDR r4, =_tx_thread_smp_protect_wait_list_lock_protect_in_force
|
||||
STR r3, [r4] ; Store the new value
|
||||
|
||||
MEND
|
||||
|
||||
|
||||
MACRO
|
||||
$label _tx_thread_smp_protect_wait_list_remove
|
||||
;VOID _tx_thread_smp_protect_wait_list_remove(UINT core)
|
||||
;{
|
||||
;
|
||||
; /* Get the core index. */
|
||||
; UINT core_index;
|
||||
; for (core_index = 0;; core_index++)
|
||||
;
|
||||
EOR r1, r1, r1 ; Clear for 'core_index'
|
||||
LDR r2, =_tx_thread_smp_protect_wait_list ; Get the address of the list
|
||||
;
|
||||
; {
|
||||
;
|
||||
$label._tx_thread_smp_protect_wait_list_remove__check_cur_core
|
||||
;
|
||||
; /* Is this the core? */
|
||||
; if (_tx_thread_smp_protect_wait_list[core_index] == core)
|
||||
; {
|
||||
; break;
|
||||
;
|
||||
LDR r3, [r2, r1, LSL #2] ; Get the value at the current index
|
||||
CMP r3, r10 ; Did we find the core?
|
||||
BEQ $label._tx_thread_smp_protect_wait_list_remove__found_core
|
||||
;
|
||||
; }
|
||||
;
|
||||
ADD r1, r1, #1 ; Increment cur index
|
||||
B $label._tx_thread_smp_protect_wait_list_remove__check_cur_core ; Restart the loop
|
||||
;
|
||||
; }
|
||||
;
|
||||
$label._tx_thread_smp_protect_wait_list_remove__found_core
|
||||
;
|
||||
; /* We're about to modify the list. Get the lock. We need the lock because another
|
||||
; core could be simultaneously adding (a core is simultaneously trying to get
|
||||
; the inter-core lock) or removing (a core is simultaneously being preempted,
|
||||
; like what is currently happening). */
|
||||
; _tx_thread_smp_protect_wait_list_lock_get();
|
||||
;
|
||||
PUSH {r1}
|
||||
|
||||
$label _tx_thread_smp_protect_wait_list_lock_get
|
||||
|
||||
POP {r1}
|
||||
;
|
||||
; /* We remove by shifting. */
|
||||
; while (core_index != _tx_thread_smp_protect_wait_list_tail)
|
||||
; {
|
||||
;
|
||||
$label._tx_thread_smp_protect_wait_list_remove__compare_index_to_tail
|
||||
|
||||
LDR r2, =_tx_thread_smp_protect_wait_list_tail ; Load tail address
|
||||
LDR r2, [r2] ; Load tail value
|
||||
CMP r1, r2 ; Compare cur index and tail
|
||||
BEQ $label._tx_thread_smp_protect_wait_list_remove__removed
|
||||
;
|
||||
; UINT next_index = core_index + 1;
|
||||
;
|
||||
MOV r2, r1 ; Move current index to next index register
|
||||
ADD r2, r2, #1 ; Add 1
|
||||
;
|
||||
; if (next_index == _tx_thread_smp_protect_wait_list_size)
|
||||
; {
|
||||
;
|
||||
LDR r3, =_tx_thread_smp_protect_wait_list_size
|
||||
LDR r3, [r3]
|
||||
CMP r2, r3
|
||||
BNE $label._tx_thread_smp_protect_wait_list_remove__next_index_no_wrap
|
||||
;
|
||||
; next_index = 0;
|
||||
;
|
||||
MOV r2, #0
|
||||
;
|
||||
; }
|
||||
;
|
||||
$label._tx_thread_smp_protect_wait_list_remove__next_index_no_wrap
|
||||
;
|
||||
; list_cores[core_index] = list_cores[next_index];
|
||||
;
|
||||
LDR r0, =_tx_thread_smp_protect_wait_list ; Get the address of the list
|
||||
LDR r3, [r0, r2, LSL #2] ; Get the value at the next index
|
||||
STR r3, [r0, r1, LSL #2] ; Store the value at the current index
|
||||
;
|
||||
; core_index = next_index;
|
||||
;
|
||||
MOV r1, r2
|
||||
|
||||
B $label._tx_thread_smp_protect_wait_list_remove__compare_index_to_tail
|
||||
;
|
||||
; }
|
||||
;
|
||||
$label._tx_thread_smp_protect_wait_list_remove__removed
|
||||
;
|
||||
; /* Now update the tail. */
|
||||
; if (_tx_thread_smp_protect_wait_list_tail == 0)
|
||||
; {
|
||||
;
|
||||
LDR r0, =_tx_thread_smp_protect_wait_list_tail ; Load tail address
|
||||
LDR r1, [r0] ; Load tail value
|
||||
CMP r1, #0
|
||||
BNE $label._tx_thread_smp_protect_wait_list_remove__tail_not_zero
|
||||
;
|
||||
; _tx_thread_smp_protect_wait_list_tail = _tx_thread_smp_protect_wait_list_size;
|
||||
;
|
||||
LDR r2, =_tx_thread_smp_protect_wait_list_size
|
||||
LDR r1, [r2]
|
||||
;
|
||||
; }
|
||||
;
|
||||
$label._tx_thread_smp_protect_wait_list_remove__tail_not_zero
|
||||
;
|
||||
; _tx_thread_smp_protect_wait_list_tail--;
|
||||
;
|
||||
SUB r1, r1, #1
|
||||
STR r1, [r0] ; Store new tail value
|
||||
;
|
||||
; /* Release the list lock. */
|
||||
; _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0;
|
||||
;
|
||||
MOV r0, #0 ; Build lock value
|
||||
LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force ; Load lock address
|
||||
STR r0, [r1] ; Store the new value
|
||||
;
|
||||
; /* We're no longer waiting. Note that this should be zero since, again,
|
||||
; this function is only called when a thread preemption is occurring. */
|
||||
; _tx_thread_smp_protect_wait_counts[core]--;
|
||||
;
|
||||
LDR r1, =_tx_thread_smp_protect_wait_counts ; Load wait list counts
|
||||
LDR r2, [r1, r10, LSL #2] ; Load waiting value
|
||||
SUB r2, r2, #1 ; Subtract 1
|
||||
STR r2, [r1, r10, LSL #2] ; Store new waiting value
|
||||
MEND
|
||||
|
||||
88
ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_time_get.s
Normal file
88
ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_time_get.s
Normal file
@@ -0,0 +1,88 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 - Low Level SMP Support */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;#define TX_THREAD_SMP_SOURCE_CODE
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h" */
|
||||
;
|
||||
;
|
||||
|
||||
AREA ||.text||, CODE, READONLY
|
||||
PRESERVE8
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_smp_time_get SMP/Cortex-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
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
|
||||
|
||||
142
ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_unprotect.s
Normal file
142
ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_unprotect.s
Normal file
@@ -0,0 +1,142 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 - Low Level SMP Support */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;#define TX_THREAD_SMP_SOURCE_CODE
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h" */
|
||||
;
|
||||
;
|
||||
IMPORT _tx_thread_current_ptr
|
||||
IMPORT _tx_thread_smp_protection
|
||||
IMPORT _tx_thread_preempt_disable
|
||||
IMPORT _tx_thread_smp_protect_wait_counts
|
||||
|
||||
AREA ||.text||, CODE, READONLY
|
||||
PRESERVE8
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_smp_unprotect SMP/Cortex-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
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
|
||||
|
||||
MRC p15, 0, r1, c0, c0, 5 ; Read CPU ID register
|
||||
AND r1, r1, #0x03 ; Mask off, leaving the CPU ID field
|
||||
|
||||
LDR r2,=_tx_thread_smp_protection ; Build address of protection structure
|
||||
LDR r3, [r2, #8] ; Pickup the owning core
|
||||
CMP r1, r3 ; Is it this core?
|
||||
BNE _still_protected ; If this is not the owning core, protection is in force elsewhere
|
||||
|
||||
LDR r3, [r2, #12] ; Pickup the protection count
|
||||
CMP r3, #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 r3, r3, #1 ; Decrement the protection count
|
||||
STR r3, [r2, #12] ; Store the new count back
|
||||
CMP r3, #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
|
||||
|
||||
LDR r2,=_tx_thread_smp_protect_wait_counts ; Build build address of wait counts
|
||||
LDR r3, [r2, r1, LSL #2] ; Pickup wait list value
|
||||
CMP r3, #0 ; Are any entities on this core waiting?
|
||||
BNE _still_protected ; Yes, skip the protection release
|
||||
|
||||
LDR r2,=_tx_thread_smp_protection ; Build address of protection structure
|
||||
MOV r3, #0xFFFFFFFF ; Build invalid value
|
||||
STR r3, [r2, #8] ; Mark the protected core as invalid
|
||||
IF :DEF:TX_MPCORE_DEBUG_ENABLE
|
||||
STR LR, [r2, #16] ; Save caller's return address
|
||||
ENDIF
|
||||
DMB ; Ensure that accesses to shared resource have completed
|
||||
MOV r3, #0 ; Build release protection value
|
||||
STR r3, [r2, #0] ; Release the protection
|
||||
DSB ; To ensure update of the protection occurs before other CPUs awake
|
||||
IF :DEF:TX_ENABLE_WFE
|
||||
SEV ; Send event to other CPUs, wakes anyone waiting on the protection (using WFE)
|
||||
ENDIF
|
||||
|
||||
_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
|
||||
|
||||
172
ports_smp/cortex_a7_smp/ac5/src/tx_thread_stack_build.s
Normal file
172
ports_smp/cortex_a7_smp/ac5/src/tx_thread_stack_build.s
Normal file
@@ -0,0 +1,172 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;
|
||||
;
|
||||
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-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;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-A7 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
|
||||
|
||||
205
ports_smp/cortex_a7_smp/ac5/src/tx_thread_system_return.s
Normal file
205
ports_smp/cortex_a7_smp/ac5/src/tx_thread_system_return.s
Normal file
@@ -0,0 +1,205 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h"
|
||||
;
|
||||
;
|
||||
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-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;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!, {D16-D31} ; Save D16-D31
|
||||
VSTMDB sp!, {D8-D15} ; Save D8-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
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_thread.h"
|
||||
;
|
||||
;
|
||||
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-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;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
|
||||
|
||||
229
ports_smp/cortex_a7_smp/ac5/src/tx_timer_interrupt.s
Normal file
229
ports_smp/cortex_a7_smp/ac5/src/tx_timer_interrupt.s
Normal file
@@ -0,0 +1,229 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* 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 */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_timer.h"
|
||||
;#include "tx_thread.h"
|
||||
;
|
||||
;
|
||||
;Define Assembly language external references...
|
||||
;
|
||||
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-A7/AC5 */
|
||||
;/* 6.0.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, 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 */
|
||||
;/* */
|
||||
;/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;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
|
||||
|
||||
322
ports_smp/cortex_a7_smp/gnu/example_build/MP_GIC.S
Normal file
322
ports_smp/cortex_a7_smp/gnu/example_build/MP_GIC.S
Normal file
@@ -0,0 +1,322 @@
|
||||
@;==================================================================
|
||||
@; Cortex-A MPCore - GIC Code
|
||||
@;
|
||||
@; Copyright (c) 2011-2012 ARM Ltd. All rights reserved.
|
||||
@;==================================================================
|
||||
|
||||
.arm
|
||||
|
||||
@;==================================================================
|
||||
@; GIC. Generic Interrupt Controller Architecture Specification
|
||||
@;==================================================================
|
||||
@
|
||||
@ ; Interrupt Distributor offset from base of private peripheral space --> 0x1000
|
||||
@ ; CPU Interface offset from base of private peripheral space --> 0x2000
|
||||
@
|
||||
@ ; Typical calls to enable interrupt ID X:
|
||||
@ ; enableIntID(X) <-- Enable that ID
|
||||
@ ; setIntPriority(X, 0) <-- Set the priority of X to 0 (the max priority)
|
||||
@ ; setPriorityMask(0x1F) <-- Set CPU's priority mask to 0x1F (the lowest priority)
|
||||
@ ; enableGIC() <-- Enable the GIC (global)
|
||||
@ ; enableGICProcessorInterface() <-- Enable the CPU interface (local to the CPU)
|
||||
@
|
||||
@
|
||||
@ EXPORT enableGIC
|
||||
@ ; void enableGIC(void)
|
||||
@ ; Global enable of the Interrupt Distributor
|
||||
.text
|
||||
.align 2
|
||||
.global enableGIC
|
||||
.type enableGIC,function
|
||||
enableGIC:
|
||||
@ Get base address of private peripheral space
|
||||
MRC p15, 4, r0, c15, c0, 0 @ Read periph base address
|
||||
ADD r0, r0, #0x1000 @ Add the Distributor offset
|
||||
|
||||
LDR r1, [r0, #0x000] @ Read the Distributor Control Register (GICD_CTLR)
|
||||
ORR r1, r1, #0x01 @ Interrupts forwarded
|
||||
STR r1, [r0, #0x000] @ Write Distributor Control Register (GICD_CTLR)
|
||||
|
||||
BX lr
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT disableGIC
|
||||
@ ; void disableGIC(void)
|
||||
@ ; Global disable of the Interrupt Distributor
|
||||
.text
|
||||
.align 2
|
||||
.global disableGIC
|
||||
.type disableGIC,function
|
||||
disableGIC:
|
||||
@ Get base address of private peripheral space
|
||||
MRC p15, 4, r0, c15, c0, 0 @ Read periph base address
|
||||
ADD r0, r0, #0x1000 @ Add the Distributor offset
|
||||
|
||||
LDR r1, [r0, #0x000] @ Read the Distributor Control Register (GICD_CTLR)
|
||||
BIC r1, r1, #0x01 @ Interrupts not forwarded
|
||||
STR r1, [r0, #0x000] @ Write the Distributor Control Register (GICD_CTLR)
|
||||
|
||||
BX lr
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT enableIntID
|
||||
@ ; void enableIntID(unsigned int ID)
|
||||
@ ; Enables the interrupt source number ID
|
||||
.text
|
||||
.align 2
|
||||
.global enableIntID
|
||||
.type enableIntID,function
|
||||
enableIntID:
|
||||
@ Get base address of private peripheral 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 Interrupt Set-Enable Registers to the offset for the ID
|
||||
STR r3, [r0, r2] @ Store out (GICD_ISENABLERn)
|
||||
|
||||
BX lr
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT disableIntID
|
||||
@ ; void disableIntID(unsigned int ID)
|
||||
@ ; Disables the interrupt source number ID
|
||||
.text
|
||||
.align 2
|
||||
.global disableIntID
|
||||
.type disableIntID,function
|
||||
disableIntID:
|
||||
@ Get base address of private peripheral 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 Interrupt Clear-Enable Registers to the offset for the ID
|
||||
STR r3, [r0, r2] @ Store out (GICD_ICENABLERn)
|
||||
|
||||
BX lr
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT setIntPriority
|
||||
@ ; void setIntPriority(unsigned int ID, unsigned int priority)
|
||||
@ ; Sets the priority of the specifed ID
|
||||
@ ; r0 = ID
|
||||
@ ; r1 = priority
|
||||
.text
|
||||
.align 2
|
||||
.global setIntPriority
|
||||
.type setIntPriority,function
|
||||
setIntPriority:
|
||||
@ Get base address of private peripheral 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 Interrupt Priority 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 two 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 Interrupt Priority Registers (GICD_IPRIORITYRn)
|
||||
BIC r3, r3, r12 @ Clear appropriate field
|
||||
ORR r3, r3, r1 @ Now OR in the priority value
|
||||
STR r3, [r0] @ And store it back again (GICD_IPRIORITYRn)
|
||||
|
||||
BX lr
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT enableGICProcessorInterface
|
||||
@ ; void enableGICProcessorInterface(void)
|
||||
@ ; Enables the processor interface
|
||||
@ ; Must be done on each core separately
|
||||
.text
|
||||
.align 2
|
||||
.global enableGICProcessorInterface
|
||||
.type enableGICProcessorInterface,function
|
||||
enableGICProcessorInterface:
|
||||
@ Get base address of private peripheral space
|
||||
MRC p15, 4, r0, c15, c0, 0 @ Read periph base address
|
||||
ADD r0, r0, #0x2000 @ Add the CPU interface offset
|
||||
|
||||
LDR r1, [r0] @ Read the CPU Interface Control Register (GICC_CTLR)
|
||||
ORR r1, r1, #0x01 @ Set bit 0, the enable bit
|
||||
STR r1, [r0] @ Write the CPU Interface Control Register (GICC_CTLR)
|
||||
|
||||
BX lr
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT disableGICProcessorInterface
|
||||
@ ; void disableGICProcessorInterface(void)
|
||||
@ ; Disables the processor interface
|
||||
@ ; Must be done on each core separately
|
||||
.text
|
||||
.align 2
|
||||
.global disableGICProcessorInterface
|
||||
.type disableGICProcessorInterface,function
|
||||
disableGICProcessorInterface:
|
||||
@ Get base address of private peripheral space
|
||||
MRC p15, 4, r0, c15, c0, 0 @ Read periph base address
|
||||
ADD r0, r0, #0x2000 @ Add the CPU interface offset
|
||||
|
||||
LDR r1, [r0] @ Read the CPU Interface Control Register (GICC_CTLR)
|
||||
BIC r1, r1, #0x01 @ Clear bit 0, the enable bit
|
||||
STR r1, [r0] @ Write the CPU Interface Control Register (GICC_CTLR)
|
||||
|
||||
BX lr
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT setPriorityMask
|
||||
@ ; void setPriorityMask(unsigned int priority)
|
||||
@ ; Sets the Priority mask register for the CPU run on
|
||||
@ ; The reset value masks ALL interrupts!
|
||||
.text
|
||||
.align 2
|
||||
.global setPriorityMask
|
||||
.type setPriorityMask,function
|
||||
setPriorityMask:
|
||||
|
||||
@ Get base address of private peripheral space
|
||||
MRC p15, 4, r1, c15, c0, 0 @ Read periph base address
|
||||
ADD r1, r1, #0x2000 @ Add the CPU interface offset
|
||||
|
||||
STR r0, [r1, #0x0004] @ Write the Interrupt Priority Mask register (GICC_PMR)
|
||||
|
||||
BX lr
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT setBinaryPoint
|
||||
@ ; void setBinaryPoint(unsigned int priority)
|
||||
@ ; Sets the Binary Point Register for the CPU run on
|
||||
.text
|
||||
.align 2
|
||||
.global setBinaryPoint
|
||||
.type setBinaryPoint,function
|
||||
setBinaryPoint:
|
||||
|
||||
@ Get base address of private peripheral space
|
||||
MRC p15, 4, r1, c15, c0, 0 @ Read periph base address
|
||||
ADD r1, r1, #0x2000 @ Add the CPU interface offset
|
||||
|
||||
STR r0, [r1, #0x0008] @ Write the Binary Point Register (GICC_BPR)
|
||||
|
||||
BX lr
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT readIntAck
|
||||
@ ; unsigned int readIntAck(void)
|
||||
@ ; Returns the value of the Interrupt Acknowledge Register
|
||||
.text
|
||||
.align 2
|
||||
.global readIntAck
|
||||
.type readIntAck,function
|
||||
readIntAck:
|
||||
MRC p15, 4, r1, c15, c0, 0 @ Read periph base address
|
||||
ADD r1, r1, #0x2000 @ Add the CPU interface offset
|
||||
|
||||
LDR r0, [r1, #0x000C] @ Read the Interrupt Acknowledge Register (GICC_IAR)
|
||||
BX lr
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT writeEOI
|
||||
@ ; void writeEOI(unsigned int ID)
|
||||
@ ; Writes ID to the End Of Interrupt register
|
||||
.text
|
||||
.align 2
|
||||
.global writeEOI
|
||||
.type writeEOI,function
|
||||
writeEOI:
|
||||
|
||||
@ Get base address of private peripheral space
|
||||
MRC p15, 4, r1, c15, c0, 0 @ Read periph base address
|
||||
ADD r1, r1, #0x2000 @ Add the CPU interface offset
|
||||
|
||||
STR r0, [r1, #0x0010] @ Write ID to the End of Interrupt register (GICC_EOIR)
|
||||
|
||||
BX lr
|
||||
|
||||
@;==================================================================
|
||||
@; SGI
|
||||
@;==================================================================
|
||||
@
|
||||
@ EXPORT sendSGI
|
||||
@ ; void sendSGI(unsigned int ID, unsigned int target_list, unsigned int filter_list);
|
||||
@ ; Send a software generate interrupt
|
||||
.text
|
||||
.align 2
|
||||
.global sendSGI
|
||||
.type sendSGI,function
|
||||
sendSGI:
|
||||
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 (GICD_SGIR)
|
||||
|
||||
BX lr
|
||||
|
||||
@;==================================================================
|
||||
@; End of code
|
||||
@;==================================================================
|
||||
@
|
||||
@;==================================================================
|
||||
@; End of MP_GIC.s
|
||||
@;==================================================================
|
||||
117
ports_smp/cortex_a7_smp/gnu/example_build/MP_GIC.h
Normal file
117
ports_smp/cortex_a7_smp/gnu/example_build/MP_GIC.h
Normal file
@@ -0,0 +1,117 @@
|
||||
// ------------------------------------------------------------
|
||||
// Cortex-A MPCore - Interrupt Controller functions
|
||||
// Header File
|
||||
//
|
||||
// Copyright (c) 2011 ARM Ltd. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#ifndef _CORTEXA_GIC_H
|
||||
#define _CORTEXA_GIC_H
|
||||
|
||||
#define SPURIOUS (255)
|
||||
|
||||
// PPI IDs:
|
||||
#define MPCORE_PPI_PRIVATE_TIMER (29)
|
||||
#define MPCORE_PPI_PRIVATE_WD (30)
|
||||
#define MPCORE_PPI_GLOBAL_TIMER (27)
|
||||
#define MPCORE_PPI_LEGACY_IRQ (31)
|
||||
#define MPCORE_PPI_LEGACY_FIQ (28)
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// GIC
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// Typical calls to enable interrupt ID X:
|
||||
// disableIntID(X) <-- Enable that ID
|
||||
// setIntPriority(X, 0) <-- Set the priority of X to 0 (the max priority)
|
||||
// setPriorityMask(0x1F) <-- Set Core's priority mask to 0x1F (the lowest priority)
|
||||
// enableGIC() <-- Enable the GIC (global)
|
||||
// enableGICProcessorInterface() <-- Enable the CPU interface (local to the core)
|
||||
//
|
||||
|
||||
|
||||
// Global enable of the Interrupt Distributor
|
||||
void enableGIC(void);
|
||||
|
||||
// Global disable of the Interrupt Distributor
|
||||
void disableGIC(void);
|
||||
|
||||
// Enables the interrupt source number ID
|
||||
void enableIntID(unsigned int ID);
|
||||
|
||||
// Disables the interrupt source number ID
|
||||
void disableIntID(unsigned int ID);
|
||||
|
||||
// Enables the processor interface
|
||||
// Must be done on each core separately
|
||||
void enableGICProcessorInterface(void);
|
||||
|
||||
// Disables the processor interface
|
||||
// Must be done on each core separately
|
||||
void disableGICProcessorInterface(void);
|
||||
|
||||
// Sets the Priority mask register for the core run on
|
||||
// The reset value masks ALL interrupts!
|
||||
//
|
||||
// NOTE: Bits 2:0 of this register are SBZ, the function does perform any shifting!
|
||||
void setPriorityMask(unsigned int priority);
|
||||
|
||||
// Sets the Binary Point Register for the core run on
|
||||
void setBinaryPoint(unsigned int priority);
|
||||
|
||||
// Sets the priority of the specifed ID
|
||||
void setIntPriority(unsigned int ID, unsigned int priority);
|
||||
|
||||
// Sets the priority of the specifed ID
|
||||
void getIntPriority(unsigned int ID, unsigned int priority);
|
||||
|
||||
#define MPCORE_IC_TARGET_NONE (0x0)
|
||||
#define MPCORE_IC_TARGET_CPU0 (0x1)
|
||||
#define MPCORE_IC_TARGET_CPU1 (0x2)
|
||||
#define MPCORE_IC_TARGET_CPU2 (0x4)
|
||||
#define MPCORE_IC_TARGET_CPU3 (0x8)
|
||||
|
||||
// Sets the target CPUs of the specified ID
|
||||
// For 'target' use one of the above defines
|
||||
unsigned int setIntTarget(unsigned int ID, unsigned int target);
|
||||
|
||||
//Returns the target CPUs of the specified ID
|
||||
unsigned int getIntTarget(unsigned int ID);
|
||||
|
||||
// Returns the value of the Interrupt Acknowledge Register
|
||||
unsigned int readIntAck(void);
|
||||
|
||||
// Writes ID to the End Of Interrupt register
|
||||
void writeEOI(unsigned int ID);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// SGI
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// Send a software generate interrupt
|
||||
void sendSGI(unsigned int ID, unsigned int core_list, unsigned int filter_list);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// TrustZone
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// Enables the sending of secure interrupts as FIQs
|
||||
void enableSecureFIQs(void);
|
||||
|
||||
// Disables the sending of secure interrupts as FIQs
|
||||
void disableSecureFIQs(void);
|
||||
|
||||
// Sets the specifed ID as secure
|
||||
void makeIntSecure(unsigned int ID);
|
||||
|
||||
// Set the specified ID as non-secure
|
||||
void makeIntNonSecure(unsigned int ID);
|
||||
|
||||
// Returns the security of the specifed ID
|
||||
void getIntSecurity(unsigned int ID);
|
||||
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// End of MP_GIC.h
|
||||
// ------------------------------------------------------------
|
||||
138
ports_smp/cortex_a7_smp/gnu/example_build/MP_Mutexes.S
Normal file
138
ports_smp/cortex_a7_smp/gnu/example_build/MP_Mutexes.S
Normal file
@@ -0,0 +1,138 @@
|
||||
@; ------------------------------------------------------------
|
||||
@; Cortex-A MPCore - Mutex Code
|
||||
@;
|
||||
@; Copyright (c) 2011-2012 ARM Ltd. All rights reserved.
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ PRESERVE8
|
||||
@
|
||||
@ AREA MP_Mutexes, CODE, READONLY
|
||||
@
|
||||
@ ;NOTES
|
||||
@ ; struct mutex_t defined in MP_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 = 0xFF
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT initMutex
|
||||
@ ; void initMutex(mutex_t* pMutex)
|
||||
@ ; Places mutex into a known state
|
||||
@ ; r0 = address of mutex_t
|
||||
.text
|
||||
.align 2
|
||||
.global $initMutex
|
||||
.type $initMutex,function
|
||||
initMutex:
|
||||
|
||||
MOV r1, #UNLOCKED @ Mark as unlocked
|
||||
STR r1, [r0]
|
||||
|
||||
BX lr
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT lockMutex
|
||||
@ ; void lockMutex(mutex_t* pMutex)
|
||||
@ ; Blocking call, returns once successfully locked a mutex
|
||||
@ ; r0 = address of mutex_t
|
||||
.text
|
||||
.align 2
|
||||
.global $lockMutex
|
||||
.type $lockMutex,function
|
||||
lockMutex:
|
||||
|
||||
@ Is mutex locked?
|
||||
@ -----------------
|
||||
LDREX r1, [r0] @ Read lock field
|
||||
CMP r1, #UNLOCKED @ Compare with "unlocked"
|
||||
|
||||
WFENE @ If mutex is locked, go into standby
|
||||
BNE lockMutex @ 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 whether store completed successfully (0=succeeded)
|
||||
BNE lockMutex @ If store failed, go back to beginning and try again
|
||||
|
||||
DMB
|
||||
|
||||
BX lr @ Return as mutex is now locked by this cpu
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT unlockMutex
|
||||
@ ; unsigned int unlockMutex(mutex_t* pMutex)
|
||||
@ ; Releases mutex, returns 0x0 for success and 0x1 for failure
|
||||
@ ; r0 = address of mutex_t
|
||||
.text
|
||||
.align 2
|
||||
.global $unlockMutex
|
||||
.type $unlockMutex,function
|
||||
unlockMutex:
|
||||
|
||||
@ 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]
|
||||
|
||||
DSB @ Ensure that no instructions following the barrier execute until
|
||||
@ all memory accesses prior to the barrier have completed.
|
||||
|
||||
SEV @ Send event to other CPUs, wakes anyone waiting on a mutex (using WFE)
|
||||
|
||||
MOV r0, #0x0 @ Return "success"
|
||||
BX lr
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT isMutexLocked
|
||||
@ ; void isMutexLocked(mutex_t* pMutex)
|
||||
@ ; Returns 0x0 if mutex unlocked, 0x1 is locked
|
||||
@ ; r0 = address of mutex_t
|
||||
.text
|
||||
.align 2
|
||||
.global $isMutexLocked
|
||||
.type $isMutexLocked,function
|
||||
isMutexLocked:
|
||||
LDR r0, [r0]
|
||||
CMP r0, #UNLOCKED
|
||||
MOVEQ r0, #0x0
|
||||
MOVNE r0, #0x1
|
||||
BX lr
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@; End of code
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ END
|
||||
@
|
||||
@; ------------------------------------------------------------
|
||||
@; End of MP_Mutexes.s
|
||||
@; ------------------------------------------------------------
|
||||
42
ports_smp/cortex_a7_smp/gnu/example_build/MP_Mutexes.h
Normal file
42
ports_smp/cortex_a7_smp/gnu/example_build/MP_Mutexes.h
Normal file
@@ -0,0 +1,42 @@
|
||||
// ------------------------------------------------------------
|
||||
// Cortex-A MPCore - Mutex
|
||||
// Header File
|
||||
//
|
||||
// Copyright (c) 2011 ARM Ltd. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#ifndef _CORTEXA_MUTEX_H
|
||||
#define _CORTEXA_MUTEX_H
|
||||
|
||||
// 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 initMutex(mutex_t* pMutex);
|
||||
|
||||
// Blocking call, returns once successfully locked a mutex
|
||||
// r0 = address of mutex_t
|
||||
void lockMutex(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 unlockMutex(mutex_t* pMutex);
|
||||
|
||||
// Returns 0x0 if mutex unlocked, 0x1 is locked
|
||||
// r0 = address of mutex_t
|
||||
void isMutexLocked(mutex_t* pMutex);
|
||||
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// End of MP_Mutexes.h
|
||||
// ------------------------------------------------------------
|
||||
257
ports_smp/cortex_a7_smp/gnu/example_build/build_threadx.bat
Normal file
257
ports_smp/cortex_a7_smp/gnu/example_build/build_threadx.bat
Normal file
@@ -0,0 +1,257 @@
|
||||
del tx.a
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 tx_initialize_low_level.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_stack_build.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_schedule.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_system_return.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_context_save.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_context_restore.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_interrupt_control.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_timer_interrupt.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_interrupt_disable.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_interrupt_restore.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_irq_nesting_end.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_irq_nesting_start.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_vectored_context_save.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_smp_core_get.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_smp_core_preempt.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_smp_current_state_get.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_smp_current_thread_get.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_smp_initialize_wait.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_smp_low_level_initialize.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_smp_protect.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_smp_time_get.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 ../src/tx_thread_smp_unprotect.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_block_allocate.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_block_pool_cleanup.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_block_pool_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_block_pool_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_block_pool_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_block_pool_initialize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_block_pool_performance_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_block_pool_performance_system_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_block_pool_prioritize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_block_release.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_byte_allocate.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_byte_pool_cleanup.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_byte_pool_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_byte_pool_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_byte_pool_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_byte_pool_initialize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_byte_pool_performance_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_byte_pool_performance_system_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_byte_pool_prioritize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_byte_pool_search.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_byte_release.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_event_flags_cleanup.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_event_flags_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_event_flags_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_event_flags_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_event_flags_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_event_flags_initialize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_event_flags_performance_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_event_flags_performance_system_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_event_flags_set.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_event_flags_set_notify.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_initialize_high_level.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_initialize_kernel_enter.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_initialize_kernel_setup.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_mutex_cleanup.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_mutex_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_mutex_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_mutex_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_mutex_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_mutex_initialize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_mutex_performance_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_mutex_performance_system_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_mutex_prioritize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_mutex_priority_change.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_mutex_put.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_queue_cleanup.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_queue_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_queue_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_queue_flush.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_queue_front_send.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_queue_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_queue_initialize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_queue_performance_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_queue_performance_system_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_queue_prioritize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_queue_receive.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_queue_send.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_queue_send_notify.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_semaphore_ceiling_put.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_semaphore_cleanup.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_semaphore_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_semaphore_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_semaphore_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_semaphore_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_semaphore_initialize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_semaphore_performance_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_semaphore_performance_system_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_semaphore_prioritize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_semaphore_put.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_semaphore_put_notify.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_entry_exit_notify.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_identify.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_initialize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_performance_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_performance_system_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_preemption_change.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_priority_change.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_relinquish.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_reset.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_resume.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_shell_entry.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_sleep.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_stack_analyze.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_stack_error_handler.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_stack_error_notify.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_suspend.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_system_preempt_check.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_system_resume.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_system_suspend.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_terminate.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_time_slice.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_time_slice_change.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_timeout.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_wait_abort.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_time_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_time_set.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_activate.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_change.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_deactivate.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_expiration_process.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_initialize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_performance_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_performance_system_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_system_activate.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_system_deactivate.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_thread_entry.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_trace_enable.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_trace_disable.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_trace_initialize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_trace_interrupt_control.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_trace_isr_enter_insert.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_trace_isr_exit_insert.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_trace_object_register.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_trace_object_unregister.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_trace_user_event_insert.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_trace_buffer_full_notify.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_trace_event_filter.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_trace_event_unfilter.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_block_allocate.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_block_pool_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_block_pool_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_block_pool_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_block_pool_prioritize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_block_release.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_byte_allocate.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_byte_pool_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_byte_pool_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_byte_pool_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_byte_pool_prioritize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_byte_release.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_event_flags_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_event_flags_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_event_flags_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_event_flags_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_event_flags_set.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_event_flags_set_notify.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_mutex_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_mutex_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_mutex_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_mutex_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_mutex_prioritize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_mutex_put.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_queue_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_queue_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_queue_flush.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_queue_front_send.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_queue_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_queue_prioritize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_queue_receive.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_queue_send.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_queue_send_notify.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_semaphore_ceiling_put.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_semaphore_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_semaphore_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_semaphore_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_semaphore_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_semaphore_prioritize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_semaphore_put.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_semaphore_put_notify.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_thread_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_thread_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_thread_entry_exit_notify.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_thread_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_thread_preemption_change.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_thread_priority_change.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_thread_relinquish.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_thread_reset.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_thread_resume.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_thread_suspend.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_thread_terminate.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_thread_time_slice_change.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_thread_wait_abort.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_timer_activate.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_timer_change.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_timer_create.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_timer_deactivate.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_timer_delete.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/txe_timer_info_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_smp_current_state_set.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_smp_debug_entry_insert.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_smp_high_level_initialize.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_smp_rebalance_execute_list.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_smp_core_exclude.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_smp_core_exclude_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_smp_core_exclude.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_timer_smp_core_exclude_get.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common_smp/inc -I../inc ../../../../common_smp/src/tx_thread_smp_utilities.c
|
||||
arm-none-eabi-ar -r tx.a tx_thread_stack_build.o tx_thread_schedule.o tx_thread_system_return.o tx_thread_context_save.o tx_thread_context_restore.o tx_timer_interrupt.o tx_thread_interrupt_control.o
|
||||
arm-none-eabi-ar -r tx.a tx_initialize_low_level.o tx_thread_interrupt_disable.o
|
||||
arm-none-eabi-ar -r tx.a tx_thread_interrupt_restore.o tx_thread_irq_nesting_end.o tx_thread_irq_nesting_start.o
|
||||
arm-none-eabi-ar -r tx.a tx_block_allocate.o tx_block_pool_cleanup.o tx_block_pool_create.o tx_block_pool_delete.o tx_block_pool_info_get.o
|
||||
arm-none-eabi-ar -r tx.a tx_block_pool_initialize.o tx_block_pool_performance_info_get.o tx_block_pool_performance_system_info_get.o tx_block_pool_prioritize.o
|
||||
arm-none-eabi-ar -r tx.a tx_block_release.o tx_byte_allocate.o tx_byte_pool_cleanup.o tx_byte_pool_create.o tx_byte_pool_delete.o tx_byte_pool_info_get.o
|
||||
arm-none-eabi-ar -r tx.a tx_byte_pool_initialize.o tx_byte_pool_performance_info_get.o tx_byte_pool_performance_system_info_get.o tx_byte_pool_prioritize.o
|
||||
arm-none-eabi-ar -r tx.a tx_byte_pool_search.o tx_byte_release.o tx_event_flags_cleanup.o tx_event_flags_create.o tx_event_flags_delete.o tx_event_flags_get.o
|
||||
arm-none-eabi-ar -r tx.a tx_event_flags_info_get.o tx_event_flags_initialize.o tx_event_flags_performance_info_get.o tx_event_flags_performance_system_info_get.o
|
||||
arm-none-eabi-ar -r tx.a tx_event_flags_set.o tx_event_flags_set_notify.o tx_initialize_high_level.o tx_initialize_kernel_enter.o tx_initialize_kernel_setup.o
|
||||
arm-none-eabi-ar -r tx.a tx_mutex_cleanup.o tx_mutex_create.o tx_mutex_delete.o tx_mutex_get.o tx_mutex_info_get.o tx_mutex_initialize.o tx_mutex_performance_info_get.o
|
||||
arm-none-eabi-ar -r tx.a tx_mutex_performance_system_info_get.o tx_mutex_prioritize.o tx_mutex_priority_change.o tx_mutex_put.o tx_queue_cleanup.o tx_queue_create.o
|
||||
arm-none-eabi-ar -r tx.a tx_queue_delete.o tx_queue_flush.o tx_queue_front_send.o tx_queue_info_get.o tx_queue_initialize.o tx_queue_performance_info_get.o
|
||||
arm-none-eabi-ar -r tx.a tx_queue_performance_system_info_get.o tx_queue_prioritize.o tx_queue_receive.o tx_queue_send.o tx_queue_send_notify.o tx_semaphore_ceiling_put.o
|
||||
arm-none-eabi-ar -r tx.a tx_semaphore_cleanup.o tx_semaphore_create.o tx_semaphore_delete.o tx_semaphore_get.o tx_semaphore_info_get.o tx_semaphore_initialize.o
|
||||
arm-none-eabi-ar -r tx.a tx_semaphore_performance_info_get.o tx_semaphore_performance_system_info_get.o tx_semaphore_prioritize.o tx_semaphore_put.o tx_semaphore_put_notify.o
|
||||
arm-none-eabi-ar -r tx.a tx_thread_create.o tx_thread_delete.o tx_thread_entry_exit_notify.o tx_thread_identify.o tx_thread_info_get.o tx_thread_initialize.o
|
||||
arm-none-eabi-ar -r tx.a tx_thread_performance_info_get.o tx_thread_performance_system_info_get.o tx_thread_preemption_change.o tx_thread_priority_change.o tx_thread_relinquish.o
|
||||
arm-none-eabi-ar -r tx.a tx_thread_reset.o tx_thread_resume.o tx_thread_shell_entry.o tx_thread_sleep.o tx_thread_stack_analyze.o tx_thread_stack_error_handler.o
|
||||
arm-none-eabi-ar -r tx.a tx_thread_stack_error_notify.o tx_thread_suspend.o tx_thread_system_preempt_check.o tx_thread_system_resume.o tx_thread_system_suspend.o
|
||||
arm-none-eabi-ar -r tx.a tx_thread_terminate.o tx_thread_time_slice.o tx_thread_time_slice_change.o tx_thread_timeout.o tx_thread_wait_abort.o tx_time_get.o
|
||||
arm-none-eabi-ar -r tx.a tx_time_set.o tx_timer_activate.o tx_timer_change.o tx_timer_create.o tx_timer_deactivate.o tx_timer_delete.o tx_timer_expiration_process.o
|
||||
arm-none-eabi-ar -r tx.a tx_timer_info_get.o tx_timer_initialize.o tx_timer_performance_info_get.o tx_timer_performance_system_info_get.o tx_timer_system_activate.o
|
||||
arm-none-eabi-ar -r tx.a tx_timer_system_deactivate.o tx_timer_thread_entry.o tx_trace_enable.o tx_trace_disable.o tx_trace_initialize.o tx_trace_interrupt_control.o
|
||||
arm-none-eabi-ar -r tx.a tx_trace_isr_enter_insert.o tx_trace_isr_exit_insert.o tx_trace_object_register.o tx_trace_object_unregister.o tx_trace_user_event_insert.o
|
||||
arm-none-eabi-ar -r tx.a tx_trace_buffer_full_notify.o tx_trace_event_filter.o tx_trace_event_unfilter.o
|
||||
arm-none-eabi-ar -r tx.a txe_block_allocate.o txe_block_pool_create.o txe_block_pool_delete.o txe_block_pool_info_get.o txe_block_pool_prioritize.o txe_block_release.o
|
||||
arm-none-eabi-ar -r tx.a txe_byte_allocate.o txe_byte_pool_create.o txe_byte_pool_delete.o txe_byte_pool_info_get.o txe_byte_pool_prioritize.o txe_byte_release.o
|
||||
arm-none-eabi-ar -r tx.a txe_event_flags_create.o txe_event_flags_delete.o txe_event_flags_get.o txe_event_flags_info_get.o txe_event_flags_set.o
|
||||
arm-none-eabi-ar -r tx.a txe_event_flags_set_notify.o txe_mutex_create.o txe_mutex_delete.o txe_mutex_get.o txe_mutex_info_get.o txe_mutex_prioritize.o
|
||||
arm-none-eabi-ar -r tx.a txe_mutex_put.o txe_queue_create.o txe_queue_delete.o txe_queue_flush.o txe_queue_front_send.o txe_queue_info_get.o txe_queue_prioritize.o
|
||||
arm-none-eabi-ar -r tx.a txe_queue_receive.o txe_queue_send.o txe_queue_send_notify.o txe_semaphore_ceiling_put.o txe_semaphore_create.o txe_semaphore_delete.o
|
||||
arm-none-eabi-ar -r tx.a txe_semaphore_get.o txe_semaphore_info_get.o txe_semaphore_prioritize.o txe_semaphore_put.o txe_semaphore_put_notify.o txe_thread_create.o
|
||||
arm-none-eabi-ar -r tx.a txe_thread_delete.o txe_thread_entry_exit_notify.o txe_thread_info_get.o txe_thread_preemption_change.o txe_thread_priority_change.o
|
||||
arm-none-eabi-ar -r tx.a txe_thread_relinquish.o txe_thread_reset.o txe_thread_resume.o txe_thread_suspend.o txe_thread_terminate.o txe_thread_time_slice_change.o
|
||||
arm-none-eabi-ar -r tx.a txe_thread_wait_abort.o txe_timer_activate.o txe_timer_change.o txe_timer_create.o txe_timer_deactivate.o txe_timer_delete.o txe_timer_info_get.o
|
||||
arm-none-eabi-ar -r tx.a tx_thread_smp_current_state_set.o tx_thread_smp_debug_entry_insert.o tx_thread_smp_high_level_initialize.o
|
||||
arm-none-eabi-ar -r tx.a tx_thread_smp_rebalance_execute_list.o tx_thread_smp_core_exclude.o tx_thread_smp_core_exclude_get.o
|
||||
arm-none-eabi-ar -r tx.a tx_timer_smp_core_exclude.o tx_timer_smp_core_exclude_get.o tx_thread_smp_utilities.o
|
||||
arm-none-eabi-ar -r tx.a tx_thread_smp_core_get.o tx_thread_smp_core_preempt.o tx_thread_smp_current_state_get.o tx_thread_smp_current_thread_get.o tx_thread_smp_initialize_wait.o
|
||||
arm-none-eabi-ar -r tx.a tx_thread_smp_low_level_initialize.o tx_thread_smp_protect.o tx_thread_smp_time_get.o tx_thread_smp_unprotect.o
|
||||
@@ -0,0 +1,7 @@
|
||||
arm-none-eabi-gcc -c -g -I../../../../common_smp/inc -I../inc -mcpu=cortex-a7 sample_threadx.c
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 startup.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 MP_GIC.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 MP_Mutexes.S
|
||||
arm-none-eabi-gcc -c -g -mcpu=cortex-a7 v7.S
|
||||
REM arm-none-eabi-ld -A cortex-a5 -T sample_threadx.ld reset.o crt0.o tx_initialize_low_level.o sample_threadx.o tx.a libc.a libgcc.a -o sample_threadx.out -M > sample_threadx.map
|
||||
arm-none-eabi-gcc -T sample_threadx.ld -e Vectors -o sample_threadx.axf MP_GIC.o MP_Mutexes.o sample_threadx.o startup.o v7.o tx.a -Wl,-M > sample_threadx.map
|
||||
381
ports_smp/cortex_a7_smp/gnu/example_build/sample_threadx.c
Normal file
381
ports_smp/cortex_a7_smp/gnu/example_build/sample_threadx.c
Normal file
@@ -0,0 +1,381 @@
|
||||
/* 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 = TX_NULL;
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
182
ports_smp/cortex_a7_smp/gnu/example_build/sample_threadx.ld
Normal file
182
ports_smp/cortex_a7_smp/gnu/example_build/sample_threadx.ld
Normal file
@@ -0,0 +1,182 @@
|
||||
/* Linker script to place sections and symbol values.
|
||||
* It references following symbols, which must be defined in code:
|
||||
* Vectors : Entry point
|
||||
*
|
||||
* It defines following symbols, which code can use without definition:
|
||||
* __code_start
|
||||
* __exidx_start
|
||||
* __exidx_end
|
||||
* __data_start
|
||||
* __preinit_array_start
|
||||
* __preinit_array_end
|
||||
* __init_array_start
|
||||
* __init_array_end
|
||||
* __fini_array_start
|
||||
* __fini_array_end
|
||||
* __bss_start__
|
||||
* __bss_end__
|
||||
* __end__
|
||||
* __stack
|
||||
* __irq_stack
|
||||
* __stack
|
||||
* __pagetable_start
|
||||
*/
|
||||
ENTRY(Vectors)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
.vectors 0x80008000:
|
||||
{
|
||||
_exec = .;
|
||||
__code_start = .;
|
||||
KEEP(*(VECTORS))
|
||||
}
|
||||
|
||||
.init :
|
||||
{
|
||||
KEEP (*(SORT_NONE(.init)))
|
||||
}
|
||||
|
||||
.text :
|
||||
{
|
||||
KEEP(*(ENABLE_CACHES))
|
||||
*(.text*)
|
||||
}
|
||||
|
||||
.fini :
|
||||
{
|
||||
KEEP (*(SORT_NONE(.fini)))
|
||||
}
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
}
|
||||
|
||||
.eh_frame :
|
||||
{
|
||||
KEEP (*(.eh_frame))
|
||||
}
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
}
|
||||
|
||||
.ARM.exidx :
|
||||
{
|
||||
__exidx_start = .;
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
__exidx_end = .;
|
||||
}
|
||||
|
||||
.preinit_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
}
|
||||
|
||||
.init_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array ))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
}
|
||||
|
||||
.fini_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
KEEP (*(.fini_array ))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
}
|
||||
|
||||
.ctors :
|
||||
{
|
||||
/* gcc uses crtbegin.o to find the start of
|
||||
the constructors, so we make sure it is
|
||||
first. Because this is a wildcard, it
|
||||
doesn't matter if the user does not
|
||||
actually link against crtbegin.o; the
|
||||
linker won't look for a file to match a
|
||||
wildcard. The wildcard also means that it
|
||||
doesn't matter which directory crtbegin.o
|
||||
is in. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*crtbegin?.o(.ctors))
|
||||
/* We don't want to include the .ctor section from
|
||||
the crtend.o file until after the sorted ctors.
|
||||
The .ctor section from the crtend file contains the
|
||||
end of ctors marker and it must be last */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
}
|
||||
|
||||
.dtors :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*crtbegin?.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
}
|
||||
|
||||
.jcr :
|
||||
{
|
||||
KEEP (*(.jcr))
|
||||
}
|
||||
|
||||
.data :
|
||||
{
|
||||
__data_start = . ;
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__bss_start__ = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
__bss_end__ = .;
|
||||
}
|
||||
|
||||
.heap (NOLOAD):
|
||||
{
|
||||
. = ALIGN(64);
|
||||
__end__ = .;
|
||||
PROVIDE(end = .);
|
||||
. = . + 0xA0000;
|
||||
}
|
||||
|
||||
.stack (NOLOAD):
|
||||
{
|
||||
. = ALIGN(64);
|
||||
. = . + 4 * 0x4000;
|
||||
__stack = .;
|
||||
_stack_init_usr = .;
|
||||
}
|
||||
|
||||
.irq_stacks (NOLOAD):
|
||||
{
|
||||
. = ALIGN(64);
|
||||
. = . + 4 * 1024;
|
||||
__irq_stack = .;
|
||||
_stack_init_irq = .;
|
||||
}
|
||||
|
||||
_end = .;
|
||||
|
||||
.pagetable 0x80100000 (NOLOAD):
|
||||
{
|
||||
_page_table_top = .;
|
||||
__pagetable_start = .;
|
||||
. = . + 0x4000;
|
||||
}
|
||||
}
|
||||
693
ports_smp/cortex_a7_smp/gnu/example_build/startup.S
Normal file
693
ports_smp/cortex_a7_smp/gnu/example_build/startup.S
Normal file
@@ -0,0 +1,693 @@
|
||||
@; ------------------------------------------------------------
|
||||
@; Cortex-A15 MPCore SMP Prime Number Generator Example
|
||||
@;
|
||||
@; Copyright (c) 2011-2012 ARM Ltd. All rights reserved.
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ PRESERVE8
|
||||
@
|
||||
@ AREA StartUp,CODE,READONLY
|
||||
@
|
||||
@; Standard definitions of mode bits and interrupt (I&F) flags in PSRs
|
||||
@
|
||||
Mode_USR = 0x10
|
||||
Mode_FIQ = 0x11
|
||||
Mode_IRQ = 0x12
|
||||
Mode_SVC = 0x13
|
||||
Mode_ABT = 0x17
|
||||
Mode_UNDEF = 0x1B
|
||||
Mode_SYS = 0x1F
|
||||
|
||||
I_Bit = 0x80 @ when I bit is set, IRQ is disabled
|
||||
F_Bit = 0x40 @ when F bit is set, FIQ is disabled
|
||||
|
||||
SYS_MODE = 0xDF
|
||||
SVC_MODE = 0xD3
|
||||
IRQ_MODE = 0xD2
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@; Porting defines
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
L1_COHERENT = 0x00014c06 @ Template descriptor for coherent memory
|
||||
L1_NONCOHERENT = 0x00000c1e @ Template descriptor for non-coherent memory
|
||||
L1_DEVICE = 0x00000c06 @ Template descriptor for device memory
|
||||
|
||||
.section VECTORS, "ax"
|
||||
.align 3
|
||||
.cfi_sections .debug_frame // put stack frame info into .debug_frame instead of .eh_frame
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ ENTRY
|
||||
@
|
||||
.global Vectors
|
||||
Vectors:
|
||||
B Reset_Handler
|
||||
B Undefined_Handler
|
||||
B SVC_Handler
|
||||
B Prefetch_Handler
|
||||
B Abort_Handler
|
||||
B Hypervisor_Handler
|
||||
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
|
||||
Hypervisor_Handler:
|
||||
B Hypervisor_Handler
|
||||
FIQ_Handler:
|
||||
B FIQ_Handler
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@; Imports
|
||||
@; ------------------------------------------------------------
|
||||
.global readIntAck
|
||||
.global writeEOI
|
||||
.global enableGIC
|
||||
.global enableGICProcessorInterface
|
||||
.global setPriorityMask
|
||||
.global enableIntID
|
||||
.global setIntPriority
|
||||
.global joinSMP
|
||||
|
||||
.global invalidateCaches
|
||||
.global disableHighVecs
|
||||
.global _start
|
||||
@; [Grape Change Start]
|
||||
@; IMPORT main_app
|
||||
|
||||
.global _tx_thread_smp_initialize_wait
|
||||
.global _tx_thread_smp_release_cores_flag
|
||||
.global _tx_thread_context_save
|
||||
.global _tx_thread_context_restore
|
||||
.global _tx_timer_interrupt
|
||||
.global _tx_thread_smp_inter_core_interrupts
|
||||
|
||||
.global enableBranchPrediction
|
||||
.global enableCaches
|
||||
|
||||
VFPEnable = 0x40000000 @ VFP enable value
|
||||
|
||||
@;/*------------------------------------------------------------------------*/
|
||||
@;/*--- Versatile Express(Timer0) ---*/
|
||||
GIC_DIST_CPUTARGET = 0x2C001820
|
||||
GIC_DIST_CPUTARGET_VALUE = 0x000f0000
|
||||
|
||||
GIC_DIST_CONFIG = 0x2C001C08
|
||||
GIC_DIST_CONFIG_VALUE = 0x00000000
|
||||
|
||||
GIC_DIST_PRIO = 0x2C001420
|
||||
GIC_DIST_PRIO_VALUE = 0x00a00000
|
||||
|
||||
GIC_DIST_CONTROL = 0x2C001000
|
||||
GIC_DIST_CONTROL_VALUE = 0x00000001
|
||||
|
||||
GIC_CPU_CONTROL = 0x2C002000
|
||||
GIC_CPU_CONTROL_VALUE = 0x00000001
|
||||
|
||||
GIC_CPU_PRIO_MASK = 0x2C002004
|
||||
GIC_CPU_PRIO_MASK_VALUE = 0x000000ff
|
||||
|
||||
GIC_DIST_ENABLE_SET = 0x2C001104
|
||||
GIC_DIST_ENABLE_SET_VALUE = 0x00000004
|
||||
|
||||
GIC_CPU_INTACK = 0x2C00200C
|
||||
GIC_CPU_EOI = 0x2C002010
|
||||
;
|
||||
;
|
||||
;
|
||||
TIMCLK_CTRL = 0x1C020000
|
||||
TIMCLK_CTRL_VALUE = 0x00028000 @ Use EXTCLK (1MHz) for TIMCLK not REFCLK32KHZ
|
||||
|
||||
TIMER_LOAD = 0x1C110000
|
||||
TIMER_LOAD_VALUE = 0x00000140 @ 10ms
|
||||
|
||||
TIMER_CTRL = 0x1C110008
|
||||
TIMER_CTRL_STOP = 0x00000020
|
||||
TIMER_CTRL_VALUE = 0x000000E0
|
||||
TIMER_ACK = 34 @ Timer0
|
||||
TIMER_INT_CLR = 0x1C11000C
|
||||
;
|
||||
HANDLER_SET = 0x80000018
|
||||
HANDLER_SET_VALUE = 0xE59FF018
|
||||
HANDLER_ADDRESS = 0x80000038 @ irq
|
||||
|
||||
@;/*--- Versatile Express(Timer0) ---*/
|
||||
@;/*------------------------------------------------------------------------*/
|
||||
@; [Grape Change End]
|
||||
|
||||
.global _page_table_top
|
||||
.global _exec
|
||||
.global _stack_init_irq
|
||||
.global _stack_init_usr
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@; Interrupt Handler
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT IRQ_Handler
|
||||
.align 2
|
||||
.global IRQ_Handler
|
||||
.type IRQ_Handler,function
|
||||
IRQ_Handler:
|
||||
@; [Grape Change Start]
|
||||
.global __tx_irq_processing_return
|
||||
@; SUB lr, lr, #4 ; Pre-adjust lr
|
||||
@; SRSFD sp!, #Mode_IRQ ; Save lr and SPRS to IRQ mode stack
|
||||
@; PUSH {r0-r4, r12} ; Save APCS corruptible 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)
|
||||
@; [Grape Change End]
|
||||
|
||||
@ Acknowledge the interrupt
|
||||
BL readIntAck
|
||||
MOV r4, r0
|
||||
|
||||
@ ;
|
||||
@ ; This example only uses (and enables) one. At this point
|
||||
@ ; you would normally check the ID, and clear the source.
|
||||
@ ;
|
||||
|
||||
@; [Grape Change Start]
|
||||
@;/*------------------------------------------------------------------------*/
|
||||
@;/*--- Versatile Express(Timer0) ---*/
|
||||
LDR r0, =TIMER_ACK @ Setup timer acknowledge number
|
||||
CMP r4, r0
|
||||
BNE by_pass
|
||||
|
||||
LDR r0, =TIMER_INT_CLR @ Setup Timer interrupt clear register address
|
||||
LDR r1, =1
|
||||
STR r1, [r0, #0] @ Clear timer interrupt
|
||||
|
||||
BL _tx_timer_interrupt @ Timer interrupt handler
|
||||
B by_pass2
|
||||
@;/*--- Versatile Express(Timer0) ---*/
|
||||
@;/*------------------------------------------------------------------------*/
|
||||
|
||||
by_pass:
|
||||
@; /* 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
|
||||
|
||||
@;/* user handler */
|
||||
|
||||
|
||||
@;/*------------------------------------------------------------------------*/
|
||||
@; [Grape Change End]
|
||||
@
|
||||
@
|
||||
@; [Grape Change Start]
|
||||
by_pass2:
|
||||
@ Write end of interrupt reg
|
||||
MOV r0, r4
|
||||
BL writeEOI
|
||||
|
||||
@; POP {r0-r4, r12} ; Restore stacked APCS registers
|
||||
@; MOV r2, #0x01 ; Set r2 so CPU leaves holding pen
|
||||
@; RFEFD sp! ; Return from exception
|
||||
@;;;;;
|
||||
@; /* Jump to context restore to restore system context. */
|
||||
POP {r4, r5} @ Recover preserved registers
|
||||
B _tx_thread_context_restore
|
||||
@; [Grape Change End]
|
||||
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@; Reset Handler - Generic initialization, run by all CPUs
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT Reset_Handler
|
||||
.align 2
|
||||
.global $Reset_Handler
|
||||
.type $Reset_Handler,function
|
||||
Reset_Handler:
|
||||
|
||||
@ ;
|
||||
@ ; Set ACTLR.SMP bit
|
||||
@ ; ------------------
|
||||
BL joinSMP
|
||||
|
||||
@;
|
||||
@; Disable caches, MMU and branch prediction in case they were 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 CP15 System Control register
|
||||
BIC r0, r0, #(0x1 << 12) @ Clear I bit 12 to disable I Cache
|
||||
BIC r0, r0, #(0x1 << 2) @ Clear C bit 2 to disable D Cache
|
||||
BIC r0, r0, #0x1 @ Clear M bit 0 to disable MMU
|
||||
BIC r0, r0, #(0x1 << 11) @ Clear Z bit 11 to disable branch prediction
|
||||
MCR p15, 0, r0, c1, c0, 0 @ Write CP15 System Control register
|
||||
|
||||
@; The MMU is enabled later, before calling main(). Caches and branch prediction are enabled inside main(),
|
||||
@; after the MMU has been enabled and scatterloading has been performed.
|
||||
@
|
||||
@ ;
|
||||
@ ; Setup stacks
|
||||
@ ;---------------
|
||||
|
||||
MRC p15, 0, r0, c0, c0, 5 @ Read CPU ID register
|
||||
ANDS r0, r0, #0x03 @ Mask off, leaving the CPU ID field
|
||||
|
||||
@; [Grape Change Start]
|
||||
@; MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
|
||||
@; LDR r1, =_stack_init_irq ; IRQ stacks for CPU 0,1,2,3
|
||||
@; SUB r1, r1, r0, LSL #8 ; 256 bytes of IRQ stack per CPU (0,1,2,3) - see scatter.scat
|
||||
@; MOV sp, r1
|
||||
@;
|
||||
@; MSR CPSR_c, #Mode_SYS:OR:I_Bit:OR:F_Bit ; Interrupts initially disabled
|
||||
@; LDR r1, =_stack_init_usr ; App stacks for all CPUs
|
||||
@; SUB r1, r1, r0, LSL #12 ; 0x1000 bytes of App stack per CPU - see scatter.scat
|
||||
@; MOV sp, r1
|
||||
|
||||
|
||||
MOV r1, #IRQ_MODE @ Build IRQ mode CPSR
|
||||
MSR CPSR_c, r1 @ Enter IRQ mode
|
||||
@ MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
|
||||
LDR r1, =_stack_init_irq @ IRQ stacks for CPU 0,1,2,3
|
||||
SUB r1, r1, r0, LSL #10 @ 1024 bytes of IRQ stack per CPU (0,1,2,3) - see scatter.scat
|
||||
MOV sp, r1
|
||||
|
||||
MOV r1, #SYS_MODE @ Build SYS mode CPSR
|
||||
MSR CPSR_c, r1 @ Enter SYS mode
|
||||
@ MSR CPSR_c, #Mode_SYS:OR:I_Bit:OR:F_Bit @ Interrupts initially disabled
|
||||
LDR r1, =_stack_init_usr @ App stacks for all CPUs
|
||||
SUB r1, r1, r0, LSL #12 @ 0x1000 bytes of App stack per CPU - see scatter.scat
|
||||
MOV sp, r1
|
||||
|
||||
MOV r2, #SVC_MODE @ Build SVC mode CPSR
|
||||
MSR CPSR_c, r2 @ Enter SVC mode
|
||||
@ MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit @ Interrupts initially disabled
|
||||
MOV sp, r1
|
||||
@; [Grape Change End]
|
||||
@
|
||||
@ ;
|
||||
@ ; Set vector base address
|
||||
@ ; ------------------------
|
||||
LDR r0, =Vectors
|
||||
MCR p15, 0, r0, c12, c0, 0 @ Write Secure or Non-secure Vector Base Address
|
||||
BL disableHighVecs @ Ensure that V-bit is cleared
|
||||
|
||||
@ ;
|
||||
@ ; Invalidate caches
|
||||
@ ; ------------------
|
||||
BL invalidateCaches
|
||||
|
||||
@ ;
|
||||
@ ; Clear Branch Prediction Array
|
||||
@ ; ------------------------------
|
||||
MOV r0, #0x0
|
||||
MCR p15, 0, r0, c7, c5, 6 @ BPIALL - Invalidate entire branch predictor array
|
||||
|
||||
@; [Grape Change Start]
|
||||
@; ; Disable loop-buffer to fix errata on A15 r0p0
|
||||
@; MRC p15, 0, r0, c0, c0, 0 ; Read main ID register MIDR
|
||||
@; MOV r1, r0, lsr #4 ; Extract Primary Part Number
|
||||
@; LDR r2, =0xFFF
|
||||
@; AND r1, r1, r2
|
||||
@; LDR r2, =0xC0F
|
||||
@; CMP r1, r2 ; Is this an A15?
|
||||
@; BNE notA15r0p0 ; Jump if not A15
|
||||
@; AND r5, r0, #0x00f00000 ; Variant
|
||||
@; AND r6, r0, #0x0000000f ; Revision
|
||||
@; ORRS r6, r6, r5 ; Combine variant and revision
|
||||
@; BNE notA15r0p0 ; Jump if not r0p0
|
||||
@; MRC p15, 0, r0, c1, c0, 1 ; Read Aux Ctrl Reg
|
||||
@; ORR r0, r0, #(1 << 1) ; Set bit 1 to Disable Loop Buffer
|
||||
@; MCR p15, 0, r0, c1, c0, 1 ; Write Aux Ctrl Reg
|
||||
@; ISB
|
||||
@;notA15r0p0
|
||||
@; [Grape Change End]
|
||||
@
|
||||
@ ;
|
||||
@ ; Invalidate TLBs
|
||||
@ ;------------------
|
||||
MOV r0, #0x0
|
||||
MCR p15, 0, r0, c8, c7, 0 @ TLBIALL - Invalidate entire Unified TLB
|
||||
|
||||
@ ;
|
||||
@ ; Set up Domain Access Control Reg
|
||||
@ ; ----------------------------------
|
||||
@ ; b00 - No Access (abort)
|
||||
@ ; b01 - Client (respect table entry)
|
||||
@ ; b10 - RESERVED
|
||||
@ ; b11 - Manager (ignore access permissions)
|
||||
|
||||
MRC p15, 0, r0, c3, c0, 0 @ Read Domain Access Control Register
|
||||
LDR r0, =0x55555555 @ Initialize every domain entry to b01 (client)
|
||||
MCR p15, 0, r0, c3, c0, 0 @ Write Domain Access Control Register
|
||||
|
||||
@ ;;
|
||||
@ ;; Enable L1 Preloader - Auxiliary Control
|
||||
@ ;; -----------------------------------------
|
||||
@ ;; Seems to undef on panda?
|
||||
@ ;MRC p15, 0, r0, c1, c0, 1 ; Read ACTLR
|
||||
@ ;ORR r0, r0, #0x4
|
||||
@ ;MCR p15, 0, r0, c1, c0, 1 ; Write ACTLR
|
||||
@
|
||||
@ ; Page tables
|
||||
@ ; -------------------------
|
||||
@ ; Each CPU will have its own L1 page table. The
|
||||
@ ; code reads the base address from the scatter file
|
||||
@ ; the uses the CPUID to calculate an offset for each
|
||||
@ ; CPU.
|
||||
@ ;
|
||||
@ ; The page tables are generated at boot time. First
|
||||
@ ; the table is zeroed. Then the individual valid
|
||||
@ ; entries are written in
|
||||
@ ;
|
||||
@
|
||||
@ ; Calculate offset for this CPU
|
||||
LDR r0, =_page_table_top
|
||||
MRC p15, 0, r1, c0, c0, 5 @ Read Multiprocessor Affinity Register
|
||||
ANDS r1, r1, #0x03 @ Mask off, leaving the CPU ID field
|
||||
MOV r1, r1, LSL #14 @ Convert core ID into a 16K offset (this is the size of the table)
|
||||
ADD r0, r1, r0 @ Add offset to current table location to get dst
|
||||
|
||||
@ Fill table with zeros
|
||||
MOV r2, #1024 @ Set r3 to loop count (4 entries per iteration, 1024 iterations)
|
||||
MOV r1, r0 @ Make a copy of the base dst
|
||||
MOV r3, #0
|
||||
MOV r4, #0
|
||||
MOV r5, #0
|
||||
MOV r6, #0
|
||||
ttb_zero_loop:
|
||||
STMIA r1!, {r3-r6} @ Store out four entries
|
||||
SUBS r2, r2, #1 @ Decrement counter
|
||||
BNE ttb_zero_loop
|
||||
|
||||
@ ;
|
||||
@ ; STANDARD ENTRIES
|
||||
@ ;
|
||||
@
|
||||
@ ; Entry for VA 0x0
|
||||
@ ; This region must be coherent
|
||||
@ ;LDR r1, =PABASE_VA0 ; Physical address
|
||||
@ ;LDR r2, =L1_COHERENT ; Descriptor template
|
||||
@ ;ORR r1, r1, r2 ; Combine address and template
|
||||
@ ;STR r1, [r0]
|
||||
@
|
||||
@
|
||||
@ ; If not flat mapping, you need a page table entry covering
|
||||
@ ; the physical address of the boot code.
|
||||
@ ; This region must be coherent
|
||||
LDR r1,=_exec @ Base physical address of code segment
|
||||
LSR r1,#20 @ Shift right to align to 1MB boundaries
|
||||
LDR r3, =L1_COHERENT @ Descriptor template
|
||||
ORR r3, r1, LSL#20 @ Setup the initial level1 descriptor again
|
||||
STR r3, [r0, r1, LSL#2] @ str table entry
|
||||
|
||||
@; [Grape Change Start]
|
||||
@;/*------------------------------------------------------------------------*/
|
||||
@;/*--- Versatile Express(Timer0) ---*/
|
||||
LDR r1, =0x80000000 @ Physical address of HANDLER
|
||||
LSR r1, r1, #20 @ Clear bottom 20 bits, to find which 1MB block it is in
|
||||
LSL r2, r1, #2 @ Make a copy, and multiply by four. This gives offset into the page tables
|
||||
LSL r1, r1, #20 @ Put back in address format
|
||||
|
||||
LDR r3, =L1_COHERENT @ Descriptor template
|
||||
ORR r1, r1, r3 @ Combine address and template
|
||||
STR r1, [r0, r2]
|
||||
|
||||
LDR r1, =0x2C000000 @ Physical address of GIC_DIST
|
||||
LSR r1, r1, #20 @ Clear bottom 20 bits, to find which 1MB block it is in
|
||||
LSL r2, r1, #2 @ Make a copy, and multiply by four. This gives offset into the page tables
|
||||
LSL r1, r1, #20 @ Put back in address format
|
||||
|
||||
LDR r3, =L1_DEVICE @ Descriptor template
|
||||
ORR r1, r1, r3 @ Combine address and template
|
||||
STR r1, [r0, r2]
|
||||
|
||||
LDR r1, =0x1C000000 @ Physical address of TIMER
|
||||
LSR r1, r1, #20 @ Clear bottom 20 bits, to find which 1MB block it is in
|
||||
LSL r2, r1, #2 @ Make a copy, and multiply by four. This gives offset into the page tables
|
||||
LSL r1, r1, #20 @ Put back in address format
|
||||
|
||||
LDR r3, =L1_DEVICE @ Descriptor template
|
||||
ORR r1, r1, r3 @ Combine address and template
|
||||
STR r1, [r0, r2]
|
||||
|
||||
LDR r1, =0x1C100000 @ Physical address of TIMER
|
||||
LSR r1, r1, #20 @ Clear bottom 20 bits, to find which 1MB block it is in
|
||||
LSL r2, r1, #2 @ Make a copy, and multiply by four. This gives offset into the page tables
|
||||
LSL r1, r1, #20 @ Put back in address format
|
||||
|
||||
LDR r3, =L1_DEVICE @ Descriptor template
|
||||
ORR r1, r1, r3 @ Combine address and template
|
||||
STR r1, [r0, r2]
|
||||
@;/*--- Versatile Express(Timer0) ---*/
|
||||
@;/*------------------------------------------------------------------------*/
|
||||
@; [Grape Change End]
|
||||
@
|
||||
@ ; Entry for private address space
|
||||
@ ; Needs to be marked as Device memory
|
||||
MRC p15, 4, r1, c15, c0, 0 @ Get base address of private address space
|
||||
LSR r1, r1, #20 @ Clear bottom 20 bits, to find which 1MB block it is in
|
||||
LSL r2, r1, #2 @ Make a copy, and multiply by four. This gives offset into the page tables
|
||||
LSL r1, r1, #20 @ Put back in address format
|
||||
|
||||
LDR r3, =L1_DEVICE @ Descriptor template
|
||||
ORR r1, r1, r3 @ Combine address and template
|
||||
STR r1, [r0, r2]
|
||||
|
||||
@ ;
|
||||
@ ; OPTIONAL ENTRIES
|
||||
@ ; You will need additional translations if:
|
||||
@ ; - No RAM at zero, so cannot use flat mapping
|
||||
@ ; - You wish to retarget
|
||||
@ ;
|
||||
@ ; If you wish to output to stdio to a UART you will need
|
||||
@ ; an additional entry
|
||||
@ ;LDR r1, =PABASE_UART ; Physical address of UART
|
||||
@ ;LSR r1, r1, #20 ; Mask off bottom 20 bits to find which 1MB it is within
|
||||
@ ;LSL r2, r1, #2 ; Make a copy and multiply by 4 to get table offset
|
||||
@ ;LSL r1, r1, #20 ; Put back into address format
|
||||
@ ;LDR r3, =L1_DEVICE ; Descriptor template
|
||||
@ ;ORR r1, r1, r3 ; Combine address and template
|
||||
@ ;STR r1, [r0, r2]
|
||||
@
|
||||
@ ;
|
||||
@ ; Barrier
|
||||
@ ; --------
|
||||
DSB
|
||||
|
||||
@ ;
|
||||
@ ; Set location of level 1 page table
|
||||
@ ;------------------------------------
|
||||
@ ; 31:14 - Base addr: 0x8050,0000 (CPU0), 0x8050,4000 (CPU1)
|
||||
@ ; 13:5 - 0x0
|
||||
@ ; 4:3 - RGN 0x0 (Outer Noncachable)
|
||||
@ ; 2 - P 0x0
|
||||
@ ; 1 - S 0x0 (Non-shared)
|
||||
@ ; 0 - C 0x0 (Inner Noncachable)
|
||||
MCR p15, 0, r0, c2, c0 ,0
|
||||
|
||||
|
||||
@ ; Enable MMU
|
||||
@ ;-------------
|
||||
@ ; Leaving the caches disabled until after scatter loading.
|
||||
MRC p15, 0, r0, c1, c0, 0 @ Read CP15 System Control register
|
||||
BIC r0, r0, #(0x1 << 12) @ Clear I bit 12 to disable I Cache
|
||||
BIC r0, r0, #(0x1 << 2) @ Clear C bit 2 to disable D Cache
|
||||
BIC r0, r0, #0x2 @ Clear A bit 1 to disable strict alignment fault checking
|
||||
ORR r0, r0, #0x1 @ Set M bit 0 to enable MMU before scatter loading
|
||||
MCR p15, 0, r0, c1, c0, 0 @ Write CP15 System Control register
|
||||
|
||||
@ ;
|
||||
@ ; MMU now enabled - Virtual address system now active
|
||||
@ ;
|
||||
@; [Grape Change Start]
|
||||
#ifdef TARGET_FPU_VFP
|
||||
MRC p15, 0, r1, c1, c0, 2 @ r1 = Access Control Register
|
||||
ORR r1, r1, #(0xf << 20) @ Enable full access for p10,11
|
||||
MCR p15, 0, r1, c1, c0, 2 @ Access Control Register = r1
|
||||
MOV r1, #0
|
||||
MCR p15, 0, r1, c7, c5, 4 @ Flush prefetch buffer because of FMXR below and
|
||||
@ CP 10 & 11 were only just enabled
|
||||
MOV r0, #VFPEnable @ Enable VFP itself
|
||||
FMXR FPEXC, r0 @ FPEXC = r0
|
||||
#endif
|
||||
|
||||
LDR r0, =_tx_thread_smp_release_cores_flag @ Build address of release cores flag
|
||||
MOV r1, #0
|
||||
STR r1, [r0]
|
||||
@; [Grape 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
|
||||
|
||||
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@; Initialization for PRIMARY CPU
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@
|
||||
@ EXPORT primaryCPUInit
|
||||
.align 2
|
||||
.global primaryCPUInit
|
||||
.type primaryCPUInit,function
|
||||
primaryCPUInit:
|
||||
|
||||
@ ;
|
||||
@ ; GIC Init
|
||||
@ ; ---------
|
||||
BL enableGIC
|
||||
BL enableGICProcessorInterface
|
||||
|
||||
BL enableCaches
|
||||
|
||||
@; /* Setup Timer for periodic interrupts. */
|
||||
@;/*------------------------------------------------------------------------*/
|
||||
@;/*--- Versatile Express(Timer0) ---*/
|
||||
LDR r0, =GIC_DIST_CPUTARGET
|
||||
LDR r2, =GIC_DIST_CPUTARGET_VALUE
|
||||
STR r2, [r0, #0]
|
||||
|
||||
LDR r0, =GIC_DIST_CONFIG
|
||||
LDR r2, =GIC_DIST_CONFIG_VALUE
|
||||
STR r2, [r0, #0]
|
||||
|
||||
LDR r0, =GIC_DIST_PRIO
|
||||
LDR r2, =GIC_DIST_PRIO_VALUE
|
||||
STR r2, [r0, #0]
|
||||
|
||||
LDR r0, =GIC_DIST_CONTROL
|
||||
LDR r2, =GIC_DIST_CONTROL_VALUE
|
||||
STR r2, [r0, #0]
|
||||
|
||||
LDR r0, =GIC_CPU_CONTROL
|
||||
LDR r2, =GIC_CPU_CONTROL_VALUE
|
||||
STR r2, [r0, #0]
|
||||
|
||||
LDR r0, =GIC_CPU_PRIO_MASK
|
||||
LDR r2, =GIC_CPU_PRIO_MASK_VALUE
|
||||
STR r2, [r0, #0]
|
||||
|
||||
LDR r0, =GIC_DIST_ENABLE_SET
|
||||
LDR r2, =GIC_DIST_ENABLE_SET_VALUE
|
||||
STR r2, [r0, #0]
|
||||
@;;;;;
|
||||
LDR r0, =HANDLER_SET
|
||||
LDR r2, =HANDLER_SET_VALUE
|
||||
STR r2, [r0, #0]
|
||||
@;
|
||||
@; LDR r0, =HANDLER_ADDRESS
|
||||
@; LDR r2, =IRQ_Handler
|
||||
@; STR r2, [r0, #0]
|
||||
@;;;;;
|
||||
LDR r0, =TIMER_CTRL
|
||||
LDR r2, =TIMER_CTRL_STOP
|
||||
STR r2, [r0, #0]
|
||||
|
||||
LDR r2, =TIMER_INT_CLR
|
||||
LDR r0, =1
|
||||
STR r0, [r2, #0]
|
||||
|
||||
LDR r0, =TIMER_LOAD
|
||||
LDR r2, =TIMER_LOAD_VALUE
|
||||
STR r2, [r0, #0]
|
||||
|
||||
LDR r0, =TIMER_CTRL
|
||||
LDR r2, =TIMER_CTRL_VALUE
|
||||
STR r2, [r0, #0]
|
||||
@;/*--- Versatile Express(Timer0) ---*/
|
||||
@;/*------------------------------------------------------------------------*/
|
||||
|
||||
@ ;
|
||||
@ ; Branch to C lib code
|
||||
@ ; ----------------------
|
||||
B _start
|
||||
|
||||
@; [Grape Change End]
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@; Initialization for SECONDARY CPUs
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT secondaryCPUsInit
|
||||
.align 2
|
||||
.global secondaryCPUsInit
|
||||
.type secondaryCPUsInit,function
|
||||
secondaryCPUsInit:
|
||||
|
||||
@ ;
|
||||
@ ; GIC Init
|
||||
@ ; ---------
|
||||
BL enableGICProcessorInterface
|
||||
|
||||
MOV r0, #0x1F @ Priority
|
||||
BL setPriorityMask
|
||||
|
||||
MOV r0, #0x0 @ ID
|
||||
BL enableIntID
|
||||
|
||||
MOV r0, #0x0 @ ID
|
||||
MOV r1, #0x0 @ Priority
|
||||
BL setIntPriority
|
||||
|
||||
|
||||
@ ;
|
||||
@ ; Holding Pen
|
||||
@ ; ------------
|
||||
@; [Grape Change Start]
|
||||
@; 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 rest of example, so mask out interrupts
|
||||
@; [Grape Change End]
|
||||
@
|
||||
@
|
||||
@ ;
|
||||
@ ; Branch to application
|
||||
@ ; ----------------------
|
||||
@; [Grape Change Start]
|
||||
@; B main_app
|
||||
|
||||
@; BL enableBranchPrediction
|
||||
BL enableCaches
|
||||
|
||||
B _tx_thread_smp_initialize_wait
|
||||
@; [Grape Change End]
|
||||
@
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@; End of code
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ END
|
||||
@
|
||||
@; ------------------------------------------------------------
|
||||
@; End of startup.s
|
||||
@; ------------------------------------------------------------
|
||||
@@ -0,0 +1,141 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 */
|
||||
@/** */
|
||||
@/** Initialize */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_initialize.h"
|
||||
@#include "tx_thread.h"
|
||||
@#include "tx_timer.h"
|
||||
@
|
||||
@
|
||||
@
|
||||
@
|
||||
|
||||
.arm
|
||||
|
||||
.global _tx_thread_system_stack_ptr
|
||||
.global _tx_initialize_unused_memory
|
||||
.global _tx_version_id
|
||||
.global _tx_build_options
|
||||
.global _end
|
||||
@
|
||||
@
|
||||
|
||||
@
|
||||
@
|
||||
@/* Define the 16-bit Thumb mode veneer for _tx_initialize_low_level for
|
||||
@ applications calling this function from to 16-bit Thumb mode. */
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
.thumb
|
||||
.global $_tx_initialize_low_level
|
||||
.type $_tx_initialize_low_level,function
|
||||
$_tx_initialize_low_level:
|
||||
BX pc @ Switch to 32-bit mode
|
||||
NOP @
|
||||
.arm
|
||||
STMFD sp!, {lr} @ Save return address
|
||||
BL _tx_initialize_low_level @ Call _tx_initialize_low_level function
|
||||
LDMFD sp!, {lr} @ Recover saved return address
|
||||
BX lr @ Return to 16-bit caller
|
||||
@
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_initialize_low_level MPCore/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_initialize_low_level(VOID)
|
||||
@{
|
||||
.global _tx_initialize_low_level
|
||||
.type _tx_initialize_low_level,function
|
||||
_tx_initialize_low_level:
|
||||
@
|
||||
@ /* Save the first available memory address. */
|
||||
@ _tx_initialize_unused_memory = (VOID_PTR) _end;
|
||||
@
|
||||
LDR r1, =_end @ Get end of non-initialized RAM area
|
||||
LDR r2, =_tx_initialize_unused_memory @ Pickup unused memory ptr address
|
||||
ADD r1, r1, #8 @ Increment to next free word
|
||||
STR r1, [r2] @ Save first free memory address
|
||||
@
|
||||
@
|
||||
|
||||
@ /* Done, return to caller. */
|
||||
@
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
@
|
||||
BUILD_OPTIONS:
|
||||
.word _tx_build_options @ Reference to bring in
|
||||
VERSION_ID:
|
||||
.word _tx_version_id @ Reference to bring in
|
||||
|
||||
|
||||
554
ports_smp/cortex_a7_smp/gnu/example_build/v7.S
Normal file
554
ports_smp/cortex_a7_smp/gnu/example_build/v7.S
Normal file
@@ -0,0 +1,554 @@
|
||||
@; ------------------------------------------------------------
|
||||
@; v7-A Cache and Branch Prediction Maintenance Operations
|
||||
@;
|
||||
@; Copyright (c) 2011 ARM Ltd. All rights reserved.
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ PRESERVE8
|
||||
@
|
||||
@ AREA v7Opps,CODE,READONLY
|
||||
|
||||
.arm
|
||||
.text
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@; Interrupt enable/disable
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ ; Could use intrinsic instead of these
|
||||
@
|
||||
@ EXPORT enableInterrupts
|
||||
@ ; void enableInterrupts(void);
|
||||
.align 2
|
||||
.global enableInterrupts
|
||||
.type enableInterrupts,function
|
||||
enableInterrupts:
|
||||
CPSIE i
|
||||
BX lr
|
||||
|
||||
|
||||
@ EXPORT disableInterrupts
|
||||
@ ; void disableInterrupts(void);
|
||||
.align 2
|
||||
.global disableInterrupts
|
||||
.type disableInterrupts,function
|
||||
disableInterrupts:
|
||||
CPSID i
|
||||
BX lr
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@; Cache Maintenance
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT enableCaches
|
||||
@ ; void enableCaches(void);
|
||||
.align 2
|
||||
.global enableCaches
|
||||
.type enableCaches,function
|
||||
enableCaches:
|
||||
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
|
||||
|
||||
|
||||
|
||||
@ EXPORT disableCaches
|
||||
@ ; void disableCaches(void)
|
||||
.align 2
|
||||
.global disableCaches
|
||||
.type disableCaches,function
|
||||
disableCaches:
|
||||
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
|
||||
|
||||
|
||||
@ EXPORT cleanDCache
|
||||
@ ; void cleanDCache(void);
|
||||
.align 2
|
||||
.global cleanDCache
|
||||
.type cleanDCache,function
|
||||
cleanDCache:
|
||||
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, #0x07000000
|
||||
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, #0x07 @ 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
|
||||
|
||||
|
||||
@ EXPORT cleanInvalidateDCache
|
||||
@ ; void cleanInvalidateDCache(void);
|
||||
.align 2
|
||||
.global cleanInvalidateDCache
|
||||
.type cleanInvalidateDCache,function
|
||||
cleanInvalidateDCache:
|
||||
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, #0x07000000
|
||||
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, #0x07 @ 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
|
||||
|
||||
|
||||
|
||||
@ EXPORT invalidateCaches
|
||||
@ ; void invalidateCaches(void);
|
||||
.align 2
|
||||
.global invalidateCaches
|
||||
.type invalidateCaches,function
|
||||
invalidateCaches:
|
||||
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, #0x07000000
|
||||
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, #0x07 @ 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
|
||||
|
||||
|
||||
@ EXPORT invalidateCaches_IS
|
||||
@ ; void invalidateCaches_IS(void);
|
||||
.align 2
|
||||
.global invalidateCaches_IS
|
||||
.type invalidateCaches_IS,function
|
||||
invalidateCaches_IS:
|
||||
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, #0x07000000
|
||||
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, #0x07 @ 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
|
||||
|
||||
@ ------------------------------------------------------------
|
||||
@ TLB
|
||||
@ ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT invalidateUnifiedTLB
|
||||
@ ; void invalidateUnifiedTLB(void);
|
||||
.align 2
|
||||
.global invalidateUnifiedTLB
|
||||
.type invalidateUnifiedTLB,function
|
||||
invalidateUnifiedTLB:
|
||||
MOV r0, #0
|
||||
MCR p15, 0, r0, c8, c7, 0 @ TLBIALL - Invalidate entire unified TLB
|
||||
BX lr
|
||||
|
||||
@ EXPORT invalidateUnifiedTLB_IS
|
||||
@ ; void invalidateUnifiedTLB_IS(void);
|
||||
.align 2
|
||||
.global invalidateUnifiedTLB_IS
|
||||
.type invalidateUnifiedTLB_IS,function
|
||||
invalidateUnifiedTLB_IS:
|
||||
MOV r0, #1
|
||||
MCR p15, 0, r0, c8, c3, 0 @ TLBIALLIS - Invalidate entire unified TLB Inner Shareable
|
||||
BX lr
|
||||
|
||||
|
||||
@ ------------------------------------------------------------
|
||||
@ Branch Prediction
|
||||
@ ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT enableBranchPrediction
|
||||
@ ; void enableBranchPrediction(void)
|
||||
.align 2
|
||||
.global enableBranchPrediction
|
||||
.type enableBranchPrediction,function
|
||||
enableBranchPrediction:
|
||||
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
|
||||
|
||||
@ EXPORT disableBranchPrediction
|
||||
@ ; void disableBranchPrediction(void)
|
||||
.align 2
|
||||
.global disableBranchPrediction
|
||||
.type disableBranchPrediction,function
|
||||
disableBranchPrediction:
|
||||
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
|
||||
|
||||
|
||||
@ EXPORT flushBranchTargetCache
|
||||
@ ; void flushBranchTargetCache(void)
|
||||
.align 2
|
||||
.global flushBranchTargetCache
|
||||
.type flushBranchTargetCache,function
|
||||
flushBranchTargetCache:
|
||||
MOV r0, #0
|
||||
MCR p15, 0, r0, c7, c5, 6 @ BPIALL - Invalidate entire branch predictor array
|
||||
BX lr
|
||||
|
||||
|
||||
@ EXPORT flushBranchTargetCache_IS
|
||||
@ ; void flushBranchTargetCache_IS(void)
|
||||
.align 2
|
||||
.global flushBranchTargetCache_IS
|
||||
.type flushBranchTargetCache_IS,function
|
||||
flushBranchTargetCache_IS:
|
||||
MOV r0, #0
|
||||
MCR p15, 0, r0, c7, c1, 6 @ BPIALLIS - Invalidate entire branch predictor array Inner Shareable
|
||||
BX lr
|
||||
|
||||
@ ------------------------------------------------------------
|
||||
@ High Vecs
|
||||
@ ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT enableHighVecs
|
||||
@ ; void enableHighVecs(void);
|
||||
.align 2
|
||||
.global enableHighVecs
|
||||
.type enableHighVecs,function
|
||||
enableHighVecs:
|
||||
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
|
||||
|
||||
|
||||
@ EXPORT disableHighVecs
|
||||
@ ; void disable_highvecs(void);
|
||||
.align 2
|
||||
.global disableHighVecs
|
||||
.type disableHighVecs,function
|
||||
disableHighVecs:
|
||||
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
|
||||
|
||||
|
||||
@ ------------------------------------------------------------
|
||||
@ Context ID
|
||||
@ ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT getContextID
|
||||
@ ; uint32_t getContextIDd(void);
|
||||
.align 2
|
||||
.global getContextID
|
||||
.type getContextID,function
|
||||
getContextID:
|
||||
MRC p15, 0, r0, c13, c0, 1 @ Read Context ID Register
|
||||
BX lr
|
||||
|
||||
|
||||
@ EXPORT setContextID
|
||||
@ ; void setContextID(uint32_t);
|
||||
.align 2
|
||||
.global setContextID
|
||||
.type setContextID,function
|
||||
setContextID:
|
||||
MCR p15, 0, r0, c13, c0, 1 @ Write Context ID Register
|
||||
BX lr
|
||||
|
||||
|
||||
@ ------------------------------------------------------------
|
||||
@ ID registers
|
||||
@ ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT getMIDR
|
||||
@ ; uint32_t getMIDR(void);
|
||||
.align 2
|
||||
.global getMIDR
|
||||
.type getMIDR,function
|
||||
getMIDR:
|
||||
MRC p15, 0, r0, c0, c0, 0 @ Read Main ID Register (MIDR)
|
||||
BX lr
|
||||
|
||||
|
||||
@ EXPORT getMPIDR
|
||||
@ ; uint32_t getMPIDR(void);
|
||||
.align 2
|
||||
.global getMPIDR
|
||||
.type getMPIDR,function
|
||||
getMPIDR:
|
||||
MRC p15, 0, r0, c0 ,c0, 5@ Read Multiprocessor ID register (MPIDR)
|
||||
BX lr
|
||||
|
||||
|
||||
@ ------------------------------------------------------------
|
||||
@ CP15 SMP related
|
||||
@ ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT getBaseAddr
|
||||
@ ; uint32_t getBaseAddr(void)
|
||||
@ ; Returns the value CBAR (base address of the private peripheral memory space)
|
||||
.align 2
|
||||
.global getBaseAddr
|
||||
.type getBaseAddr,function
|
||||
getBaseAddr:
|
||||
MRC p15, 4, r0, c15, c0, 0 @ Read periph base address
|
||||
BX lr
|
||||
|
||||
|
||||
@ ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT getCPUID
|
||||
@ ; uint32_t getCPUID(void)
|
||||
@ ; Returns the CPU ID (0 to 3) of the CPU executed on
|
||||
.align 2
|
||||
.global getCPUID
|
||||
.type getCPUID,function
|
||||
getCPUID:
|
||||
MRC p15, 0, r0, c0, c0, 5 @ Read CPU ID register
|
||||
AND r0, r0, #0x03 @ Mask off, leaving the CPU ID field
|
||||
BX lr
|
||||
|
||||
|
||||
@ ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT goToSleep
|
||||
@ ; void goToSleep(void)
|
||||
.align 2
|
||||
.global goToSleep
|
||||
.type goToSleep,function
|
||||
goToSleep:
|
||||
WFI @ Go into standby
|
||||
B goToSleep @ Catch in case of rogue events
|
||||
BX lr
|
||||
|
||||
|
||||
@ ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT joinSMP
|
||||
@ ; void joinSMP(void)
|
||||
@ ; Sets the ACTRL.SMP bit
|
||||
.align 2
|
||||
.global joinSMP
|
||||
.type joinSMP,function
|
||||
joinSMP:
|
||||
|
||||
@ SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg
|
||||
|
||||
MRC p15, 0, r0, c1, c0, 1 @ Read ACTLR
|
||||
MOV r1, r0
|
||||
ORR r0, r0, #0x040 @ Set bit 6
|
||||
CMP r0, r1
|
||||
MCRNE p15, 0, r0, c1, c0, 1 @ Write ACTLR
|
||||
|
||||
BX lr
|
||||
|
||||
|
||||
@ ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT leaveSMP
|
||||
@ ; void leaveSMP(void)
|
||||
@ ; Clear the ACTRL.SMP bit
|
||||
.align 2
|
||||
.global leaveSMP
|
||||
.type leaveSMP,function
|
||||
leaveSMP:
|
||||
|
||||
@ 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
|
||||
|
||||
|
||||
@ ------------------------------------------------------------
|
||||
@
|
||||
@ EXPORT leaveSMP
|
||||
@ ; void leaveSMP(void)
|
||||
@ ; Clear the ACTRL.SMP bit
|
||||
.align 2
|
||||
.global _exit
|
||||
.type _exit,function
|
||||
_exit:
|
||||
BX lr
|
||||
|
||||
@
|
||||
@; ------------------------------------------------------------
|
||||
@; End of code
|
||||
@; ------------------------------------------------------------
|
||||
@
|
||||
@ END
|
||||
@
|
||||
@; ------------------------------------------------------------
|
||||
@; End of v7.s
|
||||
@; ------------------------------------------------------------
|
||||
145
ports_smp/cortex_a7_smp/gnu/example_build/v7.h
Normal file
145
ports_smp/cortex_a7_smp/gnu/example_build/v7.h
Normal file
@@ -0,0 +1,145 @@
|
||||
// ------------------------------------------------------------
|
||||
// v7-A Cache, TLB and Branch Prediction Maintenance Operations
|
||||
// Header File
|
||||
//
|
||||
// Copyright (c) 2011 ARM Ltd. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#ifndef _ARMV7A_GENERIC_H
|
||||
#define _ARMV7A_GENERIC_H
|
||||
|
||||
//
|
||||
// Note:
|
||||
// *_IS() stands for "inner shareable"
|
||||
// DO NOT USE THESE FUNCTIONS ON A CORTEX-A8
|
||||
//
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Interrupts
|
||||
// Enable/disables IRQs (not FIQs)
|
||||
void enableInterrupts(void);
|
||||
void disableInterrupts(void);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Caches
|
||||
|
||||
void invalidateCaches_IS(void);
|
||||
void cleanInvalidateDCache(void);
|
||||
void invalidateCaches_IS(void);
|
||||
void enableCaches(void);
|
||||
void disableCaches(void);
|
||||
void invalidateCaches(void);
|
||||
void cleanDCache(void);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// TLBs
|
||||
|
||||
void invalidateUnifiedTLB(void);
|
||||
void invalidateUnifiedTLB_IS(void);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Branch prediction
|
||||
|
||||
void enableBranchPrediction(void);
|
||||
void disableBranchPrediction(void);
|
||||
void flushBranchTargetCache(void);
|
||||
void flushBranchTargetCache_IS(void);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// High Vecs
|
||||
|
||||
void enableHighVecs(void);
|
||||
void disableHighVecs(void);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// ID Registers
|
||||
|
||||
unsigned int getMIDR(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
|
||||
|
||||
unsigned int getMPIDR(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
|
||||
|
||||
unsigned int getContextID(void);
|
||||
|
||||
void setContextID(unsigned int);
|
||||
|
||||
#define CONTEXTID_ASID_SHIFT 0
|
||||
#define CONTEXTID_ASID_MASK 0xFF
|
||||
#define CONTEXTID_PROCID_SHIFT 8
|
||||
#define CONTEXTID_PROCID_MASK 0x00FFFFFF
|
||||
|
||||
// tmp = getContextID();
|
||||
// ASID = tmp & CONTEXTID_ASID_MASK;
|
||||
// PROCID = (tmp >> CONTEXTID_PROCID_SHIFT) & CONTEXTID_PROCID_MASK;
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// SMP related for ARMv7-A MPCore processors
|
||||
//
|
||||
// DO NOT CALL THESE FUNCTIONS ON A CORTEX-A8
|
||||
|
||||
// Returns the base address of the private peripheral memory space
|
||||
unsigned int getBaseAddr(void);
|
||||
|
||||
// Returns the CPU ID (0 to 3) of the CPU executed on
|
||||
#define MP_CPU0 (0)
|
||||
#define MP_CPU1 (1)
|
||||
#define MP_CPU2 (2)
|
||||
#define MP_CPU3 (3)
|
||||
unsigned int getCPUID(void);
|
||||
|
||||
// Set this core as participating in SMP
|
||||
void joinSMP(void);
|
||||
|
||||
// Set this core as NOT participating in SMP
|
||||
void leaveSMP(void);
|
||||
|
||||
// Go to sleep, never returns
|
||||
void goToSleep(void);
|
||||
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// End of v7.h
|
||||
// ------------------------------------------------------------
|
||||
404
ports_smp/cortex_a7_smp/gnu/inc/tx_port.h
Normal file
404
ports_smp/cortex_a7_smp/gnu/inc/tx_port.h
Normal file
@@ -0,0 +1,404 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* 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-A7/GNU */
|
||||
/* 6.0.1 */
|
||||
/* */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, 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 */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#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 4
|
||||
#endif
|
||||
|
||||
|
||||
/* Define the ThreadX SMP core mask. */
|
||||
|
||||
#ifndef TX_THREAD_SMP_CORE_MASK
|
||||
#define TX_THREAD_SMP_CORE_MASK 0xf /* Where bit 0 represents Core 0, bit 1 represents Core 1, etc. */
|
||||
#endif
|
||||
|
||||
|
||||
/* 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
|
||||
|
||||
#if __TARGET_ARCH_ARM > 4
|
||||
|
||||
#ifndef __thumb__
|
||||
|
||||
#define TX_LOWEST_SET_BIT_CALCULATE(m, b) m = m & ((ULONG) (-((LONG) m))); \
|
||||
asm volatile (" CLZ %0,%1 ": "=r" (b) : "r" (m) ); \
|
||||
b = 31 - b;
|
||||
#endif
|
||||
#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-A7. 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 SMP/Cortex-A7/GNU Version 6.0.1 *";
|
||||
#else
|
||||
extern CHAR _tx_version_id[];
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
343
ports_smp/cortex_a7_smp/gnu/readme_threadx.txt
Normal file
343
ports_smp/cortex_a7_smp/gnu/readme_threadx.txt
Normal file
@@ -0,0 +1,343 @@
|
||||
Microsoft's Azure RTOS ThreadX for Cortex-A7
|
||||
|
||||
Using the GNU Tools
|
||||
|
||||
1. Building the ThreadX run-time Library
|
||||
|
||||
First make sure you are in the "example_build" directory. Also, make sure that
|
||||
you have setup your path and other environment variables necessary for the GNU
|
||||
development environment.
|
||||
|
||||
At this point you may run the build_threadx.bat batch file. This will build the
|
||||
ThreadX run-time environment in the "example_build" directory.
|
||||
|
||||
You should observe assembly and compilation of a series of ThreadX source
|
||||
files. At the end of the batch file, they are all combined into the
|
||||
run-time library file: tx.a. This file must be linked with your
|
||||
application in order to use ThreadX.
|
||||
|
||||
|
||||
2. Demonstration System
|
||||
|
||||
The ThreadX demonstration is designed to execute under the ARM Cortex-A7x4 FVP.
|
||||
|
||||
Building the demonstration is easy; simply execute the build_threadx_sample.bat
|
||||
batch file while inside the "example_build" directory.
|
||||
|
||||
You should observe the compilation of sample_threadx.c (which is the demonstration
|
||||
application) and linking with TX.A. The resulting file DEMO is a binary file
|
||||
that can be downloaded and executed.
|
||||
|
||||
|
||||
3. System Initialization
|
||||
|
||||
The entry point in ThreadX for the Cortex-A7 using GNU tools is at label
|
||||
Reset_Handler in startup.s. After the basic core initialization is complete,
|
||||
control will transfer to __main, which is where all static and global pre-set
|
||||
C variable initialization processing takes place.
|
||||
|
||||
The ThreadX tx_initialize_low_level.s file is responsible for setting up
|
||||
various system data structures, the vector area, and a periodic timer interrupt
|
||||
source. By default, the vector area is defined to be located in the Init area,
|
||||
which is defined at the top of tx_initialize_low_level.s. This area is typically
|
||||
located at 0. In situations where this is impossible, the vectors at the beginning
|
||||
of the Init area should be copied to address 0.
|
||||
|
||||
This is also where initialization of a periodic timer interrupt source
|
||||
should take place.
|
||||
|
||||
In addition, _tx_initialize_low_level determines the first available
|
||||
address for use by the application, which is supplied as the sole input
|
||||
parameter to your application definition function, tx_application_define.
|
||||
|
||||
|
||||
4. Register Usage and Stack Frames
|
||||
|
||||
The GNU compiler assumes that registers r0-r3 (a1-a4) and r12 (ip) are scratch
|
||||
registers for each function. All other registers used by a C function must
|
||||
be preserved by the function. ThreadX takes advantage of this in situations
|
||||
where a context switch happens as a result of making a ThreadX service call
|
||||
(which is itself a C function). In such cases, the saved context of a thread
|
||||
is only the non-scratch registers.
|
||||
|
||||
The following defines the saved context stack frames for context switches
|
||||
that occur as a result of interrupt handling or from thread-level API calls.
|
||||
All suspended threads have one of these two types of stack frames. The top
|
||||
of the suspended thread's stack is pointed to by tx_thread_stack_ptr in the
|
||||
associated thread control block TX_THREAD.
|
||||
|
||||
|
||||
|
||||
Offset Interrupted Stack Frame Non-Interrupt Stack Frame
|
||||
|
||||
0x00 1 0
|
||||
0x04 CPSR CPSR
|
||||
0x08 r0 (a1) r4 (v1)
|
||||
0x0C r1 (a2) r5 (v2)
|
||||
0x10 r2 (a3) r6 (v3)
|
||||
0x14 r3 (a4) r7 (v4)
|
||||
0x18 r4 (v1) r8 (v5)
|
||||
0x1C r5 (v2) r9 (v6)
|
||||
0x20 r6 (v3) r10 (v7)
|
||||
0x24 r7 (v4) r11 (fp)
|
||||
0x28 r8 (v5) r14 (lr)
|
||||
0x2C r9 (v6)
|
||||
0x30 r10 (v7)
|
||||
0x34 r11 (fp)
|
||||
0x38 r12 (ip)
|
||||
0x3C r14 (lr)
|
||||
0x40 PC
|
||||
|
||||
|
||||
5. Improving Performance
|
||||
|
||||
The distribution version of ThreadX is built without any compiler
|
||||
optimizations. This makes it easy to debug because you can trace or set
|
||||
breakpoints inside of ThreadX itself. Of course, this costs some
|
||||
performance. To make it run faster, you can change the build_threadx.bat file to
|
||||
remove the -g option and enable all compiler optimizations.
|
||||
|
||||
In addition, you can eliminate the ThreadX basic API error checking by
|
||||
compiling your application code with the symbol TX_DISABLE_ERROR_CHECKING
|
||||
defined.
|
||||
|
||||
|
||||
6. Interrupt Handling
|
||||
|
||||
ThreadX provides complete and high-performance interrupt handling for Cortex-A7
|
||||
targets. There are a certain set of requirements that are defined in the
|
||||
following sub-sections:
|
||||
|
||||
|
||||
6.1 Vector Area
|
||||
|
||||
The Cortex-A7 vectors start at address zero. The demonstration system startup
|
||||
Init area contains the vectors and is loaded at address zero. On actual
|
||||
hardware platforms, this area might have to be copied to address 0.
|
||||
|
||||
|
||||
6.2 IRQ ISRs
|
||||
|
||||
ThreadX fully manages standard and vectored IRQ interrupts. ThreadX also supports nested
|
||||
IRQ interrupts. The following sub-sections define the IRQ capabilities.
|
||||
|
||||
|
||||
6.2.1 Standard IRQ ISRs
|
||||
|
||||
The standard ARM IRQ mechanism has a single interrupt vector at address 0x18. This IRQ
|
||||
interrupt is managed by the __tx_irq_handler code in tx_initialize_low_level. The following
|
||||
is the default IRQ handler defined in tx_initialize_low_level.s:
|
||||
|
||||
EXPORT __tx_irq_handler
|
||||
EXPORT __tx_irq_processing_return
|
||||
__tx_irq_handler
|
||||
;
|
||||
; /* Jump to context save to save system context. */
|
||||
B _tx_thread_context_save ; Jump to the context save
|
||||
__tx_irq_processing_return
|
||||
;
|
||||
; /* At this point execution is still in the IRQ mode. The CPSR, point of
|
||||
; interrupt, and all C scratch registers are available for use. Note
|
||||
; that IRQ interrupts are still disabled upon return from the context
|
||||
; save function. */
|
||||
;
|
||||
; /* Application ISR call(s) go here! */
|
||||
;
|
||||
; /* Jump to context restore to restore system context. */
|
||||
B _tx_thread_context_restore
|
||||
|
||||
|
||||
6.2.2 Vectored IRQ ISRs
|
||||
|
||||
The vectored ARM IRQ mechanism has multiple interrupt vectors at addresses specified
|
||||
by the particular implementation. The following is an example IRQ handler defined in
|
||||
tx_initialize_low_level.s:
|
||||
|
||||
EXPORT __tx_irq_example_handler
|
||||
__tx_irq_example_handler
|
||||
;
|
||||
; /* Call context save to save system context. */
|
||||
|
||||
STMDB sp!, {r0-r3} ; Save some scratch registers
|
||||
MRS r0, SPSR ; Pickup saved SPSR
|
||||
SUB lr, lr, #4 ; Adjust point of interrupt
|
||||
STMDB sp!, {r0, r10, r12, lr} ; Store other scratch registers
|
||||
BL _tx_thread_vectored_context_save ; Call the vectored IRQ context save
|
||||
;
|
||||
; /* At this point execution is still in the IRQ mode. The CPSR, point of
|
||||
; interrupt, and all C scratch registers are available for use. Note
|
||||
; that IRQ interrupts are still disabled upon return from the context
|
||||
; save function. */
|
||||
;
|
||||
; /* Application ISR call goes here! */
|
||||
;
|
||||
; /* Jump to context restore to restore system context. */
|
||||
B _tx_thread_context_restore
|
||||
|
||||
|
||||
6.2.3 Nested IRQ Support
|
||||
|
||||
By default, nested IRQ interrupt support is not enabled. To enable nested
|
||||
IRQ support, the entire library should be built with TX_ENABLE_IRQ_NESTING
|
||||
defined. With this defined, two new IRQ interrupt management services are
|
||||
available, namely _tx_thread_irq_nesting_start and _tx_thread_irq_nesting_end.
|
||||
These function should be called between the IRQ context save and restore
|
||||
calls.
|
||||
|
||||
Execution between the calls to _tx_thread_irq_nesting_start and
|
||||
_tx_thread_irq_nesting_end is enabled for IRQ nesting. This is achieved
|
||||
by switching from IRQ mode to SYS mode and enabling IRQ interrupts.
|
||||
The SYS mode stack is used during the SYS mode operation, which was
|
||||
setup in tx_initialize_low_level.s. When nested IRQ interrupts are no longer required,
|
||||
calling the _tx_thread_irq_nesting_end service disables nesting by disabling
|
||||
IRQ interrupts and switching back to IRQ mode in preparation for the IRQ
|
||||
context restore service.
|
||||
|
||||
The following is an example of enabling IRQ nested interrupts in a standard
|
||||
IRQ handler:
|
||||
|
||||
EXPORT __tx_irq_handler
|
||||
EXPORT __tx_irq_processing_return
|
||||
__tx_irq_handler
|
||||
;
|
||||
; /* Jump to context save to save system context. */
|
||||
B _tx_thread_context_save
|
||||
__tx_irq_processing_return
|
||||
;
|
||||
; /* Enable nested IRQ interrupts. NOTE: Since this service returns
|
||||
; with IRQ interrupts enabled, all IRQ interrupt sources must be
|
||||
; cleared prior to calling this service. */
|
||||
BL _tx_thread_irq_nesting_start
|
||||
;
|
||||
; /* Application ISR call(s) go here! */
|
||||
;
|
||||
; /* Disable nested IRQ interrupts. The mode is switched back to
|
||||
; IRQ mode and IRQ interrupts are disable upon return. */
|
||||
BL _tx_thread_irq_nesting_end
|
||||
;
|
||||
; /* Jump to context restore to restore system context. */
|
||||
B _tx_thread_context_restore
|
||||
|
||||
|
||||
6.3 FIQ Interrupts
|
||||
|
||||
By default, Cortex-A7 FIQ interrupts are left alone by ThreadX. Of course, this
|
||||
means that the application is fully responsible for enabling the FIQ interrupt
|
||||
and saving/restoring any registers used in the FIQ ISR processing. To globally
|
||||
enable FIQ interrupts, the application should enable FIQ interrupts at the
|
||||
beginning of each thread or before any threads are created in tx_application_define.
|
||||
In addition, the application must ensure that no ThreadX service calls are made
|
||||
from default FIQ ISRs, which is located in tx_initialize_low_level.s.
|
||||
|
||||
|
||||
6.3.1 Managed FIQ Interrupts
|
||||
|
||||
Full ThreadX management of FIQ interrupts is provided if the ThreadX sources
|
||||
are built with the TX_ENABLE_FIQ_SUPPORT defined. If the library is built
|
||||
this way, the FIQ interrupt handlers are very similar to the IRQ interrupt
|
||||
handlers defined previously. The following is default FIQ handler
|
||||
defined in tx_initialize_low_level.s:
|
||||
|
||||
|
||||
EXPORT __tx_fiq_handler
|
||||
EXPORT __tx_fiq_processing_return
|
||||
__tx_fiq_handler
|
||||
;
|
||||
; /* Jump to fiq context save to save system context. */
|
||||
B _tx_thread_fiq_context_save
|
||||
__tx_fiq_processing_return:
|
||||
;
|
||||
; /* At this point execution is still in the FIQ mode. The CPSR, point of
|
||||
; interrupt, and all C scratch registers are available for use. */
|
||||
;
|
||||
; /* Application FIQ handlers can be called here! */
|
||||
;
|
||||
; /* Jump to fiq context restore to restore system context. */
|
||||
B _tx_thread_fiq_context_restore
|
||||
|
||||
|
||||
6.3.1.1 Nested FIQ Support
|
||||
|
||||
By default, nested FIQ interrupt support is not enabled. To enable nested
|
||||
FIQ support, the entire library should be built with TX_ENABLE_FIQ_NESTING
|
||||
defined. With this defined, two new FIQ interrupt management services are
|
||||
available, namely _tx_thread_fiq_nesting_start and _tx_thread_fiq_nesting_end.
|
||||
These function should be called between the FIQ context save and restore
|
||||
calls.
|
||||
|
||||
Execution between the calls to _tx_thread_fiq_nesting_start and
|
||||
_tx_thread_fiq_nesting_end is enabled for FIQ nesting. This is achieved
|
||||
by switching from FIQ mode to SYS mode and enabling FIQ interrupts.
|
||||
The SYS mode stack is used during the SYS mode operation, which was
|
||||
setup in tx_initialize_low_level.s. When nested FIQ interrupts are no longer required,
|
||||
calling the _tx_thread_fiq_nesting_end service disables nesting by disabling
|
||||
FIQ interrupts and switching back to FIQ mode in preparation for the FIQ
|
||||
context restore service.
|
||||
|
||||
The following is an example of enabling FIQ nested interrupts in the
|
||||
typical FIQ handler:
|
||||
|
||||
|
||||
EXPORT __tx_fiq_handler
|
||||
EXPORT __tx_fiq_processing_return
|
||||
__tx_fiq_handler
|
||||
;
|
||||
; /* Jump to fiq context save to save system context. */
|
||||
B _tx_thread_fiq_context_save
|
||||
__tx_fiq_processing_return
|
||||
;
|
||||
; /* At this point execution is still in the FIQ mode. The CPSR, point of
|
||||
; interrupt, and all C scratch registers are available for use. */
|
||||
;
|
||||
; /* Enable nested FIQ interrupts. NOTE: Since this service returns
|
||||
; with FIQ interrupts enabled, all FIQ interrupt sources must be
|
||||
; cleared prior to calling this service. */
|
||||
BL _tx_thread_fiq_nesting_start
|
||||
;
|
||||
; /* Application FIQ handlers can be called here! */
|
||||
;
|
||||
; /* Disable nested FIQ interrupts. The mode is switched back to
|
||||
; FIQ mode and FIQ interrupts are disable upon return. */
|
||||
BL _tx_thread_fiq_nesting_end
|
||||
;
|
||||
; /* Jump to fiq context restore to restore system context. */
|
||||
B _tx_thread_fiq_context_restore
|
||||
|
||||
|
||||
7. ThreadX Timer Interrupt
|
||||
|
||||
ThreadX requires a periodic interrupt source to manage all time-slicing,
|
||||
thread sleeps, timeouts, and application timers. Without such a timer
|
||||
interrupt source, these services are not functional. However, all other
|
||||
ThreadX services are operational without a periodic timer source.
|
||||
|
||||
To add the timer interrupt processing, simply make a call to
|
||||
_tx_timer_interrupt in the IRQ processing. An example of this can be
|
||||
found in the file tx_initialize_low_level.s in the Integrator sub-directories.
|
||||
|
||||
|
||||
8. VFP Support
|
||||
|
||||
VFP support is optional, it can be enabled by building the ThreadX library
|
||||
assembly code with the following command-line option:
|
||||
|
||||
-mfpu=neon -DTARGET_FPU_VFP
|
||||
|
||||
Note that if ISRs need to use VFP registers, their contents much be saved
|
||||
before their use and restored after.
|
||||
|
||||
|
||||
9. Revision History
|
||||
|
||||
For generic code revision information, please refer to the readme_threadx_generic.txt
|
||||
file, which is included in your distribution. The following details the revision
|
||||
information associated with this specific port of ThreadX:
|
||||
|
||||
06/30/2020 Initial ThreadX 6.0.1 version for Cortex-A7 using GNU tools.
|
||||
|
||||
|
||||
Copyright(c) 1996-2020 Microsoft Corporation
|
||||
|
||||
|
||||
https://azure.com/rtos
|
||||
|
||||
373
ports_smp/cortex_a7_smp/gnu/src/tx_thread_context_restore.S
Normal file
373
ports_smp/cortex_a7_smp/gnu/src/tx_thread_context_restore.S
Normal file
@@ -0,0 +1,373 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@#include "tx_timer.h"
|
||||
@/* Include macros for modifying the wait list. */
|
||||
#include "tx_thread_smp_protection_wait_list_macros.h"
|
||||
|
||||
.arm
|
||||
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
SVC_MODE = 0xD3 @ Disable IRQ/FIQ, SVC mode
|
||||
IRQ_MODE = 0xD2 @ Disable IRQ/FIQ, IRQ mode
|
||||
#else
|
||||
SVC_MODE = 0x93 @ Disable IRQ, SVC mode
|
||||
IRQ_MODE = 0x92 @ Disable IRQ, IRQ mode
|
||||
#endif
|
||||
@
|
||||
|
||||
.global _tx_thread_system_state
|
||||
.global _tx_thread_current_ptr
|
||||
.global _tx_thread_execute_ptr
|
||||
.global _tx_timer_time_slice
|
||||
.global _tx_thread_schedule
|
||||
.global _tx_thread_preempt_disable
|
||||
.global _tx_timer_interrupt_active
|
||||
.global _tx_thread_smp_protection
|
||||
.global _tx_thread_smp_protect_wait_counts
|
||||
.global _tx_thread_smp_protect_wait_list
|
||||
.global _tx_thread_smp_protect_wait_list_lock_protect_in_force
|
||||
.global _tx_thread_smp_protect_wait_list_tail
|
||||
.global _tx_thread_smp_protect_wait_list_size
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
.global _tx_execution_isr_exit
|
||||
#endif
|
||||
|
||||
@
|
||||
@
|
||||
@/* No 16-bit Thumb mode veneer code is needed for _tx_thread_context_restore
|
||||
@ since it will never be called 16-bit mode. */
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_context_restore SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_context_restore(VOID)
|
||||
@{
|
||||
.global _tx_thread_context_restore
|
||||
.type _tx_thread_context_restore,function
|
||||
_tx_thread_context_restore:
|
||||
@
|
||||
@ /* Lockout interrupts. */
|
||||
@
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
CPSID if @ Disable IRQ and FIQ interrupts
|
||||
#else
|
||||
CPSID i @ Disable IRQ interrupts
|
||||
#endif
|
||||
|
||||
#ifdef 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:
|
||||
@
|
||||
@ /* Was the thread being preempted waiting for the lock? */
|
||||
@ if (_tx_thread_smp_protect_wait_counts[this_core] != 0)
|
||||
@ {
|
||||
@
|
||||
LDR r1, =_tx_thread_smp_protect_wait_counts @ Load waiting count list
|
||||
LDR r2, [r1, r10, LSL #2] @ Load waiting value for this core
|
||||
CMP r2, #0
|
||||
BEQ _nobody_waiting_for_lock @ Is the core waiting for the lock?
|
||||
@
|
||||
@ /* Do we not have the lock? This means the ISR never got the inter-core lock. */
|
||||
@ if (_tx_thread_smp_protection.tx_thread_smp_protect_owned != this_core)
|
||||
@ {
|
||||
@
|
||||
LDR r1, =_tx_thread_smp_protection @ Load address of protection structure
|
||||
LDR r2, [r1, #8] @ Pickup the owning core
|
||||
CMP r10, r2 @ Compare our core to the owning core
|
||||
BEQ _this_core_has_lock @ Do we have the lock?
|
||||
@
|
||||
@ /* We don't have the lock. This core should be in the list. Remove it. */
|
||||
@ _tx_thread_smp_protect_wait_list_remove(this_core);
|
||||
@
|
||||
_tx_thread_smp_protect_wait_list_remove @ Call macro to remove core from the list
|
||||
B _nobody_waiting_for_lock @ Leave
|
||||
@
|
||||
@ }
|
||||
@ else
|
||||
@ {
|
||||
@ /* We have the lock. This means the ISR got the inter-core lock, but
|
||||
@ never released it because it saw that there was someone waiting.
|
||||
@ Note this core is not in the list. */
|
||||
@
|
||||
_this_core_has_lock:
|
||||
@
|
||||
@ /* We're no longer waiting. Note that this should be zero since this happens during thread preemption. */
|
||||
@ _tx_thread_smp_protect_wait_counts[core]--;
|
||||
@
|
||||
LDR r1, =_tx_thread_smp_protect_wait_counts @ Load waiting count list
|
||||
LDR r2, [r1, r10, LSL #2] @ Load waiting value for this core
|
||||
SUB r2, r2, #1 @ Decrement waiting value. Should be zero now
|
||||
STR r2, [r1, r10, LSL #2] @ Store new waiting value
|
||||
@
|
||||
@ /* Now release the inter-core lock. */
|
||||
@
|
||||
@ /* Set protected core as invalid. */
|
||||
@ _tx_thread_smp_protection.tx_thread_smp_protect_core = 0xFFFFFFFF;
|
||||
@
|
||||
LDR r1, =_tx_thread_smp_protection @ Load address of protection structure
|
||||
MOV r2, #0xFFFFFFFF @ Build invalid value
|
||||
STR r2, [r1, #8] @ Mark the protected core as invalid
|
||||
DMB @ Ensure that accesses to shared resource have completed
|
||||
@
|
||||
@ /* Release protection. */
|
||||
@ _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 0;
|
||||
@
|
||||
MOV r2, #0 @ Build release protection value
|
||||
STR r2, [r1, #0] @ Release the protection
|
||||
DSB ISH @ To ensure update of the protection occurs before other CPUs awake
|
||||
@
|
||||
@ /* Wake up waiting processors. Note interrupts are already enabled. */
|
||||
@
|
||||
#ifdef TX_ENABLE_WFE
|
||||
SEV @ Send event to other CPUs
|
||||
#endif
|
||||
@
|
||||
@ }
|
||||
@ }
|
||||
@
|
||||
|
||||
_nobody_waiting_for_lock:
|
||||
|
||||
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
|
||||
|
||||
#ifdef TARGET_FPU_VFP
|
||||
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
|
||||
FMRX r2, FPSCR @ Pickup the FPSCR
|
||||
STR r2, [sp, #-4]! @ Save FPSCR
|
||||
VSTMDB sp!, {D16-D31} @ Save D16-D31
|
||||
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)
|
||||
STR r2, [r0, #152] @ Make this thread ready for executing again
|
||||
DMB @ Ensure that accesses to shared resource have completed
|
||||
@
|
||||
@ /* 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
|
||||
@}
|
||||
@
|
||||
|
||||
208
ports_smp/cortex_a7_smp/gnu/src/tx_thread_context_save.S
Normal file
208
ports_smp/cortex_a7_smp/gnu/src/tx_thread_context_save.S
Normal file
@@ -0,0 +1,208 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@
|
||||
@
|
||||
.global _tx_thread_system_state
|
||||
.global _tx_thread_current_ptr
|
||||
.global __tx_irq_processing_return
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
.global _tx_execution_isr_enter
|
||||
#endif
|
||||
@
|
||||
@
|
||||
@/* No 16-bit Thumb mode veneer code is needed for _tx_thread_context_save
|
||||
@ since it will never be called 16-bit mode. */
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_context_save SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_context_save(VOID)
|
||||
@{
|
||||
.global _tx_thread_context_save
|
||||
.type _tx_thread_context_save,function
|
||||
_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
|
||||
@
|
||||
#ifdef 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
|
||||
|
||||
#ifdef 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
|
||||
|
||||
#ifdef 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
|
||||
|
||||
#ifdef 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
|
||||
@
|
||||
@ }
|
||||
@}
|
||||
@
|
||||
|
||||
|
||||
105
ports_smp/cortex_a7_smp/gnu/src/tx_thread_interrupt_control.S
Normal file
105
ports_smp/cortex_a7_smp/gnu/src/tx_thread_interrupt_control.S
Normal file
@@ -0,0 +1,105 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@
|
||||
@
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
INT_MASK = 0xC0 @ Interrupt bit mask
|
||||
#else
|
||||
INT_MASK = 0x80 @ Interrupt bit mask
|
||||
#endif
|
||||
@
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_interrupt_control SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@UINT _tx_thread_interrupt_control(UINT new_posture)
|
||||
@{
|
||||
.global _tx_thread_interrupt_control
|
||||
.type _tx_thread_interrupt_control,function
|
||||
_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
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
@
|
||||
@}
|
||||
@
|
||||
|
||||
|
||||
114
ports_smp/cortex_a7_smp/gnu/src/tx_thread_interrupt_disable.S
Normal file
114
ports_smp/cortex_a7_smp/gnu/src/tx_thread_interrupt_disable.S
Normal file
@@ -0,0 +1,114 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@
|
||||
@
|
||||
@/* Define the 16-bit Thumb mode veneer for _tx_thread_interrupt_disable for
|
||||
@ applications calling this function from to 16-bit Thumb mode. */
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
.global $_tx_thread_interrupt_disable
|
||||
$_tx_thread_interrupt_disable:
|
||||
.thumb
|
||||
BX pc @ Switch to 32-bit mode
|
||||
NOP @
|
||||
.arm
|
||||
STMFD sp!, {lr} @ Save return address
|
||||
BL _tx_thread_interrupt_disable @ Call _tx_thread_interrupt_disable function
|
||||
LDMFD sp!, {lr} @ Recover saved return address
|
||||
BX lr @ Return to 16-bit caller
|
||||
@
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_interrupt_disable SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@UINT _tx_thread_interrupt_disable(void)
|
||||
@{
|
||||
.global _tx_thread_interrupt_disable
|
||||
.type _tx_thread_interrupt_disable,function
|
||||
_tx_thread_interrupt_disable:
|
||||
@
|
||||
@ /* Pickup current interrupt lockout posture. */
|
||||
@
|
||||
MRS r0, CPSR @ Pickup current CPSR
|
||||
@
|
||||
@ /* Mask interrupts. */
|
||||
@
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
CPSID if @ Disable IRQ and FIQ
|
||||
#else
|
||||
CPSID i @ Disable IRQ
|
||||
#endif
|
||||
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
@
|
||||
|
||||
|
||||
106
ports_smp/cortex_a7_smp/gnu/src/tx_thread_interrupt_restore.S
Normal file
106
ports_smp/cortex_a7_smp/gnu/src/tx_thread_interrupt_restore.S
Normal file
@@ -0,0 +1,106 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@
|
||||
@
|
||||
@/* Define the 16-bit Thumb mode veneer for _tx_thread_interrupt_restore for
|
||||
@ applications calling this function from to 16-bit Thumb mode. */
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
.global $_tx_thread_interrupt_restore
|
||||
$_tx_thread_interrupt_restore:
|
||||
.thumb
|
||||
BX pc @ Switch to 32-bit mode
|
||||
NOP @
|
||||
.arm
|
||||
STMFD sp!, {lr} @ Save return address
|
||||
BL _tx_thread_interrupt_restore @ Call _tx_thread_interrupt_restore function
|
||||
LDMFD sp!, {lr} @ Recover saved return address
|
||||
BX lr @ Return to 16-bit caller
|
||||
@
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_interrupt_restore SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@UINT _tx_thread_interrupt_restore(UINT old_posture)
|
||||
@{
|
||||
.global _tx_thread_interrupt_restore
|
||||
.type _tx_thread_interrupt_restore,function
|
||||
_tx_thread_interrupt_restore:
|
||||
@
|
||||
@ /* Apply the new interrupt posture. */
|
||||
@
|
||||
MSR CPSR_c, r0 @ Setup new CPSR
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
@
|
||||
|
||||
|
||||
116
ports_smp/cortex_a7_smp/gnu/src/tx_thread_irq_nesting_end.S
Normal file
116
ports_smp/cortex_a7_smp/gnu/src/tx_thread_irq_nesting_end.S
Normal file
@@ -0,0 +1,116 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@
|
||||
@
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
DISABLE_INTS = 0xC0 @ Disable IRQ/FIQ interrupts
|
||||
#else
|
||||
DISABLE_INTS = 0x80 @ Disable IRQ interrupts
|
||||
#endif
|
||||
MODE_MASK = 0x1F @ Mode mask
|
||||
IRQ_MODE_BITS = 0x12 @ IRQ mode bits
|
||||
@
|
||||
@
|
||||
@/* No 16-bit Thumb mode veneer code is needed for _tx_thread_irq_nesting_end
|
||||
@ since it will never be called 16-bit mode. */
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_irq_nesting_end SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_irq_nesting_end(VOID)
|
||||
@{
|
||||
.global _tx_thread_irq_nesting_end
|
||||
.type _tx_thread_irq_nesting_end,function
|
||||
_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!, {r1, lr} @ 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
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX r3 @ Return to caller
|
||||
#else
|
||||
MOV pc, r3 @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
|
||||
|
||||
110
ports_smp/cortex_a7_smp/gnu/src/tx_thread_irq_nesting_start.S
Normal file
110
ports_smp/cortex_a7_smp/gnu/src/tx_thread_irq_nesting_start.S
Normal file
@@ -0,0 +1,110 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@
|
||||
@
|
||||
IRQ_DISABLE = 0x80 @ IRQ disable bit
|
||||
MODE_MASK = 0x1F @ Mode mask
|
||||
SYS_MODE_BITS = 0x1F @ System mode bits
|
||||
@
|
||||
@
|
||||
@/* No 16-bit Thumb mode veneer code is needed for _tx_thread_irq_nesting_start
|
||||
@ since it will never be called 16-bit mode. */
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_irq_nesting_start SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_irq_nesting_start(VOID)
|
||||
@{
|
||||
.global _tx_thread_irq_nesting_start
|
||||
.type _tx_thread_irq_nesting_start,function
|
||||
_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!, {r1, lr} @ 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
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX r3 @ Return to caller
|
||||
#else
|
||||
MOV pc, r3 @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
@
|
||||
|
||||
|
||||
332
ports_smp/cortex_a7_smp/gnu/src/tx_thread_schedule.S
Normal file
332
ports_smp/cortex_a7_smp/gnu/src/tx_thread_schedule.S
Normal file
@@ -0,0 +1,332 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@#include "tx_timer.h"
|
||||
@
|
||||
@
|
||||
.global _tx_thread_execute_ptr
|
||||
.global _tx_thread_current_ptr
|
||||
.global _tx_timer_time_slice
|
||||
.global _tx_execution_thread_enter
|
||||
@
|
||||
@
|
||||
@/* Define the 16-bit Thumb mode veneer for _tx_thread_schedule for
|
||||
@ applications calling this function from to 16-bit Thumb mode. */
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
.global $_tx_thread_schedule
|
||||
.type $_tx_thread_schedule,function
|
||||
$_tx_thread_schedule:
|
||||
.thumb
|
||||
BX pc @ Switch to 32-bit mode
|
||||
NOP @
|
||||
.arm
|
||||
STMFD sp!, {lr} @ Save return address
|
||||
BL _tx_thread_schedule @ Call _tx_thread_schedule function
|
||||
LDMFD sp!, {lr} @ Recover saved return address
|
||||
BX lr @ Return to 16-bit caller
|
||||
@
|
||||
@
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_schedule SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_schedule(VOID)
|
||||
@{
|
||||
.global _tx_thread_schedule
|
||||
.type _tx_thread_schedule,function
|
||||
_tx_thread_schedule:
|
||||
@
|
||||
@ /* Enable interrupts. */
|
||||
@
|
||||
#ifdef 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. */
|
||||
@
|
||||
#ifdef 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);
|
||||
@
|
||||
@ /* Get the lock for accessing the thread's ready bit. */
|
||||
@
|
||||
MOV r2, #172 @ Build offset to the lock
|
||||
ADD r2, r0, r2 @ Get the address to the lock
|
||||
LDREX r3, [r2] @ Pickup the lock value
|
||||
CMP r3, #0 @ Check if it's available
|
||||
BNE _tx_thread_schedule @ No, lock not available
|
||||
MOV r3, #1 @ Build the lock set value
|
||||
STREX r4, r3, [r2] @ Try to get the lock
|
||||
CMP r4, #0 @ Check if we got the lock
|
||||
BNE _tx_thread_schedule @ No, another core got it first
|
||||
DMB @ Ensure write to lock completes
|
||||
@
|
||||
@ /* Now make sure the thread's ready bit is set. */
|
||||
@
|
||||
LDR r3, [r0, #152] @ Pickup the thread ready bit
|
||||
AND r4, r3, #0x8000 @ Isolate the ready bit
|
||||
CMP r4, #0 @ Is it set?
|
||||
BNE _tx_thread_ready_for_execution @ Yes, schedule the thread
|
||||
@
|
||||
@ /* The ready bit isn't set. Release the lock and jump back to the scheduler. */
|
||||
@
|
||||
MOV r3, #0 @ Build clear value
|
||||
STR r3, [r2] @ Release the lock
|
||||
DMB @ Ensure write to lock completes
|
||||
B _tx_thread_schedule @ Jump back to the scheduler
|
||||
@
|
||||
_tx_thread_ready_for_execution:
|
||||
@
|
||||
@ /* We have a thread to execute. */
|
||||
@
|
||||
@ /* Clear the ready bit and release the lock. */
|
||||
@
|
||||
BIC r3, r3, #0x8000 @ Clear ready bit
|
||||
STR r3, [r0, #152] @ Store it back in the thread control block
|
||||
DMB
|
||||
MOV r3, #0 @ Build clear value for the lock
|
||||
STR r3, [r2] @ Release the lock
|
||||
DMB
|
||||
@
|
||||
@ /* Setup the current thread pointer. */
|
||||
@ _tx_thread_current_ptr[core] = _tx_thread_execute_ptr[core];
|
||||
@
|
||||
LDR r2, =_tx_thread_current_ptr @ Pickup address of current thread
|
||||
ADD r2, r2, r12 @ Build index into the current thread array
|
||||
STR r0, [r2, #0] @ Setup current thread pointer
|
||||
@
|
||||
@ /* In the time between reading the execute pointer and assigning
|
||||
@ it to the current pointer, the execute pointer was changed by
|
||||
@ some external code. If the current pointer was still null when
|
||||
@ the external code checked if a core preempt was necessary, then
|
||||
@ it wouldn't have done it and a preemption will be missed. To
|
||||
@ handle this, undo some things and jump back to the scheduler so
|
||||
@ it can schedule the new thread. */
|
||||
@
|
||||
LDR r1, [r1, #0] @ Reload the execute pointer
|
||||
CMP r0, r1 @ Did it change?
|
||||
BEQ _execute_pointer_did_not_change @ If not, skip handling
|
||||
|
||||
MOV r1, #0 @ Build clear value
|
||||
STR r1, [r2, #0] @ Clear current thread pointer
|
||||
|
||||
LDR r1, [r0, #152] @ Pickup the ready bit
|
||||
ORR r1, r1, #0x8000 @ Set ready bit (bit 15)
|
||||
STR r1, [r0, #152] @ Make this thread ready for executing again
|
||||
DMB @ Ensure that accesses to shared resource have completed
|
||||
|
||||
B _tx_thread_schedule @ Jump back to the scheduler to schedule the new thread
|
||||
|
||||
_execute_pointer_did_not_change:
|
||||
@
|
||||
@ /* 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;
|
||||
@
|
||||
#ifdef 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
|
||||
#ifdef TARGET_FPU_VFP
|
||||
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
|
||||
VLDMIA sp!, {D16-D31} @ Recover D16-D31
|
||||
LDR r4, [sp], #4 @ Pickup FPSCR
|
||||
FMXR 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:
|
||||
|
||||
#ifdef TARGET_FPU_VFP
|
||||
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!, {D8-D15} @ Recover D8-D15
|
||||
VLDMIA sp!, {D16-D31} @ Recover D16-D31
|
||||
LDR r4, [sp], #4 @ Pickup FPSCR
|
||||
FMXR 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
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
@
|
||||
@}
|
||||
@
|
||||
#ifdef TARGET_FPU_VFP
|
||||
.global tx_thread_vfp_enable
|
||||
tx_thread_vfp_enable:
|
||||
MRS r2, CPSR @ Pickup the CPSR
|
||||
#ifdef 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
|
||||
|
||||
.global tx_thread_vfp_disable
|
||||
tx_thread_vfp_disable:
|
||||
MRS r2, CPSR @ Pickup the CPSR
|
||||
#ifdef 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
|
||||
|
||||
|
||||
86
ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_core_get.S
Normal file
86
ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_core_get.S
Normal file
@@ -0,0 +1,86 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 - Low Level SMP Support */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@#define TX_THREAD_SMP_SOURCE_CODE
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@#include "tx_timer.h" */
|
||||
@
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_smp_core_get SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
.global _tx_thread_smp_core_get
|
||||
.type _tx_thread_smp_core_get,function
|
||||
_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
|
||||
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
|
||||
|
||||
105
ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_core_preempt.S
Normal file
105
ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_core_preempt.S
Normal file
@@ -0,0 +1,105 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 - Low Level SMP Support */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@#define TX_THREAD_SMP_SOURCE_CODE
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@#include "tx_timer.h" */
|
||||
@
|
||||
@
|
||||
@/* for Cortex-A7 */
|
||||
@ IMPORT send_sgi
|
||||
.global endSGI
|
||||
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_smp_core_preempt SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
.global _tx_thread_smp_core_preempt
|
||||
.type _tx_thread_smp_core_preempt,function
|
||||
_tx_thread_smp_core_preempt:
|
||||
|
||||
STMDB sp!, {r4, lr} @ 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 sendSGI @ Make call to send inter-processor interrupt
|
||||
|
||||
LDMIA sp!, {r4, lr} @ Recover lr register and r4
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 - Low Level SMP Support */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@#define TX_THREAD_SMP_SOURCE_CODE
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@#include "tx_timer.h" */
|
||||
@
|
||||
@
|
||||
.global _tx_thread_system_state
|
||||
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_smp_current_state_get SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
.global _tx_thread_smp_current_state_get
|
||||
.type _tx_thread_smp_current_state_get,function
|
||||
_tx_thread_smp_current_state_get:
|
||||
|
||||
MRS r3, CPSR @ Pickup current CPSR
|
||||
|
||||
#ifdef 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
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 - Low Level SMP Support */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@#define TX_THREAD_SMP_SOURCE_CODE
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@#include "tx_timer.h" */
|
||||
@
|
||||
@
|
||||
.global _tx_thread_current_ptr
|
||||
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_smp_current_thread_get SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
.global _tx_thread_smp_current_thread_get
|
||||
.type _tx_thread_smp_current_thread_get,function
|
||||
_tx_thread_smp_current_thread_get:
|
||||
|
||||
MRS r3, CPSR @ Pickup current CPSR
|
||||
|
||||
#ifdef 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
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
|
||||
|
||||
142
ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_initialize_wait.S
Normal file
142
ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_initialize_wait.S
Normal file
@@ -0,0 +1,142 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 - Low Level SMP Support */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@#define TX_THREAD_SMP_SOURCE_CODE
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@#include "tx_timer.h" */
|
||||
@
|
||||
@
|
||||
.global _tx_thread_system_state
|
||||
.global _tx_thread_current_ptr
|
||||
.global _tx_thread_smp_release_cores_flag
|
||||
.global _tx_thread_schedule
|
||||
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_smp_initialize_wait SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
.global _tx_thread_smp_initialize_wait
|
||||
.type _tx_thread_smp_initialize_wait,function
|
||||
_tx_thread_smp_initialize_wait:
|
||||
|
||||
@ /* Lockout interrupts. */
|
||||
@
|
||||
#ifdef 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!
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 - Low Level SMP Support */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@#define TX_THREAD_SMP_SOURCE_CODE
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@#include "tx_timer.h" */
|
||||
@
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_smp_low_level_initialize SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
.global _tx_thread_smp_low_level_initialize
|
||||
.type _tx_thread_smp_low_level_initialize,function
|
||||
_tx_thread_smp_low_level_initialize:
|
||||
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
370
ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_protect.S
Normal file
370
ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_protect.S
Normal file
@@ -0,0 +1,370 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 - Low Level SMP Support */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@#define TX_THREAD_SMP_SOURCE_CODE
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@#include "tx_timer.h" */
|
||||
|
||||
@/* Include macros for modifying the wait list. */
|
||||
#include "tx_thread_smp_protection_wait_list_macros.h"
|
||||
|
||||
.global _tx_thread_current_ptr
|
||||
.global _tx_thread_smp_protection
|
||||
.global _tx_thread_smp_protect_wait_counts
|
||||
.global _tx_thread_smp_protect_wait_list
|
||||
.global _tx_thread_smp_protect_wait_list_lock_protect_in_force
|
||||
.global _tx_thread_smp_protect_wait_list_head
|
||||
.global _tx_thread_smp_protect_wait_list_tail
|
||||
.global _tx_thread_smp_protect_wait_list_size
|
||||
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_smp_protect SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, Microsoft Corporation */
|
||||
@/* */
|
||||
@/* DESCRIPTION */
|
||||
@/* */
|
||||
@/* This function gets protection for running inside the ThreadX */
|
||||
@/* source. This is ccomplished 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
.global _tx_thread_smp_protect
|
||||
.type _tx_thread_smp_protect,function
|
||||
_tx_thread_smp_protect:
|
||||
@VOID _tx_thread_smp_protect(VOID)
|
||||
@{
|
||||
@
|
||||
PUSH {r4-r6} @ Save registers we'll be using
|
||||
@
|
||||
@ /* Disable interrupts so we don't get preempted. */
|
||||
@
|
||||
MRS r0, CPSR @ Pickup current CPSR
|
||||
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
CPSID if @ Disable IRQ and FIQ interrupts
|
||||
ELSE
|
||||
CPSID i @ Disable IRQ interrupts
|
||||
#endif
|
||||
@
|
||||
@ /* Do we already have protection? */
|
||||
@ if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core)
|
||||
@ {
|
||||
@
|
||||
MRC p15, 0, r1, c0, c0, 5 @ Read CPU ID register
|
||||
AND r1, r1, #0x03 @ Mask off, leaving the CPU ID field
|
||||
LDR r2, =_tx_thread_smp_protection @ Build address to protection structure
|
||||
LDR r3, [r2, #8] @ Pickup the owning core
|
||||
CMP r1, r3 @ Is it not this core?
|
||||
BNE _protection_not_owned @ No, the protection is not already owned
|
||||
@
|
||||
@ /* We already have protection. */
|
||||
@
|
||||
@ /* Increment the protection count. */
|
||||
@ _tx_thread_smp_protection.tx_thread_smp_protect_count++;
|
||||
@
|
||||
LDR r3, [r2, #12] @ Pickup ownership count
|
||||
ADD r3, r3, #1 @ Increment ownership count
|
||||
STR r3, [r2, #12] @ Store ownership count
|
||||
DMB
|
||||
|
||||
B _return
|
||||
|
||||
_protection_not_owned:
|
||||
@
|
||||
@ /* Is the lock available? */
|
||||
@ if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0)
|
||||
@ {
|
||||
@
|
||||
LDREX r3, [r2, #0] @ Pickup the protection flag
|
||||
CMP r3, #0
|
||||
BNE _start_waiting @ No, protection not available
|
||||
@
|
||||
@ /* Is the list empty? */
|
||||
@ if (_tx_thread_smp_protect_wait_list_head == _tx_thread_smp_protect_wait_list_tail)
|
||||
@ {
|
||||
@
|
||||
LDR r3, =_tx_thread_smp_protect_wait_list_head
|
||||
LDR r3, [r3]
|
||||
LDR r4, =_tx_thread_smp_protect_wait_list_tail
|
||||
LDR r4, [r4]
|
||||
CMP r3, r4
|
||||
BNE _list_not_empty
|
||||
@
|
||||
@ /* Try to get the lock. */
|
||||
@ if (write_exclusive(&_tx_thread_smp_protection.tx_thread_smp_protect_in_force, 1) == SUCCESS)
|
||||
@ {
|
||||
@
|
||||
MOV r3, #1 @ Build lock value
|
||||
STREX r4, r3, [r2, #0] @ Attempt to get the protection
|
||||
CMP r4, #0
|
||||
BNE _start_waiting @ Did it fail?
|
||||
@
|
||||
@ /* We got the lock! */
|
||||
@ _tx_thread_smp_protect_lock_got();
|
||||
@
|
||||
DMB @ Ensure write to protection finishes
|
||||
_tx_thread_smp_protect_lock_got @ Call the lock got function
|
||||
|
||||
B _return
|
||||
|
||||
_list_not_empty:
|
||||
@
|
||||
@ /* Are we at the front of the list? */
|
||||
@ if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head])
|
||||
@ {
|
||||
@
|
||||
LDR r3, =_tx_thread_smp_protect_wait_list_head @ Get the address of the head
|
||||
LDR r3, [r3] @ Get the value of the head
|
||||
LDR r4, =_tx_thread_smp_protect_wait_list @ Get the address of the list
|
||||
LDR r4, [r4, r3, LSL #2] @ Get the value at the head index
|
||||
|
||||
CMP r1, r4
|
||||
BNE _start_waiting
|
||||
@
|
||||
@ /* Is the lock still available? */
|
||||
@ if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0)
|
||||
@ {
|
||||
@
|
||||
LDR r3, [r2, #0] @ Pickup the protection flag
|
||||
CMP r3, #0
|
||||
BNE _start_waiting @ No, protection not available
|
||||
@
|
||||
@ /* Get the lock. */
|
||||
@ _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1;
|
||||
@
|
||||
MOV r3, #1 @ Build lock value
|
||||
STR r3, [r2, #0] @ Store lock value
|
||||
DMB @
|
||||
@
|
||||
@ /* Got the lock. */
|
||||
@ _tx_thread_smp_protect_lock_got();
|
||||
@
|
||||
_tx_thread_smp_protect_lock_got
|
||||
@
|
||||
@ /* Remove this core from the wait list. */
|
||||
@ _tx_thread_smp_protect_remove_from_front_of_list();
|
||||
@
|
||||
_tx_thread_smp_protect_remove_from_front_of_list
|
||||
|
||||
B _return
|
||||
|
||||
_start_waiting:
|
||||
@
|
||||
@ /* For one reason or another, we didn't get the lock. */
|
||||
@
|
||||
@ /* Increment wait count. */
|
||||
@ _tx_thread_smp_protect_wait_counts[this_core]++;
|
||||
@
|
||||
LDR r3, =_tx_thread_smp_protect_wait_counts @ Load wait list counts
|
||||
LDR r4, [r3, r1, LSL #2] @ Load waiting value for this core
|
||||
ADD r4, r4, #1 @ Increment wait value
|
||||
STR r4, [r3, r1, LSL #2] @ Store new wait value
|
||||
@
|
||||
@ /* Have we not added ourselves to the list yet? */
|
||||
@ if (_tx_thread_smp_protect_wait_counts[this_core] == 1)
|
||||
@ {
|
||||
@
|
||||
CMP r4, #1
|
||||
BNE _already_in_list0 @ Is this core already waiting?
|
||||
@
|
||||
@ /* Add ourselves to the list. */
|
||||
@ _tx_thread_smp_protect_wait_list_add(this_core);
|
||||
@
|
||||
_tx_thread_smp_protect_wait_list_add @ Call macro to add ourselves to the list
|
||||
@
|
||||
@ }
|
||||
@
|
||||
_already_in_list0:
|
||||
@
|
||||
@ /* Restore interrupts. */
|
||||
@
|
||||
MSR CPSR_c, r0 @ Restore CPSR
|
||||
#ifdef TX_ENABLE_WFE
|
||||
WFE @ Go into standby
|
||||
#endif
|
||||
@
|
||||
@ /* We do this until we have the lock. */
|
||||
@ while (1)
|
||||
@ {
|
||||
@
|
||||
_try_to_get_lock:
|
||||
@
|
||||
@ /* Disable interrupts so we don't get preempted. */
|
||||
@
|
||||
#ifdef 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
|
||||
@
|
||||
@ /* Do we already have protection? */
|
||||
@ if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core)
|
||||
@ {
|
||||
@
|
||||
LDR r3, [r2, #8] @ Pickup the owning core
|
||||
CMP r3, r1 @ Is it this core?
|
||||
BEQ _got_lock_after_waiting @ Yes, the protection is already owned. This means
|
||||
@ an ISR preempted us and got protection
|
||||
@
|
||||
@ }
|
||||
@
|
||||
@ /* Are we at the front of the list? */
|
||||
@ if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head])
|
||||
@ {
|
||||
@
|
||||
LDR r3, =_tx_thread_smp_protect_wait_list_head @ Get the address of the head
|
||||
LDR r3, [r3] @ Get the value of the head
|
||||
LDR r4, =_tx_thread_smp_protect_wait_list @ Get the address of the list
|
||||
LDR r4, [r4, r3, LSL #2] @ Get the value at the head index
|
||||
|
||||
CMP r1, r4
|
||||
BNE _did_not_get_lock
|
||||
@
|
||||
@ /* Is the lock still available? */
|
||||
@ if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0)
|
||||
@ {
|
||||
@
|
||||
LDR r3, [r2, #0] @ Pickup the protection flag
|
||||
CMP r3, #0
|
||||
BNE _did_not_get_lock @ No, protection not available
|
||||
@
|
||||
@ /* Get the lock. */
|
||||
@ _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1;
|
||||
@
|
||||
MOV r3, #1 @ Build lock value
|
||||
STR r3, [r2, #0] @ Store lock value
|
||||
DMB @
|
||||
@
|
||||
@ /* Got the lock. */
|
||||
@ _tx_thread_smp_protect_lock_got();
|
||||
@
|
||||
_tx_thread_smp_protect_lock_got
|
||||
@
|
||||
@ /* Remove this core from the wait list. */
|
||||
@ _tx_thread_smp_protect_remove_from_front_of_list();
|
||||
@
|
||||
_tx_thread_smp_protect_remove_from_front_of_list
|
||||
|
||||
B _got_lock_after_waiting
|
||||
|
||||
_did_not_get_lock:
|
||||
@
|
||||
@ /* For one reason or another, we didn't get the lock. */
|
||||
@
|
||||
@ /* Were we removed from the list? This can happen if we're a thread
|
||||
@ and we got preempted. */
|
||||
@ if (_tx_thread_smp_protect_wait_counts[this_core] == 0)
|
||||
@ {
|
||||
@
|
||||
LDR r3, =_tx_thread_smp_protect_wait_counts @ Load wait list counts
|
||||
LDR r4, [r3, r1, LSL #2] @ Load waiting value for this core
|
||||
CMP r4, #0
|
||||
BNE _already_in_list1 @ Is this core already in the list?
|
||||
@
|
||||
@ /* Add ourselves to the list. */
|
||||
@ _tx_thread_smp_protect_wait_list_add(this_core);
|
||||
@
|
||||
_tx_thread_smp_protect_wait_list_add @ Call macro to add ourselves to the list
|
||||
@
|
||||
@ /* Our waiting count was also reset when we were preempted. Increment it again. */
|
||||
@ _tx_thread_smp_protect_wait_counts[this_core]++;
|
||||
@
|
||||
LDR r3, =_tx_thread_smp_protect_wait_counts @ Load wait list counts
|
||||
LDR r4, [r3, r1, LSL #2] @ Load waiting value for this core
|
||||
ADD r4, r4, #1 @ Increment wait value
|
||||
STR r4, [r3, r1, LSL #2] @ Store new wait value value
|
||||
@
|
||||
@ }
|
||||
@
|
||||
_already_in_list1:
|
||||
@
|
||||
@ /* Restore interrupts and try again. */
|
||||
@
|
||||
MSR CPSR_c, r0 @ Restore CPSR
|
||||
#ifdef TX_ENABLE_WFE
|
||||
WFE @ Go into standby
|
||||
#endif
|
||||
B _try_to_get_lock @ On waking, restart the protection attempt
|
||||
|
||||
_got_lock_after_waiting:
|
||||
@
|
||||
@ /* We're no longer waiting. */
|
||||
@ _tx_thread_smp_protect_wait_counts[this_core]--;
|
||||
@
|
||||
LDR r3, =_tx_thread_smp_protect_wait_counts @ Load waiting list
|
||||
LDR r4, [r3, r1, LSL #2] @ Load current wait value
|
||||
SUB r4, r4, #1 @ Decrement wait value
|
||||
STR r4, [r3, r1, LSL #2] @ Store new wait value value
|
||||
|
||||
@
|
||||
@ /* Restore link register and return. */
|
||||
@
|
||||
_return:
|
||||
|
||||
POP {r4-r6} @ Restore registers
|
||||
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 - Low Level SMP Support */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
|
||||
.macro _tx_thread_smp_protect_lock_got
|
||||
@
|
||||
@ /* Set the currently owned core. */
|
||||
@ _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core;
|
||||
@
|
||||
STR r1, [r2, #8] @ Store this core
|
||||
@
|
||||
@ /* Increment the protection count. */
|
||||
@ _tx_thread_smp_protection.tx_thread_smp_protect_count++;
|
||||
@
|
||||
LDR r3, [r2, #12] @ Pickup ownership count
|
||||
ADD r3, r3, #1 @ Increment ownership count
|
||||
STR r3, [r2, #12] @ Store ownership count
|
||||
DMB
|
||||
|
||||
#ifdef TX_MPCORE_DEBUG_ENABLE
|
||||
LSL r3, r1, #2 @ Build offset to array indexes
|
||||
LDR r4, =_tx_thread_current_ptr @ Pickup start of the current thread array
|
||||
ADD r4, r3, r4 @ Build index into the current thread array
|
||||
LDR r3, [r4] @ Pickup current thread for this core
|
||||
STR r3, [r2, #4] @ Save current thread pointer
|
||||
STR LR, [r2, #16] @ Save caller's return address
|
||||
STR r0, [r2, #20] @ Save CPSR
|
||||
#endif
|
||||
|
||||
.endm
|
||||
|
||||
.macro _tx_thread_smp_protect_remove_from_front_of_list
|
||||
@
|
||||
@ /* Remove ourselves from the list. */
|
||||
@ _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head++] = 0xFFFFFFFF;
|
||||
@
|
||||
MOV r3, #0xFFFFFFFF @ Build the invalid core value
|
||||
LDR r4, =_tx_thread_smp_protect_wait_list_head @ Get the address of the head
|
||||
LDR r5, [r4] @ Get the value of the head
|
||||
LDR r6, =_tx_thread_smp_protect_wait_list @ Get the address of the list
|
||||
STR r3, [r6, r5, LSL #2] @ Store the invalid core value
|
||||
ADD r5, r5, #1 @ Increment the head
|
||||
@
|
||||
@ /* Did we wrap? */
|
||||
@ if (_tx_thread_smp_protect_wait_list_head == TX_THREAD_SMP_MAX_CORES + 1)
|
||||
@ {
|
||||
@
|
||||
LDR r3, =_tx_thread_smp_protect_wait_list_size @ Load address of core list size
|
||||
LDR r3, [r3] @ Load the max cores value
|
||||
CMP r5, r3 @ Compare the head to it
|
||||
BNE _store_new_head\@ @ Are we at the max?
|
||||
@
|
||||
@ _tx_thread_smp_protect_wait_list_head = 0;
|
||||
@
|
||||
EOR r5, r5, r5 @ We're at the max. Set it to zero
|
||||
@
|
||||
@ }
|
||||
@
|
||||
_store_new_head\@:
|
||||
|
||||
STR r5, [r4] @ Store the new head
|
||||
@
|
||||
@ /* We have the lock! */
|
||||
@ return;
|
||||
@
|
||||
.endm
|
||||
|
||||
|
||||
.macro _tx_thread_smp_protect_wait_list_lock_get
|
||||
@VOID _tx_thread_smp_protect_wait_list_lock_get()
|
||||
@{
|
||||
@ /* We do this until we have the lock. */
|
||||
@ while (1)
|
||||
@ {
|
||||
@
|
||||
_tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock\@:
|
||||
@
|
||||
@ /* Is the list lock available? */
|
||||
@ _tx_thread_smp_protect_wait_list_lock_protect_in_force = load_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force);
|
||||
@
|
||||
LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force
|
||||
LDREX r2, [r1] @ Pickup the protection flag
|
||||
@
|
||||
@ if (protect_in_force == 0)
|
||||
@ {
|
||||
@
|
||||
CMP r2, #0
|
||||
BNE _tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock\@ @ No, protection not available
|
||||
@
|
||||
@ /* Try to get the list. */
|
||||
@ int status = store_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force, 1);
|
||||
@
|
||||
MOV r2, #1 @ Build lock value
|
||||
STREX r3, r2, [r1] @ Attempt to get the protection
|
||||
@
|
||||
@ if (status == SUCCESS)
|
||||
@
|
||||
CMP r3, #0
|
||||
BNE _tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock\@ @ Did it fail? If so, try again.
|
||||
@
|
||||
@ /* We have the lock! */
|
||||
@ return;
|
||||
@
|
||||
.endm
|
||||
|
||||
|
||||
.macro _tx_thread_smp_protect_wait_list_add
|
||||
@VOID _tx_thread_smp_protect_wait_list_add(UINT new_core)
|
||||
@{
|
||||
@
|
||||
@ /* We're about to modify the list, so get the list lock. */
|
||||
@ _tx_thread_smp_protect_wait_list_lock_get();
|
||||
@
|
||||
PUSH {r1-r2}
|
||||
|
||||
_tx_thread_smp_protect_wait_list_lock_get
|
||||
|
||||
POP {r1-r2}
|
||||
@
|
||||
@ /* Add this core. */
|
||||
@ _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_tail++] = new_core;
|
||||
@
|
||||
LDR r3, =_tx_thread_smp_protect_wait_list_tail @ Get the address of the tail
|
||||
LDR r4, [r3] @ Get the value of tail
|
||||
LDR r5, =_tx_thread_smp_protect_wait_list @ Get the address of the list
|
||||
STR r1, [r5, r4, LSL #2] @ Store the new core value
|
||||
ADD r4, r4, #1 @ Increment the tail
|
||||
@
|
||||
@ /* Did we wrap? */
|
||||
@ if (_tx_thread_smp_protect_wait_list_tail == _tx_thread_smp_protect_wait_list_size)
|
||||
@ {
|
||||
@
|
||||
LDR r5, =_tx_thread_smp_protect_wait_list_size @ Load max cores address
|
||||
LDR r5, [r5] @ Load max cores value
|
||||
CMP r4, r5 @ Compare max cores to tail
|
||||
BNE _tx_thread_smp_protect_wait_list_add__no_wrap\@ @ Did we wrap?
|
||||
@
|
||||
@ _tx_thread_smp_protect_wait_list_tail = 0;
|
||||
@
|
||||
MOV r4, #0
|
||||
@
|
||||
@ }
|
||||
@
|
||||
_tx_thread_smp_protect_wait_list_add__no_wrap\@:
|
||||
|
||||
STR r4, [r3] @ Store the new tail value.
|
||||
@
|
||||
@ /* Release the list lock. */
|
||||
@ _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0;
|
||||
@
|
||||
MOV r3, #0 @ Build lock value
|
||||
LDR r4, =_tx_thread_smp_protect_wait_list_lock_protect_in_force
|
||||
STR r3, [r4] @ Store the new value
|
||||
|
||||
.endm
|
||||
|
||||
|
||||
.macro _tx_thread_smp_protect_wait_list_remove
|
||||
@VOID _tx_thread_smp_protect_wait_list_remove(UINT core)
|
||||
@{
|
||||
@
|
||||
@ /* Get the core index. */
|
||||
@ UINT core_index;
|
||||
@ for (core_index = 0;; core_index++)
|
||||
@
|
||||
EOR r1, r1, r1 @ Clear for 'core_index'
|
||||
LDR r2, =_tx_thread_smp_protect_wait_list @ Get the address of the list
|
||||
@
|
||||
@ {
|
||||
@
|
||||
_tx_thread_smp_protect_wait_list_remove__check_cur_core\@:
|
||||
@
|
||||
@ /* Is this the core? */
|
||||
@ if (_tx_thread_smp_protect_wait_list[core_index] == core)
|
||||
@ {
|
||||
@ break;
|
||||
@
|
||||
LDR r3, [r2, r1, LSL #2] @ Get the value at the current index
|
||||
CMP r3, r10 @ Did we find the core?
|
||||
BEQ _tx_thread_smp_protect_wait_list_remove__found_core\@
|
||||
@
|
||||
@ }
|
||||
@
|
||||
ADD r1, r1, #1 @ Increment cur index
|
||||
B _tx_thread_smp_protect_wait_list_remove__check_cur_core\@ @ Restart the loop
|
||||
@
|
||||
@ }
|
||||
@
|
||||
_tx_thread_smp_protect_wait_list_remove__found_core\@:
|
||||
@
|
||||
@ /* We're about to modify the list. Get the lock. We need the lock because another
|
||||
@ core could be simultaneously adding (a core is simultaneously trying to get
|
||||
@ the inter-core lock) or removing (a core is simultaneously being preempted,
|
||||
@ like what is currently happening). */
|
||||
@ _tx_thread_smp_protect_wait_list_lock_get();
|
||||
@
|
||||
PUSH {r1}
|
||||
|
||||
_tx_thread_smp_protect_wait_list_lock_get
|
||||
|
||||
POP {r1}
|
||||
@
|
||||
@ /* We remove by shifting. */
|
||||
@ while (core_index != _tx_thread_smp_protect_wait_list_tail)
|
||||
@ {
|
||||
@
|
||||
_tx_thread_smp_protect_wait_list_remove__compare_index_to_tail\@:
|
||||
|
||||
LDR r2, =_tx_thread_smp_protect_wait_list_tail @ Load tail address
|
||||
LDR r2, [r2] @ Load tail value
|
||||
CMP r1, r2 @ Compare cur index and tail
|
||||
BEQ _tx_thread_smp_protect_wait_list_remove__removed\@
|
||||
@
|
||||
@ UINT next_index = core_index + 1;
|
||||
@
|
||||
MOV r2, r1 @ Move current index to next index register
|
||||
ADD r2, r2, #1 @ Add 1
|
||||
@
|
||||
@ if (next_index == _tx_thread_smp_protect_wait_list_size)
|
||||
@ {
|
||||
@
|
||||
LDR r3, =_tx_thread_smp_protect_wait_list_size
|
||||
LDR r3, [r3]
|
||||
CMP r2, r3
|
||||
BNE _tx_thread_smp_protect_wait_list_remove__next_index_no_wrap\@
|
||||
@
|
||||
@ next_index = 0;
|
||||
@
|
||||
MOV r2, #0
|
||||
@
|
||||
@ }
|
||||
@
|
||||
_tx_thread_smp_protect_wait_list_remove__next_index_no_wrap\@:
|
||||
@
|
||||
@ list_cores[core_index] = list_cores[next_index];
|
||||
@
|
||||
LDR r0, =_tx_thread_smp_protect_wait_list @ Get the address of the list
|
||||
LDR r3, [r0, r2, LSL #2] @ Get the value at the next index
|
||||
STR r3, [r0, r1, LSL #2] @ Store the value at the current index
|
||||
@
|
||||
@ core_index = next_index;
|
||||
@
|
||||
MOV r1, r2
|
||||
|
||||
B _tx_thread_smp_protect_wait_list_remove__compare_index_to_tail\@
|
||||
@
|
||||
@ }
|
||||
@
|
||||
_tx_thread_smp_protect_wait_list_remove__removed\@:
|
||||
@
|
||||
@ /* Now update the tail. */
|
||||
@ if (_tx_thread_smp_protect_wait_list_tail == 0)
|
||||
@ {
|
||||
@
|
||||
LDR r0, =_tx_thread_smp_protect_wait_list_tail @ Load tail address
|
||||
LDR r1, [r0] @ Load tail value
|
||||
CMP r1, #0
|
||||
BNE _tx_thread_smp_protect_wait_list_remove__tail_not_zero\@
|
||||
@
|
||||
@ _tx_thread_smp_protect_wait_list_tail = _tx_thread_smp_protect_wait_list_size;
|
||||
@
|
||||
LDR r2, =_tx_thread_smp_protect_wait_list_size
|
||||
LDR r1, [r2]
|
||||
@
|
||||
@ }
|
||||
@
|
||||
_tx_thread_smp_protect_wait_list_remove__tail_not_zero\@:
|
||||
@
|
||||
@ _tx_thread_smp_protect_wait_list_tail--;
|
||||
@
|
||||
SUB r1, r1, #1
|
||||
STR r1, [r0] @ Store new tail value
|
||||
@
|
||||
@ /* Release the list lock. */
|
||||
@ _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0;
|
||||
@
|
||||
MOV r0, #0 @ Build lock value
|
||||
LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force @ Load lock address
|
||||
STR r0, [r1] @ Store the new value
|
||||
@
|
||||
@ /* We're no longer waiting. Note that this should be zero since, again,
|
||||
@ this function is only called when a thread preemption is occurring. */
|
||||
@ _tx_thread_smp_protect_wait_counts[core]--;
|
||||
@
|
||||
LDR r1, =_tx_thread_smp_protect_wait_counts @ Load wait list counts
|
||||
LDR r2, [r1, r10, LSL #2] @ Load waiting value
|
||||
SUB r2, r2, #1 @ Subtract 1
|
||||
STR r2, [r1, r10, LSL #2] @ Store new waiting value
|
||||
|
||||
.endm
|
||||
|
||||
89
ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_time_get.S
Normal file
89
ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_time_get.S
Normal file
@@ -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 - Low Level SMP Support */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@#define TX_THREAD_SMP_SOURCE_CODE
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@#include "tx_timer.h" */
|
||||
@
|
||||
@
|
||||
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_smp_time_get SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
.global _tx_thread_smp_time_get
|
||||
.type _tx_thread_smp_time_get,function
|
||||
_tx_thread_smp_time_get:
|
||||
|
||||
MRC p15, 4, r0, c15, c0, 0 @ Read periph base address
|
||||
LDR r0, [r0, #0x604] @ Read count register
|
||||
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
|
||||
|
||||
142
ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_unprotect.s
Normal file
142
ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_unprotect.s
Normal file
@@ -0,0 +1,142 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 - Low Level SMP Support */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@#define TX_THREAD_SMP_SOURCE_CODE
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@#include "tx_timer.h" */
|
||||
@
|
||||
@
|
||||
.global _tx_thread_current_ptr
|
||||
.global _tx_thread_smp_protection
|
||||
.global _tx_thread_preempt_disable
|
||||
.global _tx_thread_smp_protect_wait_counts
|
||||
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_smp_unprotect SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
.global _tx_thread_smp_unprotect
|
||||
.type _tx_thread_smp_unprotect,function
|
||||
_tx_thread_smp_unprotect:
|
||||
@
|
||||
@ /* Lockout interrupts. */
|
||||
@
|
||||
#ifdef 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
|
||||
|
||||
LDR r2,=_tx_thread_smp_protection @ Build address of protection structure
|
||||
LDR r3, [r2, #8] @ Pickup the owning core
|
||||
CMP r1, r3 @ Is it this core?
|
||||
BNE _still_protected @ If this is not the owning core, protection is in force elsewhere
|
||||
|
||||
LDR r3, [r2, #12] @ Pickup the protection count
|
||||
CMP r3, #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 r3, r3, #1 @ Decrement the protection count
|
||||
STR r3, [r2, #12] @ Store the new count back
|
||||
CMP r3, #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
|
||||
|
||||
LDR r2,=_tx_thread_smp_protect_wait_counts @ Build build address of wait counts
|
||||
LDR r3, [r2, r1, LSL #2] @ Pickup wait list value
|
||||
CMP r3, #0 @ Are any entities on this core waiting?
|
||||
BNE _still_protected @ Yes, skip the protection release
|
||||
|
||||
LDR r2,=_tx_thread_smp_protection @ Build address of protection structure
|
||||
MOV r3, #0xFFFFFFFF @ Build invalid value
|
||||
STR r3, [r2, #8] @ Mark the protected core as invalid
|
||||
#ifdef TX_MPCORE_DEBUG_ENABLE
|
||||
STR LR, [r2, #16] @ Save caller's return address
|
||||
#endif
|
||||
DMB @ Ensure that accesses to shared resource have completed
|
||||
MOV r3, #0 @ Build release protection value
|
||||
STR r3, [r2, #0] @ Release the protection
|
||||
DSB @ To ensure update of the protection occurs before other CPUs awake
|
||||
#ifdef TX_ENABLE_WFE
|
||||
SEV @ Send event to other CPUs, wakes anyone waiting on the protection (using WFE)
|
||||
#endif
|
||||
|
||||
_still_protected:
|
||||
MSR CPSR_c, r0 @ Restore CPSR
|
||||
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
|
||||
174
ports_smp/cortex_a7_smp/gnu/src/tx_thread_stack_build.S
Normal file
174
ports_smp/cortex_a7_smp/gnu/src/tx_thread_stack_build.S
Normal file
@@ -0,0 +1,174 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@
|
||||
@
|
||||
SVC_MODE = 0x13 @ SVC mode
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
CPSR_MASK = 0xDF @ Mask initial CPSR, IRQ & FIQ ints enabled
|
||||
#else
|
||||
CPSR_MASK = 0x9F @ Mask initial CPSR, IRQ ints enabled
|
||||
#endif
|
||||
|
||||
THUMB_BIT = 0x20 @ Thumb-bit
|
||||
|
||||
@
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_stack_build SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
|
||||
@{
|
||||
.global _tx_thread_stack_build
|
||||
.type _tx_thread_stack_build,function
|
||||
_tx_thread_stack_build:
|
||||
@
|
||||
@
|
||||
@ /* Build a fake interrupt frame. The form of the fake interrupt stack
|
||||
@ on the Cortex-A7 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
|
||||
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
@}
|
||||
|
||||
|
||||
207
ports_smp/cortex_a7_smp/gnu/src/tx_thread_system_return.S
Normal file
207
ports_smp/cortex_a7_smp/gnu/src/tx_thread_system_return.S
Normal file
@@ -0,0 +1,207 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@#include "tx_timer.h"
|
||||
@
|
||||
@
|
||||
.global _tx_thread_current_ptr
|
||||
.global _tx_timer_time_slice
|
||||
.global _tx_thread_schedule
|
||||
.global _tx_thread_preempt_disable
|
||||
.global _tx_thread_smp_protection
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
.global _tx_execution_thread_exit
|
||||
#endif
|
||||
@
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_system_return SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_system_return(VOID)
|
||||
@{
|
||||
.global _tx_thread_system_return
|
||||
.type _tx_thread_system_return,function
|
||||
_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
|
||||
#ifdef TARGET_FPU_VFP
|
||||
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
|
||||
FMRX r4, FPSCR @ Pickup the FPSCR
|
||||
STR r4, [sp, #-4]! @ Save FPSCR
|
||||
VSTMDB sp!, {D16-D31} @ Save D16-D31
|
||||
VSTMDB sp!, {D8-D15} @ Save D8-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. */
|
||||
@
|
||||
#ifdef TX_ENABLE_FIQ_SUPPORT
|
||||
CPSID if @ Disable IRQ and FIQ interrupts
|
||||
#else
|
||||
CPSID i @ Disable IRQ interrupts
|
||||
#endif
|
||||
|
||||
#ifdef 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
|
||||
|
||||
#ifdef 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!
|
||||
@
|
||||
@}
|
||||
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_thread.h"
|
||||
@
|
||||
@
|
||||
.global _tx_thread_system_state
|
||||
.global _tx_thread_current_ptr
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
.global _tx_execution_isr_enter
|
||||
#endif
|
||||
@
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_thread_vectored_context_save SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_thread_vectored_context_save(VOID)
|
||||
@{
|
||||
.global _tx_thread_vectored_context_save
|
||||
.type _tx_thread_vectored_context_save,function
|
||||
_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]++)
|
||||
@ {
|
||||
@
|
||||
#ifdef 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
|
||||
|
||||
#ifdef 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
|
||||
|
||||
#ifdef __THUMB_INTERWORK
|
||||
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
|
||||
|
||||
#ifdef 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
|
||||
|
||||
#ifdef __THUMB_INTERWORK
|
||||
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
|
||||
|
||||
#ifdef 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
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
@
|
||||
@ }
|
||||
@}
|
||||
@
|
||||
|
||||
|
||||
231
ports_smp/cortex_a7_smp/gnu/src/tx_timer_interrupt.S
Normal file
231
ports_smp/cortex_a7_smp/gnu/src/tx_timer_interrupt.S
Normal file
@@ -0,0 +1,231 @@
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* 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 */
|
||||
@/** */
|
||||
@/**************************************************************************/
|
||||
@/**************************************************************************/
|
||||
@
|
||||
@#define TX_SOURCE_CODE
|
||||
@
|
||||
@
|
||||
@/* Include necessary system files. */
|
||||
@
|
||||
@#include "tx_api.h"
|
||||
@#include "tx_timer.h"
|
||||
@#include "tx_thread.h"
|
||||
@
|
||||
@
|
||||
@Define Assembly language external references...
|
||||
@
|
||||
.global _tx_timer_time_slice
|
||||
.global _tx_timer_system_clock
|
||||
.global _tx_timer_current_ptr
|
||||
.global _tx_timer_list_start
|
||||
.global _tx_timer_list_end
|
||||
.global _tx_timer_expired_time_slice
|
||||
.global _tx_timer_expired
|
||||
.global _tx_thread_time_slice
|
||||
.global _tx_timer_expiration_process
|
||||
.global _tx_timer_interrupt_active
|
||||
.global _tx_thread_smp_protect
|
||||
.global _tx_thread_smp_unprotect
|
||||
.global _tx_trace_isr_enter_insert
|
||||
.global _tx_trace_isr_exit_insert
|
||||
@
|
||||
@
|
||||
.arm
|
||||
.text
|
||||
.align 2
|
||||
@/**************************************************************************/
|
||||
@/* */
|
||||
@/* FUNCTION RELEASE */
|
||||
@/* */
|
||||
@/* _tx_timer_interrupt SMP/Cortex-A7/GNU */
|
||||
@/* 6.0.1 */
|
||||
@/* AUTHOR */
|
||||
@/* */
|
||||
@/* William E. Lamie, 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 */
|
||||
@/* */
|
||||
@/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
@/* */
|
||||
@/**************************************************************************/
|
||||
@VOID _tx_timer_interrupt(VOID)
|
||||
@{
|
||||
.global _tx_timer_interrupt
|
||||
.type _tx_timer_interrupt,function
|
||||
_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!, {r4, lr} @ 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!, {r4, lr} @ Recover lr register and r4
|
||||
#ifdef __THUMB_INTERWORK
|
||||
BX lr @ Return to caller
|
||||
#else
|
||||
MOV pc, lr @ Return to caller
|
||||
#endif
|
||||
@
|
||||
@}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user