Update BSP and SDK for HiFive board (#645)

* Update BSP and SDK for HiFive board

This commit also adds demo start and success/failure output messages.
This commit is contained in:
Gaurav-Aggarwal-AWS 2021-07-15 18:40:22 -07:00 committed by GitHub
parent b550e6090d
commit 2fedeff332
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
263 changed files with 36551 additions and 6623 deletions

View file

@ -1,176 +1,93 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage"> <?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<storageModule moduleId="org.eclipse.cdt.core.settings"> <cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" moduleId="org.eclipse.cdt.core.settings" name="Debug">
<cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480"> <externalSettings/>
<extensions>
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" moduleId="org.eclipse.cdt.core.settings" name="Debug"> <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<externalSettings/> <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extensions> <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> </extensions>
</storageModule>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> <storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration 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="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" name="Debug" parent="cdt.managedbuild.config.gnu.cross.exe.debug" postbuildStep="riscv64-unknown-elf-objcopy -O binary ${ProjName} ${ProjName}.bin">
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480." name="/" resourcePath="">
<toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.debug.1023181676" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.debug">
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> <option id="cdt.managedbuild.option.gnu.cross.path.2116215758" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${eclipse_home}/SiFive/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8/bin" valueType="string"/>
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.1119183919" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> <builder buildPath="${workspace_loc:/RTOSDemo}/Debug" id="cdt.managedbuild.builder.gnu.cross.1388532167" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="cdt.managedbuild.builder.gnu.cross"/>
<tool command="riscv64-unknown-elf-gcc" id="cdt.managedbuild.tool.gnu.cross.c.compiler.1469975065" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler">
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> <option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.option.optimization.level.440219377" name="Optimization Level" superClass="gnu.c.compiler.option.optimization.level" useByScannerDiscovery="false" valueType="enumerated"/>
<option id="gnu.c.compiler.option.debugging.level.1721555429" name="Debug Level" superClass="gnu.c.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.c.debugging.level.max" valueType="enumerated"/>
</extensions> <option id="gnu.c.compiler.option.dialect.std.1648189865" name="Language standard" superClass="gnu.c.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.c.compiler.dialect.default" valueType="enumerated"/>
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.c.compiler.option.include.paths.1720192082" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
</storageModule> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/FreeRTOS_Source/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/full_demo/Common_Demo_Tasks/include}&quot;"/>
<storageModule moduleId="cdtBuildSystem" version="4.0.0"> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/FreeRTOS_Source/portable/GCC/RISC-V}&quot;"/>
<configuration 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="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" name="Debug" parent="cdt.managedbuild.config.gnu.cross.exe.debug"> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/FreeRTOS_Source/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/freedom-metal}&quot;"/>
<folderInfo id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480." name="/" resourcePath=""> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/bsp/install/include}&quot;"/>
</option>
<toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.debug.1023181676" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.debug"> <option id="gnu.c.compiler.option.misc.other.257964774" name="Other flags" superClass="gnu.c.compiler.option.misc.other" useByScannerDiscovery="false" value="-c -fmessage-length=0 -march=rv32imac -mabi=ilp32 -mcmodel=medlow -ffunction-sections -fdata-sections --specs=nano.specs -Wno-unused-parameter" valueType="string"/>
<option id="gnu.c.compiler.option.warnings.extrawarn.1802410957" name="Extra warnings (-Wextra)" superClass="gnu.c.compiler.option.warnings.extrawarn" useByScannerDiscovery="false" value="true" valueType="boolean"/>
<option id="cdt.managedbuild.option.gnu.cross.path.2116215758" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${eclipse_home}/SiFive/riscv64-unknown-elf-gcc-8.3.0-2019.08.0/bin" valueType="string"/> <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1079251302" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
</tool>
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.1119183919" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/> <tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.420742449" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler">
<option id="gnu.cpp.compiler.option.optimization.level.1056760450" name="Optimization Level" superClass="gnu.cpp.compiler.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
<builder buildPath="${workspace_loc:/RTOSDemo}/Debug" id="cdt.managedbuild.builder.gnu.cross.1388532167" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="cdt.managedbuild.builder.gnu.cross"/> <option id="gnu.cpp.compiler.option.debugging.level.52506316" name="Debug Level" superClass="gnu.cpp.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
</tool>
<tool command="riscv64-unknown-elf-gcc" id="cdt.managedbuild.tool.gnu.cross.c.compiler.1469975065" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler"> <tool command="riscv64-unknown-elf-gcc" id="cdt.managedbuild.tool.gnu.cross.c.linker.558060359" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker">
<option id="gnu.c.link.option.ldflags.46965227" name="Linker flags" superClass="gnu.c.link.option.ldflags" useByScannerDiscovery="false" value="-Xlinker --gc-sections -Wl,-Map,RTOSDemo.map -T../bsp/metal.default.lds -march=rv32imac -mabi=ilp32 -mcmodel=medlow -Wl,--start-group -lc -lgcc -Wl,--end-group --specs=nano.specs" valueType="string"/>
<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.option.optimization.level.440219377" name="Optimization Level" superClass="gnu.c.compiler.option.optimization.level" useByScannerDiscovery="false" valueType="enumerated"/> <option id="gnu.c.link.option.nostart.1038463237" name="Do not use standard start files (-nostartfiles)" superClass="gnu.c.link.option.nostart" useByScannerDiscovery="false" value="true" valueType="boolean"/>
<option id="gnu.c.link.option.nostdlibs.934043026" name="No startup or default libs (-nostdlib)" superClass="gnu.c.link.option.nostdlibs" useByScannerDiscovery="false" value="false" valueType="boolean"/>
<option id="gnu.c.compiler.option.debugging.level.1721555429" name="Debug Level" superClass="gnu.c.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.c.debugging.level.max" valueType="enumerated"/> <option id="gnu.c.link.option.nodeflibs.1095611620" name="Do not use default libraries (-nodefaultlibs)" superClass="gnu.c.link.option.nodeflibs" useByScannerDiscovery="false" value="false" valueType="boolean"/>
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.c.link.option.other.875927818" name="Other options (-Xlinker [option])" superClass="gnu.c.link.option.other" useByScannerDiscovery="false" valueType="stringList">
<option id="gnu.c.compiler.option.dialect.std.1648189865" name="Language standard" superClass="gnu.c.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.c.compiler.dialect.default" valueType="enumerated"/> <listOptionValue builtIn="false" value="--defsym=__heap_max=1"/>
</option>
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.c.compiler.option.include.paths.1720192082" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath"> <inputType id="cdt.managedbuild.tool.gnu.c.linker.input.549526426" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/FreeRTOS_Source/include}&quot;"/> <additionalInput kind="additionalinput" paths="$(LIBS)"/>
</inputType>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/full_demo/Common_Demo_Tasks/include}&quot;"/> </tool>
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.linker.2105463183" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}&quot;"/> <tool id="cdt.managedbuild.tool.gnu.cross.archiver.424513814" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>
<tool command="riscv64-unknown-elf-gcc" id="cdt.managedbuild.tool.gnu.cross.assembler.825438707" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/FreeRTOS_Source/portable/GCC/RISC-V}&quot;"/> <option id="gnu.both.asm.option.flags.1946908814" name="Assembler flags" superClass="gnu.both.asm.option.flags" useByScannerDiscovery="false" value="-march=rv32imac -mabi=ilp32 -mcmodel=medlow -c -DportasmHANDLE_INTERRUPT=handle_trap -g3" valueType="string"/>
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.both.asm.option.include.paths.1448234506" name="Include paths (-I)" superClass="gnu.both.asm.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/FreeRTOS_Source/include}&quot;"/> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/FreeRTOS_Source/portable/GCC/RISC-V/chip_specific_extensions/RV32I_CLINT_no_extensions}&quot;"/>
</option>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/freedom-metal}&quot;"/> <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1723023894" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
</tool>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/bsp/install/include}&quot;"/> </toolChain>
</folderInfo>
</option> <sourceEntries>
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
<option id="gnu.c.compiler.option.misc.other.257964774" name="Other flags" superClass="gnu.c.compiler.option.misc.other" useByScannerDiscovery="false" value="-c -fmessage-length=0 -march=rv32imac -mabi=ilp32 -mcmodel=medlow -ffunction-sections -fdata-sections --specs=nano.specs -Wno-unused-parameter" valueType="string"/> </sourceEntries>
</configuration>
<option id="gnu.c.compiler.option.warnings.extrawarn.1802410957" name="Extra warnings (-Wextra)" superClass="gnu.c.compiler.option.warnings.extrawarn" useByScannerDiscovery="false" value="true" valueType="boolean"/> </storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1079251302" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> </cconfiguration>
</storageModule>
</tool> <storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="RTOSDemo.cdt.managedbuild.target.gnu.cross.exe.1669036252" name="Executable" projectType="cdt.managedbuild.target.gnu.cross.exe"/>
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.420742449" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler"> </storageModule>
<storageModule moduleId="scannerConfiguration">
<option id="gnu.cpp.compiler.option.optimization.level.1056760450" name="Optimization Level" superClass="gnu.cpp.compiler.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/> <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.debug.206163480;cdt.managedbuild.config.gnu.cross.exe.debug.206163480.;cdt.managedbuild.tool.gnu.cross.c.compiler.1469975065;cdt.managedbuild.tool.gnu.c.compiler.input.1079251302">
<option id="gnu.cpp.compiler.option.debugging.level.52506316" name="Debug Level" superClass="gnu.cpp.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/> <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
</scannerConfigBuildInfo>
</tool> </storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
<tool command="riscv64-unknown-elf-gcc" id="cdt.managedbuild.tool.gnu.cross.c.linker.558060359" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker"> <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
<storageModule moduleId="refreshScope" versionNumber="2">
<option id="gnu.c.link.option.ldflags.46965227" name="Linker flags" superClass="gnu.c.link.option.ldflags" useByScannerDiscovery="false" value="-Xlinker --gc-sections -Wl,-Map,RTOSDemo.map -T../bsp/metal.default.lds -march=rv32imac -mabi=ilp32 -mcmodel=medlow -Wl,--start-group -lc -lgcc -Wl,--end-group --specs=nano.specs" valueType="string"/> <configuration configurationName="Debug">
<resource resourceType="PROJECT" workspacePath="/RTOSDemo"/>
<option id="gnu.c.link.option.nostart.1038463237" name="Do not use standard start files (-nostartfiles)" superClass="gnu.c.link.option.nostart" useByScannerDiscovery="false" value="true" valueType="boolean"/> </configuration>
</storageModule>
<option id="gnu.c.link.option.nostdlibs.934043026" name="No startup or default libs (-nostdlib)" superClass="gnu.c.link.option.nostdlibs" useByScannerDiscovery="false" value="false" valueType="boolean"/> <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
<option id="gnu.c.link.option.nodeflibs.1095611620" name="Do not use default libraries (-nodefaultlibs)" superClass="gnu.c.link.option.nodeflibs" useByScannerDiscovery="false" value="false" valueType="boolean"/>
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.549526426" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
</inputType>
</tool>
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.linker.2105463183" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker"/>
<tool id="cdt.managedbuild.tool.gnu.cross.archiver.424513814" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>
<tool command="riscv64-unknown-elf-gcc" id="cdt.managedbuild.tool.gnu.cross.assembler.825438707" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler">
<option id="gnu.both.asm.option.flags.1946908814" name="Assembler flags" superClass="gnu.both.asm.option.flags" useByScannerDiscovery="false" value="-march=rv32imac -mabi=ilp32 -mcmodel=medlow -c -DportasmHANDLE_INTERRUPT=handle_trap -g3" valueType="string"/>
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.both.asm.option.include.paths.1448234506" name="Include paths (-I)" superClass="gnu.both.asm.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/FreeRTOS_Source/portable/GCC/RISC-V/chip_specific_extensions/RV32I_CLINT_no_extensions}&quot;"/>
</option>
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1723023894" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
</tool>
</toolChain>
</folderInfo>
<sourceEntries>
<entry 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="RTOSDemo.cdt.managedbuild.target.gnu.cross.exe.1669036252" name="Executable" projectType="cdt.managedbuild.target.gnu.cross.exe"/>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.debug.206163480;cdt.managedbuild.config.gnu.cross.exe.debug.206163480.;cdt.managedbuild.tool.gnu.cross.c.compiler.1469975065;cdt.managedbuild.tool.gnu.c.compiler.input.1079251302">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
</scannerConfigBuildInfo>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
<storageModule moduleId="refreshScope" versionNumber="2">
<configuration configurationName="Debug">
<resource resourceType="PROJECT" workspacePath="/RTOSDemo"/>
</configuration>
</storageModule>
</cproject> </cproject>

View file

@ -1,26 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project> <project>
<configuration id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" name="Debug">
<configuration id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" name="Debug"> <extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider"> <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="644150116465149599" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> <language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> </extension>
</configuration>
<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-1852838222473283" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
</extension>
</configuration>
</project> </project>

View file

@ -99,4 +99,7 @@ header file. */
void vAssertCalled( void ); void vAssertCalled( void );
#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled() #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled()
/* Map to the platform write function. */
#define configPRINT_STRING( pcString ) write( STDOUT_FILENO, pcString, strlen( pcString ) )
#endif /* FREERTOS_CONFIG_H */ #endif /* FREERTOS_CONFIG_H */

View file

@ -0,0 +1,13 @@
HiFive1 Rev B is a low-cost, Arduino-compatible development board featuring the Freedom E310. Its the best way to start prototyping and developing your RISCV applications.
This target is ideal for getting familiar with the RISC-V ISA instruction set and the freedom-metal libraries. It supports:
- 1 hart with RV32IMAC core
- 4 hardware breakpoints
- Physical Memory Protection with 8 regions
- 16 local interrupts signal that can be connected to off core complex devices
- Up to 127 PLIC interrupt signals that can be connected to off core complex devices, with 7 priority levels
- GPIO memory with 16 interrupt lines
- SPI memory with 1 interrupt line
- Serial port with 1 interrupt line
- 1 RGB LEDS

View file

@ -0,0 +1,262 @@
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
compatible = "sifive,hifive1-revb";
model = "sifive,hifive1-revb";
cpus {
#address-cells = <1>;
#size-cells = <0>;
compatible = "sifive,fe310-g000";
L6: cpu@0 {
clocks = <&hfclk>;
compatible = "sifive,rocket0", "riscv";
device_type = "cpu";
i-cache-block-size = <64>;
i-cache-sets = <128>;
i-cache-size = <16384>;
next-level-cache = <&spi0>;
reg = <0>;
riscv,isa = "rv32imac";
riscv,pmpregions = <8>;
sifive,itim = <&itim>;
sifive,dtim = <&dtim>;
status = "okay";
timebase-frequency = <16000000>;
hardware-exec-breakpoint-count = <4>;
hlic: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
};
soc {
#address-cells = <1>;
#size-cells = <1>;
#clock-cells = <1>;
compatible = "sifive,hifive1";
ranges;
hfxoscin: clock@0 {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <16000000>;
};
hfxoscout: clock@1 {
compatible = "sifive,fe310-g000,hfxosc";
clocks = <&hfxoscin>;
reg = <&prci 0x4>;
reg-names = "config";
};
hfroscin: clock@2 {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <72000000>;
};
hfroscout: clock@3 {
compatible = "sifive,fe310-g000,hfrosc";
clocks = <&hfroscin>;
reg = <&prci 0x0>;
reg-names = "config";
};
hfclk: clock@4 {
compatible = "sifive,fe310-g000,pll";
clocks = <&hfxoscout &hfroscout>;
clock-names = "pllref", "pllsel0";
reg = <&prci 0x8 &prci 0xc>;
reg-names = "config", "divider";
clock-frequency = <16000000>;
};
lfrosc: clock@5 {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <32768>;
};
psdlfaltclk: clock@6 {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <32768>;
};
lfclk: clock@7 {
compatible = "sifive,fe310-g000,lfrosc";
clocks = <&lfrosc &psdlfaltclk>;
clock-names = "lfrosc", "psdlfaltclk";
reg = <&aon 0x70 &aon 0x7C>;
reg-names = "config", "mux";
};
debug-controller@0 {
compatible = "sifive,debug-011", "riscv,debug-011";
interrupts-extended = <&hlic 65535>;
reg = <0x0 0x1000>;
reg-names = "control";
};
/* Missing: Error device */
maskrom@1000 {
reg = <0x1000 0x2000>;
reg-names = "mem";
};
otp@20000 {
reg = <0x20000 0x2000 0x10010000 0x1000>;
reg-names = "mem", "control";
};
clint: clint@2000000 {
compatible = "riscv,clint0";
interrupts-extended = <&hlic 3 &hlic 7>;
reg = <0x2000000 0x10000>;
reg-names = "control";
};
itim: itim@8000000 {
compatible = "sifive,itim0";
reg = <0x8000000 0x2000>;
reg-names = "mem";
};
plic: interrupt-controller@c000000 {
#interrupt-cells = <1>;
compatible = "riscv,plic0";
interrupt-controller;
interrupts-extended = <&hlic 11>;
reg = <0xc000000 0x4000000>;
reg-names = "control";
riscv,max-priority = <7>;
riscv,ndev = <52>;
};
aon: aon@10000000 {
compatible = "sifive,aon0";
reg = <0x10000000 0x8000>;
reg-names = "mem";
interrupt-parent = <&plic>;
interrupts = <1 2>;
clocks = <&lfclk>;
};
prci: prci@10008000 {
compatible = "sifive,fe310-g000,prci";
reg = <0x10008000 0x8000>;
reg-names = "mem";
};
gpio0: gpio@10012000 {
compatible = "sifive,gpio0";
interrupt-parent = <&plic>;
interrupts = <8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
23 24 25 26 27 28 29 30 31 32 33 34 35 36
27 28 29>;
reg = <0x10012000 0x1000>;
reg-names = "control";
};
led@0 {
compatible = "sifive,gpio-leds";
label = "LD0red";
gpios = <&gpio0 22>;
linux,default-trigger = "none";
};
led@1 {
compatible = "sifive,gpio-leds";
label = "LD0green";
gpios = <&gpio0 19>;
linux,default-trigger = "none";
};
led@2 {
compatible = "sifive,gpio-leds";
label = "LD0blue";
gpios = <&gpio0 21>;
linux,default-trigger = "none";
};
uart0: serial@10013000 {
compatible = "sifive,uart0";
interrupt-parent = <&plic>;
interrupts = <3>;
reg = <0x10013000 0x1000>;
reg-names = "control";
clocks = <&hfclk>;
pinmux = <&gpio0 0x0 0x30000>;
};
spi0: spi@10014000 {
compatible = "sifive,spi0";
interrupt-parent = <&plic>;
interrupts = <5>;
reg = <0x10014000 0x1000 0x20000000 0x7A120>;
reg-names = "control", "mem";
clocks = <&hfclk>;
pinmux = <&gpio0 0x0 0x0>;
#address-cells = <1>;
#size-cells = <1>;
flash@0 {
compatible = "jedec,spi-nor";
reg = <0x20000000 0x424000>;
};
};
pwm0: pwm@10015000 {
compatible = "sifive,pwm0";
sifive,comparator-widthbits = <8>;
sifive,ncomparators = <4>;
interrupt-parent = <&plic>;
interrupts = <40 41 42 43>;
reg = <0x10015000 0x1000>;
reg-names = "control";
clocks = <&hfclk>;
pinmux = <&gpio0 0x0F 0x0F>;
};
i2c0: i2c@10016000 {
compatible = "sifive,i2c0";
interrupt-parent = <&plic>;
interrupts = <52>;
reg = <0x10016000 0x1000>;
reg-names = "control";
clocks = <&hfclk>;
pinmux = <&gpio0 0x0 0x3000>;
};
uart1: serial@10023000 {
compatible = "sifive,uart0";
interrupt-parent = <&plic>;
interrupts = <4>;
reg = <0x10023000 0x1000>;
reg-names = "control";
clocks = <&hfclk>;
pinmux = <&gpio0 0x0 0x840000>;
};
spi1: spi@10024000 {
compatible = "sifive,spi0";
interrupt-parent = <&plic>;
interrupts = <6>;
reg = <0x10024000 0x1000>;
reg-names = "control";
clocks = <&hfclk>;
pinmux = <&gpio0 0x0 0x0003C>;
};
pwm1: pwm@10025000 {
compatible = "sifive,pwm0";
sifive,comparator-widthbits = <16>;
sifive,ncomparators = <4>;
interrupt-parent = <&plic>;
interrupts = <44 45 46 47>;
reg = <0x10025000 0x1000>;
reg-names = "control";
clocks = <&hfclk>;
pinmux = <&gpio0 0x780000 0x780000>;
};
spi2: spi@10034000 {
compatible = "sifive,spi0";
interrupt-parent = <&plic>;
interrupts = <7>;
reg = <0x10034000 0x1000>;
reg-names = "control";
clocks = <&hfclk>;
pinmux = <&gpio0 0x0 0xFC000000>;
};
pwm2: pwm@10035000 {
compatible = "sifive,pwm0";
sifive,comparator-widthbits = <16>;
sifive,ncomparators = <4>;
interrupt-parent = <&plic>;
interrupts = <48 49 50 51>;
reg = <0x10035000 0x1000>;
reg-names = "control";
clocks = <&hfclk>;
pinmux = <&gpio0 0x3C00 0x3C00>;
};
dtim: dtim@80000000 {
compatible = "sifive,dtim0";
reg = <0x80000000 0x4000>;
reg-names = "mem";
};
};
};

View file

@ -1,209 +1,10 @@
/dts-v1/; /include/ "core.dts"
/ { / {
#address-cells = <1>; chosen {
#size-cells = <1>; metal,entry = <&spi0 1 65536>;
compatible = "sifive,hifive1-revb"; metal,boothart = <&L6>;
model = "sifive,hifive1-revb"; stdout-path = "/soc/serial@10013000:115200";
metal,itim = <&itim 0 0>;
chosen { metal,ram = <&dtim 0 0>;
stdout-path = "/soc/serial@10013000:115200"; };
metal,entry = <&spi0 0x10000>;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
compatible = "sifive,fe310-g000";
L6: cpu@0 {
clocks = <&hfclk>;
compatible = "sifive,rocket0", "riscv";
device_type = "cpu";
i-cache-block-size = <64>;
i-cache-sets = <128>;
i-cache-size = <16384>;
next-level-cache = <&spi0>;
reg = <0>;
riscv,isa = "rv32imac";
riscv,pmpregions = <8>;
sifive,dtim = <&dtim>;
status = "okay";
timebase-frequency = <1000000>;
hardware-exec-breakpoint-count = <4>;
hlic: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
};
soc {
#address-cells = <1>;
#size-cells = <1>;
#clock-cells = <1>;
compatible = "sifive,hifive1";
ranges;
hfxoscin: clock@0 {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <16000000>;
};
hfxoscout: clock@1 {
compatible = "sifive,fe310-g000,hfxosc";
clocks = <&hfxoscin>;
reg = <&prci 0x4>;
reg-names = "config";
};
hfroscin: clock@2 {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <72000000>;
};
hfroscout: clock@3 {
compatible = "sifive,fe310-g000,hfrosc";
clocks = <&hfroscin>;
reg = <&prci 0x0>;
reg-names = "config";
};
hfclk: clock@4 {
compatible = "sifive,fe310-g000,pll";
clocks = <&hfxoscout &hfroscout>;
clock-names = "pllref", "pllsel0";
reg = <&prci 0x8 &prci 0xc>;
reg-names = "config", "divider";
clock-frequency = <16000000>;
};
lfroscin: clock@5 {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <32000000>;
};
lfclk: clock@6 {
compatible = "sifive,fe310-g000,lfrosc";
clocks = <&lfroscin>;
reg = <&aon 0x70>;
reg-names = "config";
};
aon: aon@10000000 {
compatible = "sifive,aon0";
reg = <0x10000000 0x8000>;
reg-names = "mem";
};
prci: prci@10008000 {
compatible = "sifive,fe310-g000,prci";
reg = <0x10008000 0x8000>;
reg-names = "mem";
};
clint: clint@2000000 {
compatible = "riscv,clint0";
interrupts-extended = <&hlic 3 &hlic 7>;
reg = <0x2000000 0x10000>;
reg-names = "control";
};
local-external-interrupts-0 {
compatible = "sifive,local-external-interrupts0";
interrupt-parent = <&hlic>;
interrupts = <16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31>;
};
plic: interrupt-controller@c000000 {
#interrupt-cells = <1>;
compatible = "riscv,plic0";
interrupt-controller;
interrupts-extended = <&hlic 11>;
reg = <0xc000000 0x4000000>;
reg-names = "control";
riscv,max-priority = <7>;
riscv,ndev = <26>;
};
global-external-interrupts {
compatile = "sifive,global-external-interrupts0";
interrupt-parent = <&plic>;
interrupts = <1 2 3 4>;
};
debug-controller@0 {
compatible = "sifive,debug-011", "riscv,debug-011";
interrupts-extended = <&hlic 65535>;
reg = <0x0 0x100>;
reg-names = "control";
};
maskrom@1000 {
reg = <0x1000 0x2000>;
reg-names = "mem";
};
otp@20000 {
reg = <0x20000 0x2000 0x10010000 0x1000>;
reg-names = "mem", "control";
};
dtim: dtim@80000000 {
compatible = "sifive,dtim0";
reg = <0x80000000 0x4000>;
reg-names = "mem";
};
pwm@10015000 {
compatible = "sifive,pwm0";
interrupt-parent = <&plic>;
interrupts = <23 24 25 26>;
reg = <0x10015000 0x1000>;
reg-names = "control";
};
gpio0: gpio@10012000 {
compatible = "sifive,gpio0";
interrupt-parent = <&plic>;
interrupts = <7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22>;
reg = <0x10012000 0x1000>;
reg-names = "control";
};
uart0: serial@10013000 {
compatible = "sifive,uart0";
interrupt-parent = <&plic>;
interrupts = <5>;
reg = <0x10013000 0x1000>;
reg-names = "control";
clocks = <&hfclk>;
pinmux = <&gpio0 0x30000 0x30000>;
};
spi0: spi@10014000 {
compatible = "sifive,spi0";
interrupt-parent = <&plic>;
interrupts = <6>;
reg = <0x10014000 0x1000 0x20000000 0x7A120>;
reg-names = "control", "mem";
clocks = <&hfclk>;
pinmux = <&gpio0 0x0003C 0x0003C>;
};
i2c0: i2c@10016000 {
compatible = "sifive,i2c0";
interrupt-parent = <&plic>;
interrupts = <52>;
reg = <0x10016000 0x1000>;
reg-names = "control";
};
led@0red {
compatible = "sifive,gpio-leds";
label = "LD0red";
gpios = <&gpio0 22>;
linux,default-trigger = "none";
};
led@0green {
compatible = "sifive,gpio-leds";
label = "LD0green";
gpios = <&gpio0 19>;
linux,default-trigger = "none";
};
led@0blue {
compatible = "sifive,gpio-leds";
label = "LD0blue";
gpios = <&gpio0 21>;
linux,default-trigger = "none";
};
};
}; };

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,259 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__ATOMIC_H
#define METAL__ATOMIC_H
#include <stdint.h>
#include <metal/compiler.h>
typedef volatile int32_t metal_atomic_t;
#define METAL_ATOMIC_DECLARE(name) \
__attribute((section(".data.atomics"))) metal_atomic_t name
#define _METAL_STORE_AMO_ACCESS_FAULT 7
/* This macro stores the memory address in mtval like a normal store/amo access
* fault, triggers a trap, and then if execution returns, returns 0 as an
* arbitrary choice */
#define _METAL_TRAP_AMO_ACCESS(addr) \
__asm__("csrw mtval, %[atomic]" ::[atomic] "r"(a)); \
_metal_trap(_METAL_STORE_AMO_ACCESS_FAULT); \
return 0;
/*!
* @brief Check if the platform supports atomic operations
*
* @return 1 if atomic operations are supported, 0 if not
*/
__inline__ int32_t metal_atomic_available(void) {
#ifdef __riscv_atomic
return 1;
#else
return 0;
#endif
}
/*!
* @brief Atomically increment a metal_atomic_t and return its old value
*
* If atomics are not supported on the platform, this function will trap with
* a Store/AMO access fault.
*
* @param a The pointer to the value to increment
* @param increment the amount to increment the value
*
* @return The previous value of the metal_atomic_t
*/
__inline__ int32_t metal_atomic_add(metal_atomic_t *a, int32_t increment) {
#ifdef __riscv_atomic
int32_t old;
__asm__ volatile("amoadd.w %[old], %[increment], (%[atomic])"
: [old] "=r"(old)
: [increment] "r"(increment), [atomic] "r"(a)
: "memory");
return old;
#else
_METAL_TRAP_AMO_ACCESS(a);
#endif
}
/*!
* @brief Atomically bitwise-AND a metal_atomic_t and return its old value
*
* If atomics are not supported on the platform, this function will trap with
* a Store/AMO access fault.
*
* @param a The pointer to the value to bitwise-AND
* @param mask the bitmask to AND
*
* @return The previous value of the metal_atomic_t
*/
__inline__ int32_t metal_atomic_and(metal_atomic_t *a, int32_t mask) {
#ifdef __riscv_atomic
int32_t old;
__asm__ volatile("amoand.w %[old], %[mask], (%[atomic])"
: [old] "=r"(old)
: [mask] "r"(mask), [atomic] "r"(a)
: "memory");
return old;
#else
_METAL_TRAP_AMO_ACCESS(a);
#endif
}
/*!
* @brief Atomically bitwise-OR a metal_atomic_t and return its old value
*
* If atomics are not supported on the platform, this function will trap with
* a Store/AMO access fault.
*
* @param a The pointer to the value to bitwise-OR
* @param mask the bitmask to OR
*
* @return The previous value of the metal_atomic_t
*/
__inline__ int32_t metal_atomic_or(metal_atomic_t *a, int32_t mask) {
#ifdef __riscv_atomic
int32_t old;
__asm__ volatile("amoor.w %[old], %[mask], (%[atomic])"
: [old] "=r"(old)
: [mask] "r"(mask), [atomic] "r"(a)
: "memory");
return old;
#else
_METAL_TRAP_AMO_ACCESS(a);
#endif
}
/*!
* @brief Atomically swap a metal_atomic_t and return its old value
*
* If atomics are not supported on the platform, this function will trap with
* a Store/AMO access fault.
*
* @param a The pointer to the value to swap
* @param new_value the value to store in the metal_atomic_t
*
* @return The previous value of the metal_atomic_t
*/
__inline__ int32_t metal_atomic_swap(metal_atomic_t *a, int32_t new_value) {
#ifdef __riscv_atomic
int32_t old;
__asm__ volatile("amoswap.w %[old], %[newval], (%[atomic])"
: [old] "=r"(old)
: [newval] "r"(new_value), [atomic] "r"(a)
: "memory");
return old;
#else
_METAL_TRAP_AMO_ACCESS(a);
#endif
}
/*!
* @brief Atomically bitwise-XOR a metal_atomic_t and return its old value
*
* If atomics are not supported on the platform, this function will trap with
* a Store/AMO access fault.
*
* @param a The pointer to the value to bitwise-XOR
* @param mask the bitmask to XOR
*
* @return The previous value of the metal_atomic_t
*/
__inline__ int32_t metal_atomic_xor(metal_atomic_t *a, int32_t mask) {
#ifdef __riscv_atomic
int32_t old;
__asm__ volatile("amoxor.w %[old], %[mask], (%[atomic])"
: [old] "=r"(old)
: [mask] "r"(mask), [atomic] "r"(a)
: "memory");
return old;
#else
_METAL_TRAP_AMO_ACCESS(a);
#endif
}
/*!
* @brief Atomically set the value of a memory location to the greater of
* its current value or a value to compare it with.
*
* If atomics are not supported on the platform, this function will trap with
* a Store/AMO access fault.
*
* @param a The pointer to the value to swap
* @param compare the value to compare with the value in memory
*
* @return The previous value of the metal_atomic_t
*/
__inline__ int32_t metal_atomic_max(metal_atomic_t *a, int32_t compare) {
#ifdef __riscv_atomic
int32_t old;
__asm__ volatile("amomax.w %[old], %[compare], (%[atomic])"
: [old] "=r"(old)
: [compare] "r"(compare), [atomic] "r"(a)
: "memory");
return old;
#else
_METAL_TRAP_AMO_ACCESS(a);
#endif
}
/*!
* @brief Atomically set the value of a memory location to the (unsigned)
* greater of its current value or a value to compare it with.
*
* If atomics are not supported on the platform, this function will trap with
* a Store/AMO access fault.
*
* @param a The pointer to the value to swap
* @param compare the value to compare with the value in memory
*
* @return The previous value of the metal_atomic_t
*/
__inline__ uint32_t metal_atomic_max_u(metal_atomic_t *a, uint32_t compare) {
#ifdef __riscv_atomic
int32_t old;
__asm__ volatile("amomaxu.w %[old], %[compare], (%[atomic])"
: [old] "=r"(old)
: [compare] "r"(compare), [atomic] "r"(a)
: "memory");
return old;
#else
_METAL_TRAP_AMO_ACCESS(a);
#endif
}
/*!
* @brief Atomically set the value of a memory location to the lesser of
* its current value or a value to compare it with.
*
* If atomics are not supported on the platform, this function will trap with
* a Store/AMO access fault.
*
* @param a The pointer to the value to swap
* @param compare the value to compare with the value in memory
*
* @return The previous value of the metal_atomic_t
*/
__inline__ int32_t metal_atomic_min(metal_atomic_t *a, int32_t compare) {
#ifdef __riscv_atomic
int32_t old;
__asm__ volatile("amomin.w %[old], %[compare], (%[atomic])"
: [old] "=r"(old)
: [compare] "r"(compare), [atomic] "r"(a)
: "memory");
return old;
#else
_METAL_TRAP_AMO_ACCESS(a);
#endif
}
/*!
* @brief Atomically set the value of a memory location to the (unsigned) lesser
* of its current value or a value to compare it with.
*
* If atomics are not supported on the platform, this function will trap with
* a Store/AMO access fault.
*
* @param a The pointer to the value to swap
* @param compare the value to compare with the value in memory
*
* @return The previous value of the metal_atomic_t
*/
__inline__ uint32_t metal_atomic_min_u(metal_atomic_t *a, uint32_t compare) {
#ifdef __riscv_atomic
int32_t old;
__asm__ volatile("amominu.w %[old], %[compare], (%[atomic])"
: [old] "=r"(old)
: [compare] "r"(compare), [atomic] "r"(a)
: "memory");
return old;
#else
_METAL_TRAP_AMO_ACCESS(a);
#endif
}
#endif /* METAL__ATOMIC_H */

View file

@ -15,7 +15,8 @@ struct metal_button;
struct metal_button_vtable { struct metal_button_vtable {
int (*button_exist)(struct metal_button *button, char *label); int (*button_exist)(struct metal_button *button, char *label);
struct metal_interrupt* (*interrupt_controller)(struct metal_button *button); struct metal_interrupt *(*interrupt_controller)(
struct metal_button *button);
int (*get_interrupt_id)(struct metal_button *button); int (*get_interrupt_id)(struct metal_button *button);
}; };
@ -35,8 +36,7 @@ struct metal_button {
* @param label The DeviceTree label for the button * @param label The DeviceTree label for the button
* @return A handle for the button * @return A handle for the button
*/ */
struct metal_button* metal_button_get(char *label); struct metal_button *metal_button_get(char *label);
/*! /*!
* @brief Get the interrupt controller for a button * @brief Get the interrupt controller for a button
@ -45,8 +45,10 @@ struct metal_button* metal_button_get(char *label);
* @return A pointer to the interrupt controller responsible for handling * @return A pointer to the interrupt controller responsible for handling
* button interrupts. * button interrupts.
*/ */
inline struct metal_interrupt* __inline__ struct metal_interrupt *
metal_button_interrupt_controller(struct metal_button *button) { return button->vtable->interrupt_controller(button); } metal_button_interrupt_controller(struct metal_button *button) {
return button->vtable->interrupt_controller(button);
}
/*! /*!
* @brief Get the interrupt id for a button * @brief Get the interrupt id for a button
@ -54,6 +56,8 @@ inline struct metal_interrupt*
* @param button The handle for the button * @param button The handle for the button
* @return The interrupt id corresponding to a button. * @return The interrupt id corresponding to a button.
*/ */
inline int metal_button_get_interrupt_id(struct metal_button *button) { return button->vtable->get_interrupt_id(button); } __inline__ int metal_button_get_interrupt_id(struct metal_button *button) {
return button->vtable->get_interrupt_id(button);
}
#endif #endif

View file

@ -1,4 +1,4 @@
/* Copyright 2018 SiFive, Inc */ /* Copyright 2020 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */ /* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__CACHE_H #ifndef METAL__CACHE_H
@ -9,40 +9,58 @@
* *
* @brief API for configuring caches * @brief API for configuring caches
*/ */
#include <stdint.h>
struct metal_cache;
struct __metal_cache_vtable {
void (*init)(struct metal_cache *cache, int ways);
int (*get_enabled_ways)(struct metal_cache *cache);
int (*set_enabled_ways)(struct metal_cache *cache, int ways);
};
/*! /*!
* @brief a handle for a cache * @brief a handle for a cache
* Note: To be deprecated in next release.
*/ */
struct metal_cache { struct metal_cache {
const struct __metal_cache_vtable *vtable; uint8_t __no_empty_structs;
}; };
/*!
* @brief Initialize L2 cache controller.
* Enables all available cache ways.
* @param None
* @return 0 If no error
*/
int metal_l2cache_init(void);
/*!
* @brief Get the current number of enabled L2 cache ways
* @param None
* @return The current number of enabled L2 cache ways
*/
int metal_l2cache_get_enabled_ways(void);
/*!
* @brief Enable the requested number of L2 cache ways
* @param ways Number of ways to enable
* @return 0 if the ways are successfully enabled
*/
int metal_l2cache_set_enabled_ways(int ways);
/*! /*!
* @brief Initialize a cache * @brief Initialize a cache
* @param cache The handle for the cache to initialize * @param cache The handle for the cache to initialize
* @param ways The number of ways to enable * @param ways The number of ways to enable
* *
* Initializes a cache with the requested number of ways enabled. * Initializes a cache with the requested number of ways enabled.
* Note: API to be deprecated in next release.
*/ */
inline void metal_cache_init(struct metal_cache *cache, int ways) { __inline__ void metal_cache_init(struct metal_cache *cache, int ways) {
return cache->vtable->init(cache, ways); metal_l2cache_init();
} }
/*! /*!
* @brief Get the current number of enabled cache ways * @brief Get the current number of enabled cache ways
* @param cache The handle for the cache * @param cache The handle for the cache
* @return The current number of enabled cache ways * @return The current number of enabled cache ways
* Note: API to be deprecated in next release.
*/ */
inline int metal_cache_get_enabled_ways(struct metal_cache *cache) { __inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache) {
return cache->vtable->get_enabled_ways(cache); return metal_l2cache_get_enabled_ways();
} }
/*! /*!
@ -50,9 +68,41 @@ inline int metal_cache_get_enabled_ways(struct metal_cache *cache) {
* @param cache The handle for the cache * @param cache The handle for the cache
* @param ways The number of ways to enabled * @param ways The number of ways to enabled
* @return 0 if the ways are successfully enabled * @return 0 if the ways are successfully enabled
* Note: API to be deprecated in next release.
*/ */
inline int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways) { __inline__ int metal_cache_set_enabled_ways(struct metal_cache *cache,
return cache->vtable->set_enabled_ways(cache, ways); int ways) {
return metal_l2cache_set_enabled_ways(ways);
} }
/*!
* @brief Check if dcache is supported on the core
* @param hartid The core to check
* @return 1 if dcache is present
*/
int metal_dcache_l1_available(int hartid);
/*!
* @brief Flush dcache for L1 on the requested core with write back
* @param hartid The core to flush
* @param address The virtual address of cacheline to invalidate
* @return None
*/
void metal_dcache_l1_flush(int hartid, uintptr_t address);
/*!
* @brief Discard dcache for L1 on the requested core with no write back
* @param hartid The core to discard
* @param address The virtual address of cacheline to invalidate
* @return None
*/
void metal_dcache_l1_discard(int hartid, uintptr_t address);
/*!
* @brief Check if icache is supported on the core
* @param hartid The core to check
* @return 1 if icache is present
*/
int metal_icache_l1_available(int hartid);
#endif #endif

View file

@ -8,7 +8,8 @@
* @file clock.h * @file clock.h
* @brief API for manipulating clock sources * @brief API for manipulating clock sources
* *
* The clock interface allows for controlling the rate of various clocks in the system. * The clock interface allows for controlling the rate of various clocks in the
* system.
*/ */
struct metal_clock; struct metal_clock;
@ -22,37 +23,82 @@ struct __metal_clock_vtable {
}; };
/*! /*!
* @brief Function signature of clock pre-rate change callbacks * @brief Function signature of clock rate change callbacks
*/ */
typedef void (*metal_clock_pre_rate_change_callback)(void *priv); typedef void (*metal_clock_rate_change_callback)(void *priv);
struct _metal_clock_callback_t;
struct _metal_clock_callback_t {
/* The callback function */
metal_clock_rate_change_callback callback;
/* Private data for the callback function */
void *priv;
struct _metal_clock_callback_t *_next;
};
/*! /*!
* @brief Function signature of clock post-rate change callbacks * @brief Type for the linked list of callbacks for clock rate changes
*/ */
typedef void (*metal_clock_post_rate_change_callback)(void *priv); typedef struct _metal_clock_callback_t metal_clock_callback;
/*!
* @brief Call all callbacks in the linked list, if any are registered
*/
__inline__ void
_metal_clock_call_all_callbacks(const metal_clock_callback *const list) {
const metal_clock_callback *current = list;
while (current) {
current->callback(current->priv);
current = current->_next;
}
}
/*!
* @brief Append a callback to the linked list and return the head of the list
*/
__inline__ metal_clock_callback *
_metal_clock_append_to_callbacks(metal_clock_callback *list,
metal_clock_callback *const cb) {
cb->_next = NULL;
if (!list) {
return cb;
}
metal_clock_callback *current = list;
while ((current->_next) != NULL) {
current = current->_next;
}
current->_next = cb;
return list;
}
/*! /*!
* @struct metal_clock * @struct metal_clock
* @brief The handle for a clock * @brief The handle for a clock
* *
* Clocks are defined as a pointer to a `struct metal_clock`, the contents of which * Clocks are defined as a pointer to a `struct metal_clock`, the contents of
* are implementation defined. Users of the clock interface must call functions * which are implementation defined. Users of the clock interface must call
* which accept a `struct metal_clock *` as an argument to interract with the clock. * functions which accept a `struct metal_clock *` as an argument to interract
* with the clock.
* *
* Note that no mechanism for obtaining a pointer to a `struct metal_clock` has been * Note that no mechanism for obtaining a pointer to a `struct metal_clock` has
* defined, making it impossible to call any of these functions without invoking * been defined, making it impossible to call any of these functions without
* implementation-defined behavior. * invoking implementation-defined behavior.
*/ */
struct metal_clock { struct metal_clock {
const struct __metal_clock_vtable *vtable; const struct __metal_clock_vtable *vtable;
/* Pre-rate change callback */ /* Pre-rate change callback linked list */
metal_clock_pre_rate_change_callback _pre_rate_change_callback; metal_clock_callback *_pre_rate_change_callback;
void *_pre_rate_change_callback_priv;
/* Post-rate change callback */ /* Post-rate change callback linked list */
metal_clock_post_rate_change_callback _post_rate_change_callback; metal_clock_callback *_post_rate_change_callback;
void *_post_rate_change_callback_priv;
}; };
/*! /*!
@ -61,7 +107,9 @@ struct metal_clock {
* @param clk The handle for the clock * @param clk The handle for the clock
* @return The current rate of the clock in Hz * @return The current rate of the clock in Hz
*/ */
inline long metal_clock_get_rate_hz(const struct metal_clock *clk) { return clk->vtable->get_rate_hz(clk); } __inline__ long metal_clock_get_rate_hz(const struct metal_clock *clk) {
return clk->vtable->get_rate_hz(clk);
}
/*! /*!
* @brief Set the current rate of a clock * @brief Set the current rate of a clock
@ -74,18 +122,15 @@ inline long metal_clock_get_rate_hz(const struct metal_clock *clk) { return clk-
* to the given rate in Hz. Returns the actual value that's been selected, which * to the given rate in Hz. Returns the actual value that's been selected, which
* could be anything! * could be anything!
* *
* Prior to and after the rate change of the clock, this will call the registered * Prior to and after the rate change of the clock, this will call the
* pre- and post-rate change callbacks. * registered pre- and post-rate change callbacks.
*/ */
inline long metal_clock_set_rate_hz(struct metal_clock *clk, long hz) __inline__ long metal_clock_set_rate_hz(struct metal_clock *clk, long hz) {
{ _metal_clock_call_all_callbacks(clk->_pre_rate_change_callback);
if(clk->_pre_rate_change_callback != NULL)
clk->_pre_rate_change_callback(clk->_pre_rate_change_callback_priv);
long out = clk->vtable->set_rate_hz(clk, hz); long out = clk->vtable->set_rate_hz(clk, hz);
if (clk->_post_rate_change_callback != NULL) _metal_clock_call_all_callbacks(clk->_post_rate_change_callback);
clk->_post_rate_change_callback(clk->_post_rate_change_callback_priv);
return out; return out;
} }
@ -95,12 +140,12 @@ inline long metal_clock_set_rate_hz(struct metal_clock *clk, long hz)
* *
* @param clk The handle for the clock * @param clk The handle for the clock
* @param cb The callback to be registered * @param cb The callback to be registered
* @param priv Private data for the callback handler
*/ */
inline void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_pre_rate_change_callback cb, void *priv) __inline__ void
{ metal_clock_register_pre_rate_change_callback(struct metal_clock *clk,
clk->_pre_rate_change_callback = cb; metal_clock_callback *cb) {
clk->_pre_rate_change_callback_priv = priv; clk->_pre_rate_change_callback =
_metal_clock_append_to_callbacks(clk->_pre_rate_change_callback, cb);
} }
/*! /*!
@ -108,12 +153,12 @@ inline void metal_clock_register_pre_rate_change_callback(struct metal_clock *cl
* *
* @param clk The handle for the clock * @param clk The handle for the clock
* @param cb The callback to be registered * @param cb The callback to be registered
* @param priv Private data for the callback handler
*/ */
inline void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_post_rate_change_callback cb, void *priv) __inline__ void
{ metal_clock_register_post_rate_change_callback(struct metal_clock *clk,
clk->_post_rate_change_callback = cb; metal_clock_callback *cb) {
clk->_post_rate_change_callback_priv = priv; clk->_post_rate_change_callback =
_metal_clock_append_to_callbacks(clk->_post_rate_change_callback, cb);
} }
#endif #endif

View file

@ -4,18 +4,19 @@
#ifndef METAL__COMPILER_H #ifndef METAL__COMPILER_H
#define METAL__COMPILER_H #define METAL__COMPILER_H
#define __METAL_DECLARE_VTABLE(type) \ #define __METAL_DECLARE_VTABLE(type) extern const struct type type;
extern const struct type type;
#define __METAL_DEFINE_VTABLE(type) \ #define __METAL_DEFINE_VTABLE(type) const struct type type
const struct type type
#define __METAL_GET_FIELD(reg, mask) \ #define __METAL_GET_FIELD(reg, mask) \
(((reg) & (mask)) / ((mask) & ~((mask) << 1))) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
/* Set field with mask for a given value */ /* Set field with mask for a given value */
#define __METAL_SET_FIELD(reg, mask, val) \ #define __METAL_SET_FIELD(reg, mask, val) \
(((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
#define __METAL_MIN(a, b) ((a) < (b) ? (a) : (b))
#define __METAL_MAX(a, b) ((a) > (b) ? (a) : (b))
void _metal_trap(int ecode); void _metal_trap(int ecode);

View file

@ -9,33 +9,35 @@
#ifndef METAL__CPU_H #ifndef METAL__CPU_H
#define METAL__CPU_H #define METAL__CPU_H
#include <stdint.h>
#include <metal/interrupt.h> #include <metal/interrupt.h>
#include <stdint.h>
struct metal_cpu; struct metal_cpu;
/*! /*!
* @brief Function signature for exception handlers * @brief Function signature for exception handlers
*/ */
typedef void (*metal_exception_handler_t) (struct metal_cpu *cpu, int ecode); typedef void (*metal_exception_handler_t)(struct metal_cpu *cpu, int ecode);
struct metal_cpu_vtable { struct metal_cpu_vtable {
unsigned long long (*timer_get)(struct metal_cpu *cpu); unsigned long long (*mcycle_get)(struct metal_cpu *cpu);
unsigned long long (*timebase_get)(struct metal_cpu *cpu); unsigned long long (*timebase_get)(struct metal_cpu *cpu);
unsigned long long (*mtime_get)(struct metal_cpu *cpu); unsigned long long (*mtime_get)(struct metal_cpu *cpu);
int (*mtimecmp_set)(struct metal_cpu *cpu, unsigned long long time); int (*mtimecmp_set)(struct metal_cpu *cpu, unsigned long long time);
struct metal_interrupt* (*tmr_controller_interrupt)(struct metal_cpu *cpu); struct metal_interrupt *(*tmr_controller_interrupt)(struct metal_cpu *cpu);
int (*get_tmr_interrupt_id)(struct metal_cpu *cpu); int (*get_tmr_interrupt_id)(struct metal_cpu *cpu);
struct metal_interrupt* (*sw_controller_interrupt)(struct metal_cpu *cpu); struct metal_interrupt *(*sw_controller_interrupt)(struct metal_cpu *cpu);
int (*get_sw_interrupt_id)(struct metal_cpu *cpu); int (*get_sw_interrupt_id)(struct metal_cpu *cpu);
int (*set_sw_ipi)(struct metal_cpu *cpu, int hartid); int (*set_sw_ipi)(struct metal_cpu *cpu, int hartid);
int (*clear_sw_ipi)(struct metal_cpu *cpu, int hartid); int (*clear_sw_ipi)(struct metal_cpu *cpu, int hartid);
int (*get_msip)(struct metal_cpu *cpu, int hartid); int (*get_msip)(struct metal_cpu *cpu, int hartid);
struct metal_interrupt* (*controller_interrupt)(struct metal_cpu *cpu); struct metal_interrupt *(*controller_interrupt)(struct metal_cpu *cpu);
int (*exception_register)(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler); int (*exception_register)(struct metal_cpu *cpu, int ecode,
metal_exception_handler_t handler);
int (*get_ilen)(struct metal_cpu *cpu, uintptr_t epc); int (*get_ilen)(struct metal_cpu *cpu, uintptr_t epc);
uintptr_t (*get_epc)(struct metal_cpu *cpu); uintptr_t (*get_epc)(struct metal_cpu *cpu);
int (*set_epc)(struct metal_cpu *cpu, uintptr_t epc); int (*set_epc)(struct metal_cpu *cpu, uintptr_t epc);
struct metal_buserror *(*get_buserror)(struct metal_cpu *cpu);
}; };
/*! @brief A device handle for a CPU hart /*! @brief A device handle for a CPU hart
@ -49,17 +51,17 @@ struct metal_cpu {
* @param hartid The ID of the desired CPU hart * @param hartid The ID of the desired CPU hart
* @return A pointer to the CPU device handle * @return A pointer to the CPU device handle
*/ */
struct metal_cpu* metal_cpu_get(int hartid); struct metal_cpu *metal_cpu_get(unsigned int hartid);
/*! @brief Get the hartid of the CPU hart executing this function /*! @brief Get the hartid of the CPU hart executing this function
* *
* @return The hartid of the current CPU hart */ * @return The hartid of the current CPU hart */
int metal_cpu_get_current_hartid(); int metal_cpu_get_current_hartid(void);
/*! @brief Get the number of CPU harts /*! @brief Get the number of CPU harts
* *
* @return The number of CPU harts */ * @return The number of CPU harts */
int metal_cpu_get_num_harts(); int metal_cpu_get_num_harts(void);
/*! @brief Get the CPU cycle count timer value /*! @brief Get the CPU cycle count timer value
* *
@ -68,8 +70,9 @@ int metal_cpu_get_num_harts();
* @param cpu The CPU device handle * @param cpu The CPU device handle
* @return The value of the CPU cycle count timer * @return The value of the CPU cycle count timer
*/ */
inline unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu) __inline__ unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu) {
{ return cpu->vtable->timer_get(cpu); } return cpu->vtable->mcycle_get(cpu);
}
/*! @brief Get the timebase of the CPU /*! @brief Get the timebase of the CPU
* *
@ -78,8 +81,9 @@ inline unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu)
* @param cpu The CPU device handle * @param cpu The CPU device handle
* @return The value of the cycle count timer timebase * @return The value of the cycle count timer timebase
*/ */
inline unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu) __inline__ unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu) {
{ return cpu->vtable->timebase_get(cpu); } return cpu->vtable->timebase_get(cpu);
}
/*! @brief Get the value of the mtime RTC /*! @brief Get the value of the mtime RTC
* *
@ -90,8 +94,9 @@ inline unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu)
* @param cpu The CPU device handle * @param cpu The CPU device handle
* @return The value of mtime, or 0 if failure * @return The value of mtime, or 0 if failure
*/ */
inline unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu) __inline__ unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu) {
{ return cpu->vtable->mtime_get(cpu); } return cpu->vtable->mtime_get(cpu);
}
/*! @brief Set the value of the RTC mtimecmp RTC /*! @brief Set the value of the RTC mtimecmp RTC
* *
@ -103,20 +108,24 @@ inline unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu)
* @param time The value to set the compare register to * @param time The value to set the compare register to
* @return The value of mtimecmp or -1 if error * @return The value of mtimecmp or -1 if error
*/ */
inline int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time) __inline__ int metal_cpu_set_mtimecmp(struct metal_cpu *cpu,
{ return cpu->vtable->mtimecmp_set(cpu, time); } unsigned long long time) {
return cpu->vtable->mtimecmp_set(cpu, time);
}
/*! @brief Get a reference to RTC timer interrupt controller /*! @brief Get a reference to RTC timer interrupt controller
* *
* Get a reference to the interrupt controller for the real-time clock interrupt. * Get a reference to the interrupt controller for the real-time clock
* The controller returned by this function must be initialized before any interrupts * interrupt. The controller returned by this function must be initialized
* are registered or enabled with it. * before any interrupts are registered or enabled with it.
* *
* @param cpu The CPU device handle * @param cpu The CPU device handle
* @return A pointer to the timer interrupt handle * @return A pointer to the timer interrupt handle
*/ */
inline struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu) __inline__ struct metal_interrupt *
{ return cpu->vtable->tmr_controller_interrupt(cpu); } metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu) {
return cpu->vtable->tmr_controller_interrupt(cpu);
}
/*! @brief Get the RTC timer interrupt id /*! @brief Get the RTC timer interrupt id
* *
@ -125,20 +134,23 @@ inline struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal
* @param cpu The CPU device handle * @param cpu The CPU device handle
* @return The timer interrupt ID * @return The timer interrupt ID
*/ */
inline int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu) __inline__ int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu) {
{ return cpu->vtable->get_tmr_interrupt_id(cpu); } return cpu->vtable->get_tmr_interrupt_id(cpu);
}
/*! @brief Get a reference to the software interrupt controller /*! @brief Get a reference to the software interrupt controller
* *
* Get a reference to the interrupt controller for the software/inter-process * Get a reference to the interrupt controller for the software/inter-process
* interrupt. The controller returned by this function must be initialized before * interrupt. The controller returned by this function must be initialized
* any interrupts are registered or enabled with it. * before any interrupts are registered or enabled with it.
* *
* @param cpu The CPU device handle * @param cpu The CPU device handle
* @return A pointer to the software interrupt handle * @return A pointer to the software interrupt handle
*/ */
inline struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu) __inline__ struct metal_interrupt *
{ return cpu->vtable->sw_controller_interrupt(cpu); } metal_cpu_software_interrupt_controller(struct metal_cpu *cpu) {
return cpu->vtable->sw_controller_interrupt(cpu);
}
/*! @brief Get the software interrupt id /*! @brief Get the software interrupt id
* *
@ -147,8 +159,9 @@ inline struct metal_interrupt* metal_cpu_software_interrupt_controller(struct me
* @param cpu The CPU device handle * @param cpu The CPU device handle
* @return the software interrupt ID * @return the software interrupt ID
*/ */
inline int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu) __inline__ int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu) {
{ return cpu->vtable->get_sw_interrupt_id(cpu); } return cpu->vtable->get_sw_interrupt_id(cpu);
}
/*! /*!
* @brief Set the inter-process interrupt for a hart * @brief Set the inter-process interrupt for a hart
@ -161,8 +174,9 @@ inline int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu)
* @param hartid The CPU hart ID to be interrupted * @param hartid The CPU hart ID to be interrupted
* @return 0 upon success * @return 0 upon success
*/ */
inline int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid) __inline__ int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid) {
{ return cpu->vtable->set_sw_ipi(cpu, hartid); } return cpu->vtable->set_sw_ipi(cpu, hartid);
}
/*! /*!
* @brief Clear the inter-process interrupt for a hart * @brief Clear the inter-process interrupt for a hart
@ -175,8 +189,9 @@ inline int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid)
* @param hartid The CPU hart ID to clear * @param hartid The CPU hart ID to clear
* @return 0 upon success * @return 0 upon success
*/ */
inline int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid) __inline__ int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid) {
{ return cpu->vtable->clear_sw_ipi(cpu, hartid); } return cpu->vtable->clear_sw_ipi(cpu, hartid);
}
/*! /*!
* @brief Get the value of MSIP for the given hart * @brief Get the value of MSIP for the given hart
@ -190,8 +205,9 @@ inline int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid)
* @param hartid The CPU hart to read * @param hartid The CPU hart to read
* @return 0 upon success * @return 0 upon success
*/ */
inline int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid) __inline__ int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid) {
{ return cpu->vtable->get_msip(cpu, hartid); } return cpu->vtable->get_msip(cpu, hartid);
}
/*! /*!
* @brief Get the interrupt controller for the CPU * @brief Get the interrupt controller for the CPU
@ -204,22 +220,26 @@ inline int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid)
* @param cpu The CPU device handle * @param cpu The CPU device handle
* @return The handle for the CPU interrupt controller * @return The handle for the CPU interrupt controller
*/ */
inline struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu) __inline__ struct metal_interrupt *
{ return cpu->vtable->controller_interrupt(cpu); } metal_cpu_interrupt_controller(struct metal_cpu *cpu) {
return cpu->vtable->controller_interrupt(cpu);
}
/*! /*!
* @brief Register an exception handler * @brief Register an exception handler
* *
* Register an exception handler for the CPU. The CPU interrupt controller must be initialized * Register an exception handler for the CPU. The CPU interrupt controller must
* before this function is called. * be initialized before this function is called.
* *
* @param cpu The CPU device handle * @param cpu The CPU device handle
* @param ecode The exception code to register a handler for * @param ecode The exception code to register a handler for
* @param handler Callback function for the exception handler * @param handler Callback function for the exception handler
* @return 0 upon success * @return 0 upon success
*/ */
inline int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler) __inline__ int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode,
{ return cpu->vtable->exception_register(cpu, ecode, handler); } metal_exception_handler_t handler) {
return cpu->vtable->exception_register(cpu, ecode, handler);
}
/*! /*!
* @brief Get the length of an instruction in bytes * @brief Get the length of an instruction in bytes
@ -237,8 +257,10 @@ inline int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_
* @param epc The address of the instruction to measure * @param epc The address of the instruction to measure
* @return the length of the instruction in bytes * @return the length of the instruction in bytes
*/ */
inline int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc) __inline__ int metal_cpu_get_instruction_length(struct metal_cpu *cpu,
{ return cpu->vtable->get_ilen(cpu, epc); } uintptr_t epc) {
return cpu->vtable->get_ilen(cpu, epc);
}
/*! /*!
* @brief Get the program counter of the current exception. * @brief Get the program counter of the current exception.
@ -249,8 +271,9 @@ inline int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc
* @param cpu The CPU device handle * @param cpu The CPU device handle
* @return The value of the program counter at the time of the exception * @return The value of the program counter at the time of the exception
*/ */
inline uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu) __inline__ uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu) {
{ return cpu->vtable->get_epc(cpu); } return cpu->vtable->get_epc(cpu);
}
/*! /*!
* @brief Set the exception program counter * @brief Set the exception program counter
@ -265,7 +288,20 @@ inline uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu)
* @param epc The address to set the exception program counter to * @param epc The address to set the exception program counter to
* @return 0 upon success * @return 0 upon success
*/ */
inline int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc) __inline__ int metal_cpu_set_exception_pc(struct metal_cpu *cpu,
{ return cpu->vtable->set_epc(cpu, epc); } uintptr_t epc) {
return cpu->vtable->set_epc(cpu, epc);
}
/*!
* @brief Get the handle for the hart's bus error unit
*
* @param cpu The CPU device handle
* @return A pointer to the bus error unit handle
*/
__inline__ struct metal_buserror *
metal_cpu_get_buserror(struct metal_cpu *cpu) {
return cpu->vtable->get_buserror(cpu);
}
#endif #endif

View file

@ -0,0 +1,32 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__CSR_H
#define METAL__CSR_H
#include <metal/compiler.h>
#include <stddef.h>
#include <stdint.h>
/*!
* @file csr.h
* @brief A collection of APIs for get and set CSR registers
*/
/*!
* @brief Read a given CSR register without checking validity of CSR offset
* @param crs Register label or hex value offset to read from
* @param value Variable name of uintprt_t type to get the value
*/
#define METAL_CPU_GET_CSR(reg, value) \
__asm__ volatile("csrr %0, " #reg : "=r"(value));
/*!
* @brief Write to a given CSR register without checking validity of CSR offset
* @param crs Register label or hex value offset to write to
* @param value Variable name of uintprt_t type to set the value
*/
#define METAL_CPU_SET_CSR(reg, value) \
__asm__ volatile("csrw " #reg ", %0" : : "r"(value));
#endif // METAL__CSR_H

View file

@ -6,8 +6,8 @@
struct __metal_driver_fixed_clock; struct __metal_driver_fixed_clock;
#include <metal/compiler.h>
#include <metal/clock.h> #include <metal/clock.h>
#include <metal/compiler.h>
struct __metal_driver_vtable_fixed_clock { struct __metal_driver_vtable_fixed_clock {
struct __metal_clock_vtable clock; struct __metal_clock_vtable clock;

View file

@ -6,8 +6,8 @@
struct __metal_driver_fixed_factor_clock; struct __metal_driver_fixed_factor_clock;
#include <metal/compiler.h>
#include <metal/clock.h> #include <metal/clock.h>
#include <metal/compiler.h>
struct __metal_driver_vtable_fixed_factor_clock { struct __metal_driver_vtable_fixed_factor_clock {
struct __metal_clock_vtable clock; struct __metal_clock_vtable clock;

View file

@ -21,4 +21,7 @@ struct __metal_driver_riscv_clint0 {
}; };
#undef __METAL_MACHINE_MACROS #undef __METAL_MACHINE_MACROS
int __metal_driver_riscv_clint0_command_request(
struct metal_interrupt *controller, int command, void *data);
#endif #endif

View file

@ -4,148 +4,154 @@
#ifndef METAL__DRIVERS__RISCV_CPU_H #ifndef METAL__DRIVERS__RISCV_CPU_H
#define METAL__DRIVERS__RISCV_CPU_H #define METAL__DRIVERS__RISCV_CPU_H
#include <stdint.h>
#include <metal/cpu.h>
#include <metal/compiler.h> #include <metal/compiler.h>
#include <metal/cpu.h>
#include <stdint.h>
#define METAL_MAX_CORES 8 #define METAL_MAX_CORES 8
#define METAL_MAX_MI 32 /* Per ISA MCause interrupts 32+ are Reserved */ #define METAL_MAX_MI 32 /* Per ISA MCause interrupts 32+ are Reserved */
#define METAL_MAX_ME 12 /* Per ISA Exception codes 12+ are Reserved */ #define METAL_MAX_ME 12 /* Per ISA Exception codes 12+ are Reserved */
#define METAL_DEFAULT_RTC_FREQ 32768 #define METAL_DEFAULT_RTC_FREQ 32768
#define METAL_DISABLE 0 #define METAL_DISABLE 0
#define METAL_ENABLE 1 #define METAL_ENABLE 1
#define METAL_ISA_A_EXTENSIONS 0x0001 #define METAL_ISA_A_EXTENSIONS 0x0001
#define METAL_ISA_C_EXTENSIONS 0x0004 #define METAL_ISA_C_EXTENSIONS 0x0004
#define METAL_ISA_D_EXTENSIONS 0x0008 #define METAL_ISA_D_EXTENSIONS 0x0008
#define METAL_ISA_E_EXTENSIONS 0x0010 #define METAL_ISA_E_EXTENSIONS 0x0010
#define METAL_ISA_F_EXTENSIONS 0x0020 #define METAL_ISA_F_EXTENSIONS 0x0020
#define METAL_ISA_G_EXTENSIONS 0x0040 #define METAL_ISA_G_EXTENSIONS 0x0040
#define METAL_ISA_I_EXTENSIONS 0x0100 #define METAL_ISA_I_EXTENSIONS 0x0100
#define METAL_ISA_M_EXTENSIONS 0x1000 #define METAL_ISA_M_EXTENSIONS 0x1000
#define METAL_ISA_N_EXTENSIONS 0x2000 #define METAL_ISA_N_EXTENSIONS 0x2000
#define METAL_ISA_Q_EXTENSIONS 0x10000 #define METAL_ISA_Q_EXTENSIONS 0x10000
#define METAL_ISA_S_EXTENSIONS 0x40000 #define METAL_ISA_S_EXTENSIONS 0x40000
#define METAL_ISA_U_EXTENSIONS 0x100000 #define METAL_ISA_U_EXTENSIONS 0x100000
#define METAL_ISA_V_EXTENSIONS 0x200000 #define METAL_ISA_V_EXTENSIONS 0x200000
#define METAL_ISA_XL32_EXTENSIONS 0x40000000UL #define METAL_ISA_XL32_EXTENSIONS 0x40000000UL
#define METAL_ISA_XL64_EXTENSIONS 0x8000000000000000UL #define METAL_ISA_XL64_EXTENSIONS 0x8000000000000000UL
#define METAL_ISA_XL128_EXTENSIONS 0xC000000000000000UL #define METAL_ISA_XL128_EXTENSIONS 0xC000000000000000UL
#define METAL_MTVEC_DIRECT 0x00 #define METAL_MTVEC_DIRECT 0x00
#define METAL_MTVEC_VECTORED 0x01 #define METAL_MTVEC_VECTORED 0x01
#define METAL_MTVEC_CLIC 0x02 #define METAL_MTVEC_CLIC 0x02
#define METAL_MTVEC_CLIC_VECTORED 0x03 #define METAL_MTVEC_CLIC_VECTORED 0x03
#define METAL_MTVEC_CLIC_RESERVED 0x3C #define METAL_MTVEC_CLIC_RESERVED 0x3C
#define METAL_MTVEC_MASK 0x3F #define METAL_MTVEC_MASK 0x3F
#if __riscv_xlen == 32 #if __riscv_xlen == 32
#define METAL_MCAUSE_INTR 0x80000000UL #define METAL_MCAUSE_INTR 0x80000000UL
#define METAL_MCAUSE_CAUSE 0x000003FFUL #define METAL_MCAUSE_CAUSE 0x000003FFUL
#else #else
#define METAL_MCAUSE_INTR 0x8000000000000000UL #define METAL_MCAUSE_INTR 0x8000000000000000UL
#define METAL_MCAUSE_CAUSE 0x00000000000003FFUL #define METAL_MCAUSE_CAUSE 0x00000000000003FFUL
#endif #endif
#define METAL_MCAUSE_MINHV 0x40000000UL #define METAL_MCAUSE_MINHV 0x40000000UL
#define METAL_MCAUSE_MPP 0x30000000UL #define METAL_MCAUSE_MPP 0x30000000UL
#define METAL_MCAUSE_MPIE 0x08000000UL #define METAL_MCAUSE_MPIE 0x08000000UL
#define METAL_MCAUSE_MPIL 0x00FF0000UL #define METAL_MCAUSE_MPIL 0x00FF0000UL
#define METAL_MSTATUS_MIE 0x00000008UL #define METAL_MSTATUS_MIE 0x00000008UL
#define METAL_MSTATUS_MPIE 0x00000080UL #define METAL_MSTATUS_MPIE 0x00000080UL
#define METAL_MSTATUS_MPP 0x00001800UL #define METAL_MSTATUS_MPP 0x00001800UL
#define METAL_MSTATUS_FS_INIT 0x00002000UL #define METAL_MSTATUS_FS_INIT 0x00002000UL
#define METAL_MSTATUS_FS_CLEAN 0x00004000UL #define METAL_MSTATUS_FS_CLEAN 0x00004000UL
#define METAL_MSTATUS_FS_DIRTY 0x00006000UL #define METAL_MSTATUS_FS_DIRTY 0x00006000UL
#define METAL_MSTATUS_MPRV 0x00020000UL #define METAL_MSTATUS_MPRV 0x00020000UL
#define METAL_MSTATUS_MXR 0x00080000UL #define METAL_MSTATUS_MXR 0x00080000UL
#define METAL_MINTSTATUS_MIL 0xFF000000UL #define METAL_MINTSTATUS_MIL 0xFF000000UL
#define METAL_MINTSTATUS_SIL 0x0000FF00UL #define METAL_MINTSTATUS_SIL 0x0000FF00UL
#define METAL_MINTSTATUS_UIL 0x000000FFUL #define METAL_MINTSTATUS_UIL 0x000000FFUL
#define METAL_LOCAL_INTR(X) (16 + X) #define METAL_LOCAL_INTR(X) (16 + X)
#define METAL_MCAUSE_EVAL(cause) (cause & METAL_MCAUSE_INTR) #define METAL_MCAUSE_EVAL(cause) (cause & METAL_MCAUSE_INTR)
#define METAL_INTERRUPT(cause) (METAL_MCAUSE_EVAL(cause) ? 1 : 0) #define METAL_INTERRUPT(cause) (METAL_MCAUSE_EVAL(cause) ? 1 : 0)
#define METAL_EXCEPTION(cause) (METAL_MCAUSE_EVAL(cause) ? 0 : 1) #define METAL_EXCEPTION(cause) (METAL_MCAUSE_EVAL(cause) ? 0 : 1)
#define METAL_SW_INTR_EXCEPTION (METAL_MCAUSE_INTR + 3) #define METAL_SW_INTR_EXCEPTION (METAL_MCAUSE_INTR + 3)
#define METAL_TMR_INTR_EXCEPTION (METAL_MCAUSE_INTR + 7) #define METAL_TMR_INTR_EXCEPTION (METAL_MCAUSE_INTR + 7)
#define METAL_EXT_INTR_EXCEPTION (METAL_MCAUSE_INTR + 11) #define METAL_EXT_INTR_EXCEPTION (METAL_MCAUSE_INTR + 11)
#define METAL_LOCAL_INTR_EXCEPTION(X) (METAL_MCAUSE_INTR + METAL_LOCAL_INTR(X)) #define METAL_LOCAL_INTR_EXCEPTION(X) (METAL_MCAUSE_INTR + METAL_LOCAL_INTR(X))
#define METAL_LOCAL_INTR_RESERVE0 1 #define METAL_LOCAL_INTR_RESERVE0 1
#define METAL_LOCAL_INTR_RESERVE1 2 #define METAL_LOCAL_INTR_RESERVE1 2
#define METAL_LOCAL_INTR_RESERVE2 4 #define METAL_LOCAL_INTR_RESERVE2 4
#define METAL_LOCAL_INTERRUPT_SW 8 /* Bit3 0x008 */ #define METAL_LOCAL_INTERRUPT_SW 8 /* Bit3 0x008 */
#define METAL_LOCAL_INTR_RESERVE4 16 #define METAL_LOCAL_INTR_RESERVE4 16
#define METAL_LOCAL_INTR_RESERVE5 32 #define METAL_LOCAL_INTR_RESERVE5 32
#define METAL_LOCAL_INTR_RESERVE6 64 #define METAL_LOCAL_INTR_RESERVE6 64
#define METAL_LOCAL_INTERRUPT_TMR 128 /* Bit7 0x080 */ #define METAL_LOCAL_INTERRUPT_TMR 128 /* Bit7 0x080 */
#define METAL_LOCAL_INTR_RESERVE8 256 #define METAL_LOCAL_INTR_RESERVE8 256
#define METAL_LOCAL_INTR_RESERVE9 512 #define METAL_LOCAL_INTR_RESERVE9 512
#define METAL_LOCAL_INTR_RESERVE10 1024 #define METAL_LOCAL_INTR_RESERVE10 1024
#define METAL_LOCAL_INTERRUPT_EXT 2048 /* Bit11 0x800 */ #define METAL_LOCAL_INTERRUPT_EXT 2048 /* Bit11 0x800 */
/* Bit12 to Bit15 are Reserved */ /* Bit12 to Bit15 are Reserved */
#define METAL_LOCAL_INTERRUPT(X) (0x10000 << X) /* Bit16+ Start of Custom Local Interrupt */ #define METAL_LOCAL_INTERRUPT(X) \
#define METAL_MIE_INTERRUPT METAL_MSTATUS_MIE (0x10000 << X) /* Bit16+ Start of Custom Local Interrupt */
#define METAL_MIE_INTERRUPT METAL_MSTATUS_MIE
#define METAL_INSN_LENGTH_MASK 3
#define METAL_INSN_NOT_COMPRESSED 3
typedef enum { typedef enum {
METAL_MACHINE_PRIVILEGE_MODE, METAL_MACHINE_PRIVILEGE_MODE,
METAL_SUPERVISOR_PRIVILEGE_MODE, METAL_SUPERVISOR_PRIVILEGE_MODE,
METAL_USER_PRIVILEGE_MODE, METAL_USER_PRIVILEGE_MODE,
} metal_privilege_mode_e; } metal_privilege_mode_e;
typedef enum { typedef enum {
METAL_INTERRUPT_ID_BASE, METAL_INTERRUPT_ID_BASE,
METAL_INTERRUPT_ID_SW = (METAL_INTERRUPT_ID_BASE + 3), METAL_INTERRUPT_ID_SW = (METAL_INTERRUPT_ID_BASE + 3),
METAL_INTERRUPT_ID_TMR = (METAL_INTERRUPT_ID_BASE + 7), METAL_INTERRUPT_ID_TMR = (METAL_INTERRUPT_ID_BASE + 7),
METAL_INTERRUPT_ID_EXT = (METAL_INTERRUPT_ID_BASE + 11), METAL_INTERRUPT_ID_EXT = (METAL_INTERRUPT_ID_BASE + 11),
METAL_INTERRUPT_ID_LC0 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(0)), METAL_INTERRUPT_ID_CSW = (METAL_INTERRUPT_ID_BASE + 12),
METAL_INTERRUPT_ID_LC1 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(1)), METAL_INTERRUPT_ID_LC0 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(0)),
METAL_INTERRUPT_ID_LC2 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(2)), METAL_INTERRUPT_ID_LC1 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(1)),
METAL_INTERRUPT_ID_LC3 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(3)), METAL_INTERRUPT_ID_LC2 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(2)),
METAL_INTERRUPT_ID_LC4 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(4)), METAL_INTERRUPT_ID_LC3 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(3)),
METAL_INTERRUPT_ID_LC5 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(5)), METAL_INTERRUPT_ID_LC4 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(4)),
METAL_INTERRUPT_ID_LC6 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(6)), METAL_INTERRUPT_ID_LC5 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(5)),
METAL_INTERRUPT_ID_LC7 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(7)), METAL_INTERRUPT_ID_LC6 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(6)),
METAL_INTERRUPT_ID_LC8 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(8)), METAL_INTERRUPT_ID_LC7 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(7)),
METAL_INTERRUPT_ID_LC9 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(9)), METAL_INTERRUPT_ID_LC8 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(8)),
METAL_INTERRUPT_ID_LC10 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(10)), METAL_INTERRUPT_ID_LC9 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(9)),
METAL_INTERRUPT_ID_LC11 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(11)), METAL_INTERRUPT_ID_LC10 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(10)),
METAL_INTERRUPT_ID_LC12 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(12)), METAL_INTERRUPT_ID_LC11 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(11)),
METAL_INTERRUPT_ID_LC13 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(13)), METAL_INTERRUPT_ID_LC12 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(12)),
METAL_INTERRUPT_ID_LC14 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(14)), METAL_INTERRUPT_ID_LC13 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(13)),
METAL_INTERRUPT_ID_LC15 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(15)), METAL_INTERRUPT_ID_LC14 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(14)),
METAL_INTERRUPT_ID_LCMX, METAL_INTERRUPT_ID_LC15 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(15)),
METAL_INTERRUPT_ID_GL0 = METAL_INTERRUPT_ID_LCMX, METAL_INTERRUPT_ID_LCMX,
METAL_INTERRUPT_ID_GLMX = (METAL_MCAUSE_CAUSE + 1), METAL_INTERRUPT_ID_GL0 = METAL_INTERRUPT_ID_LCMX,
METAL_INTERRUPT_ID_GLMX = (METAL_MCAUSE_CAUSE + 1),
METAL_INTERRUPT_ID_BEU = 128,
} metal_interrupt_id_e; } metal_interrupt_id_e;
typedef enum { typedef enum {
METAL_IAM_EXCEPTION_CODE, /* Instruction address misaligned */ METAL_IAM_EXCEPTION_CODE, /* Instruction address misaligned */
METAL_IAF_EXCEPTION_CODE, /* Instruction access faultd */ METAL_IAF_EXCEPTION_CODE, /* Instruction access faultd */
METAL_II_EXCEPTION_CODE, /* Illegal instruction */ METAL_II_EXCEPTION_CODE, /* Illegal instruction */
METAL_BREAK_EXCEPTION_CODE, /* Breakpoint */ METAL_BREAK_EXCEPTION_CODE, /* Breakpoint */
METAL_LAM_EXCEPTION_CODE, /* Load address misaligned */ METAL_LAM_EXCEPTION_CODE, /* Load address misaligned */
METAL_LAF_EXCEPTION_CODE, /* Load access fault */ METAL_LAF_EXCEPTION_CODE, /* Load access fault */
METAL_SAMOAM_EXCEPTION_CODE, /* Store/AMO address misaligned */ METAL_SAMOAM_EXCEPTION_CODE, /* Store/AMO address misaligned */
METAL_SAMOAF_EXCEPTION_CODE, /* Store/AMO access fault */ METAL_SAMOAF_EXCEPTION_CODE, /* Store/AMO access fault */
METAL_ECALL_U_EXCEPTION_CODE, /* Environment call from U-mode */ METAL_ECALL_U_EXCEPTION_CODE, /* Environment call from U-mode */
METAL_R9_EXCEPTION_CODE, /* Reserved */ METAL_R9_EXCEPTION_CODE, /* Reserved */
METAL_R10_EXCEPTION_CODE, /* Reserved */ METAL_R10_EXCEPTION_CODE, /* Reserved */
METAL_ECALL_M_EXCEPTION_CODE, /* Environment call from M-mode */ METAL_ECALL_M_EXCEPTION_CODE, /* Environment call from M-mode */
METAL_MAX_EXCEPTION_CODE, METAL_MAX_EXCEPTION_CODE,
} metal_exception_code_e; } metal_exception_code_e;
typedef enum { typedef enum {
METAL_TIMER_MTIME_GET = 1, METAL_TIMER_MTIME_GET = 1,
METAL_SOFTWARE_IPI_CLEAR, METAL_SOFTWARE_IPI_CLEAR,
METAL_SOFTWARE_IPI_SET, METAL_SOFTWARE_IPI_SET,
METAL_SOFTWARE_MSIP_GET, METAL_SOFTWARE_MSIP_GET,
METAL_MAX_INTERRUPT_GET, METAL_MAX_INTERRUPT_GET,
METAL_INDEX_INTERRUPT_GET, METAL_INDEX_INTERRUPT_GET,
} metal_interrup_cmd_e; } metal_interrup_cmd_e;
typedef struct __metal_interrupt_data { typedef struct __metal_interrupt_data {
long long pad : 64; long long pad : 64;
metal_interrupt_handler_t handler; metal_interrupt_handler_t handler;
void *sub_int; void *sub_int;
void *exint_data; void *exint_data;
} __metal_interrupt_data; } __metal_interrupt_data;
@ -154,30 +160,15 @@ typedef struct __metal_interrupt_data {
uintptr_t __metal_myhart_id(void); uintptr_t __metal_myhart_id(void);
struct __metal_driver_interrupt_controller_vtable {
void (*interrupt_init)(struct metal_interrupt *controller);
int (*interrupt_register)(struct metal_interrupt *controller,
int id, metal_interrupt_handler_t isr, void *priv_data);
int (*interrupt_enable)(struct metal_interrupt *controller, int id);
int (*interrupt_disable)(struct metal_interrupt *controller, int id);
int (*command_request)(struct metal_interrupt *intr, int cmd, void *data);
};
struct __metal_driver_vtable_riscv_cpu_intc { struct __metal_driver_vtable_riscv_cpu_intc {
struct metal_interrupt_vtable controller_vtable; struct metal_interrupt_vtable controller_vtable;
}; };
void __metal_interrupt_global_enable(void); void __metal_interrupt_global_enable(void);
void __metal_interrupt_global_disable(void); void __metal_interrupt_global_disable(void);
void __metal_controller_interrupt_vector(metal_vector_mode mode, void *vec_table); metal_vector_mode __metal_controller_interrupt_vector_mode(void);
inline int __metal_controller_interrupt_is_selective_vectored (void) void __metal_controller_interrupt_vector(metal_vector_mode mode,
{ void *vec_table);
uintptr_t val;
asm volatile ("csrr %0, mtvec" : "=r"(val));
return ((val & METAL_MTVEC_CLIC_VECTORED) == METAL_MTVEC_CLIC);
}
__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_cpu_intc) __METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_cpu_intc)
@ -186,18 +177,20 @@ struct __metal_driver_riscv_cpu_intc {
int init_done; int init_done;
uintptr_t metal_mtvec_table[METAL_MAX_MI]; uintptr_t metal_mtvec_table[METAL_MAX_MI];
__metal_interrupt_data metal_int_table[METAL_MAX_MI]; __metal_interrupt_data metal_int_table[METAL_MAX_MI];
__metal_interrupt_data metal_int_beu;
metal_exception_handler_t metal_exception_table[METAL_MAX_ME]; metal_exception_handler_t metal_exception_table[METAL_MAX_ME];
}; };
/* CPU driver*/ /* CPU driver*/
struct __metal_driver_vtable_cpu { struct __metal_driver_vtable_cpu {
struct metal_cpu_vtable cpu_vtable; struct metal_cpu_vtable cpu_vtable;
}; };
__METAL_DECLARE_VTABLE(__metal_driver_vtable_cpu) __METAL_DECLARE_VTABLE(__metal_driver_vtable_cpu)
struct __metal_driver_cpu { struct __metal_driver_cpu {
struct metal_cpu cpu; struct metal_cpu cpu;
unsigned int hpm_count; /* Available HPM counters per CPU */
}; };
#endif #endif

View file

@ -7,10 +7,10 @@
#include <metal/compiler.h> #include <metal/compiler.h>
#include <metal/drivers/riscv_cpu.h> #include <metal/drivers/riscv_cpu.h>
#define METAL_PLIC_SOURCE_MASK 0x1F #define METAL_PLIC_SOURCE_MASK 0x1F
#define METAL_PLIC_SOURCE_SHIFT 5 #define METAL_PLIC_SOURCE_SHIFT 5
#define METAL_PLIC_SOURCE_PRIORITY_SHIFT 2 #define METAL_PLIC_SOURCE_PRIORITY_SHIFT 2
#define METAL_PLIC_SOURCE_PENDING_SHIFT 0 #define METAL_PLIC_SOURCE_PENDING_SHIFT 0
struct __metal_driver_vtable_riscv_plic0 { struct __metal_driver_vtable_riscv_plic0 {
struct metal_interrupt_vtable plic_vtable; struct metal_interrupt_vtable plic_vtable;

View file

@ -0,0 +1,184 @@
/* Copyright 2020 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_BUSERROR0_H
#define METAL__DRIVERS__SIFIVE_BUSERROR0_H
/*!
* @file sifive_buserror0.h
*
* @brief API for configuring the SiFive Bus Error Unit
*/
#include <metal/compiler.h>
#include <stdbool.h>
#include <stdint.h>
/*!
* @brief The set of possible events handled by a SiFive Bus Error Unit
*/
typedef enum {
/*! @brief No event or error has been detected */
METAL_BUSERROR_EVENT_NONE = 0,
/*! @brief A correctable ECC error has occurred in the I$ or ITIM */
METAL_BUSERROR_EVENT_INST_CORRECTABLE_ECC_ERROR = (1 << 2),
/*! @brief An uncorrectable ECC error has occurred in the I$ or ITIM */
METAL_BUSERROR_EVENT_INST_UNCORRECTABLE_ECC_ERROR = (1 << 3),
/*! @brief A TileLink load or store bus error has occurred */
METAL_BUSERROR_EVENT_LOAD_STORE_ERROR = (1 << 5),
/*! @brief A correctable ECC error has occurred in the D$ or DTIM */
METAL_BUSERROR_EVENT_DATA_CORRECTABLE_ECC_ERROR = (1 << 6),
/*! @brief An uncorrectable ECC error has occurred in the D$ or DTIM */
METAL_BUSERROR_EVENT_DATA_UNCORRECTABLE_ECC_ERROR = (1 << 7),
/*! @brief Used to set/clear all interrupts or query/clear all accrued
events */
METAL_BUSERROR_EVENT_ALL =
METAL_BUSERROR_EVENT_INST_CORRECTABLE_ECC_ERROR |
METAL_BUSERROR_EVENT_INST_UNCORRECTABLE_ECC_ERROR |
METAL_BUSERROR_EVENT_LOAD_STORE_ERROR |
METAL_BUSERROR_EVENT_DATA_CORRECTABLE_ECC_ERROR |
METAL_BUSERROR_EVENT_DATA_UNCORRECTABLE_ECC_ERROR,
/*! @brief A synonym of METAL_BUSERROR_EVENT_ALL */
METAL_BUSERROR_EVENT_ANY = METAL_BUSERROR_EVENT_ALL,
/*! @brief A value which is impossible for the bus error unit to report.
* Indicates an error has occurred if provided as a return value. */
METAL_BUSERROR_EVENT_INVALID = (1 << 8),
} metal_buserror_event_t;
/*!
* @brief The handle for a bus error unit
*/
struct metal_buserror {
uint8_t __no_empty_structs;
};
/*!
* @brief Enable bus error events
*
* Enabling bus error events causes them to be registered as accrued and,
* if the corresponding interrupt is inabled, trigger interrupts.
*
* @param beu The bus error unit handle
* @param events A mask of error events to enable
* @param enabled True if the mask should be enabled, false if they should be
* disabled
* @return 0 upon success
*/
int metal_buserror_set_event_enabled(struct metal_buserror *beu,
metal_buserror_event_t events,
bool enabled);
/*!
* @brief Get enabled bus error events
* @param beu The bus error unit handle
* @return A mask of all enabled events
*/
metal_buserror_event_t
metal_buserror_get_event_enabled(struct metal_buserror *beu);
/*!
* @brief Enable or disable the platform interrupt
*
* @param beu The bus error unit handle
* @param event The error event which would trigger the interrupt
* @param enabled True if the interrupt should be enabled
* @return 0 upon success
*/
int metal_buserror_set_platform_interrupt(struct metal_buserror *beu,
metal_buserror_event_t events,
bool enabled);
/*!
* @brief Enable or disable the hart-local interrupt
*
* @param beu The bus error unit handle
* @param event The error event which would trigger the interrupt
* @param enabled True if the interrupt should be enabled
* @return 0 upon success
*/
int metal_buserror_set_local_interrupt(struct metal_buserror *beu,
metal_buserror_event_t events,
bool enabled);
/*!
* @brief Get the error event which caused the most recent interrupt
*
* This method should be called from within the interrupt handler for the bus
* error unit interrupt
*
* @param beu The bus error unit handle
* @return The event which caused the interrupt
*/
metal_buserror_event_t metal_buserror_get_cause(struct metal_buserror *beu);
/*!
* @brief Clear the cause register for the bus error unit
*
* This method should be called from within the interrupt handler for the bus
* error unit to un-latch the cause register for the next event
*
* @param beu The bus error unit handle
* @return 0 upon success
*/
int metal_buserror_clear_cause(struct metal_buserror *beu);
/*!
* @brief Get the physical address of the error event
*
* This method should be called from within the interrupt handler for the bus
* error unit.
*
* @param beu The bus error unit handle
* @return The address of the error event
*/
uintptr_t metal_buserror_get_event_address(struct metal_buserror *beu);
/*!
* @brief Returns true if the event is set in the accrued register
*
* @param beu The bus error unit handle
* @param event The event to query
* @return True if the event is set in the accrued register
*/
bool metal_buserror_is_event_accrued(struct metal_buserror *beu,
metal_buserror_event_t events);
/*!
* @brief Clear the given event from the accrued register
*
* @param beu The bus error unit handle
* @param event The event to clear
* @return 0 upon success
*/
int metal_buserror_clear_event_accrued(struct metal_buserror *beu,
metal_buserror_event_t events);
/*!
* @brief get the platform-level interrupt parent of the bus error unit
*
* @param beu The bus error unit handle
* @return A pointer to the interrupt parent
*/
struct metal_interrupt *
metal_buserror_get_platform_interrupt_parent(struct metal_buserror *beu);
/*!
* @brief Get the platform-level interrupt id for the bus error unit interrupt
*
* @param beu The bus error unit handle
* @return The interrupt id
*/
int metal_buserror_get_platform_interrupt_id(struct metal_buserror *beu);
/*!
* @brief Get the hart-local interrupt id for the bus error unit interrupt
*
* @param beu The bus error unit handle
* @return The interrupt id
*/
int metal_buserror_get_local_interrupt_id(struct metal_buserror *beu);
#endif

View file

@ -0,0 +1,140 @@
/* Copyright 2020 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_CCACHE0_H
#define METAL__DRIVERS__SIFIVE_CCACHE0_H
/*!
* @file sifive_ccache0.h
*
* @brief API for configuring the SiFive L2 cache controller
*/
#include <metal/interrupt.h>
#include <stdint.h>
/*! @brief Cache configuration data */
typedef struct {
uint32_t num_bank;
uint32_t num_ways;
uint32_t num_sets;
uint32_t block_size;
} sifive_ccache0_config;
/*! @brief Set of values for ECC error type */
typedef enum {
SIFIVE_CCACHE0_DATA = 0,
SIFIVE_CCACHE0_DIR = 1,
} sifive_ccache0_ecc_errtype_t;
/*! @brief Initialize cache controller, enables all available
* cache-ways.
* Note: If LIM is in use, corresponding cache ways are not enabled.
* @param None.
* @return 0 If no error.*/
int sifive_ccache0_init(void);
/*! @brief Get cache configuration data.
* @param config User specified data buffer.
* @return None.*/
void sifive_ccache0_get_config(sifive_ccache0_config *config);
/*! @brief Get currently active cache ways.
* @param None.
* @return Number of cache ways enabled.*/
uint32_t sifive_ccache0_get_enabled_ways(void);
/*! @brief Enable specified cache ways.
* @param ways Number of ways to be enabled.
* @return 0 If no error.*/
int sifive_ccache0_set_enabled_ways(uint32_t ways);
/*! @brief Inject ECC error into data or meta-data.
* @param bitindex Bit index to be corrupted on next cache operation.
* @param type ECC error target location.
* @return None.*/
void sifive_ccache0_inject_ecc_error(uint32_t bitindex,
sifive_ccache0_ecc_errtype_t type);
/*! @brief Flush out entire cache block containing given address.
* @param flush_addr Address for the cache block to be flushed.
* @return None.*/
void sifive_ccache0_flush(uintptr_t flush_addr);
/*! @brief Get most recently ECC corrected address.
* @param type ECC error target location.
* @return Last corrected ECC address.*/
uintptr_t sifive_ccache0_get_ecc_fix_addr(sifive_ccache0_ecc_errtype_t type);
/*! @brief Get number of times ECC errors were corrected.
* Clears related ECC interrupt signals.
* @param type ECC error target location.
* @return Corrected ECC error count.*/
uint32_t sifive_ccache0_get_ecc_fix_count(sifive_ccache0_ecc_errtype_t type);
/*! @brief Get address location of most recent uncorrected ECC error.
* @param type ECC error target location.
* @return Last uncorrected ECC address.*/
uintptr_t sifive_ccache0_get_ecc_fail_addr(sifive_ccache0_ecc_errtype_t type);
/*! @brief Get number of times ECC errors were not corrected.
* Clears related ECC interrupt signals.
* @param type ECC error target location.
* @return Uncorrected ECC error count.*/
uint32_t sifive_ccache0_get_ecc_fail_count(sifive_ccache0_ecc_errtype_t type);
/*! @brief Get currently active way enable mask value for the given master ID.
* @param master_id Cache controller master ID.
* @return Way enable mask. */
uint64_t sifive_ccache0_get_way_mask(uint32_t master_id);
/*! @brief Set way enable mask for the given master ID.
* @param master_id Cache controller master ID.
* @param waymask Specify ways to be enabled.
* @return 0 If no error.*/
int sifive_ccache0_set_way_mask(uint32_t master_id, uint64_t waymask);
/*! @brief Select cache performance events to be counted.
* @param counter Cache performance monitor counter index.
* @param mask Event selection mask.
* @return None.*/
void sifive_ccache0_set_pmevent_selector(uint32_t counter, uint64_t mask);
/*! @brief Get currently set events for the given counter index.
* @param counter Cache performance monitor counter index.
* @return Event selection mask.*/
uint64_t sifive_ccache0_get_pmevent_selector(uint32_t counter);
/*! @brief Clears specified cache performance counter.
* @param counter Cache performance monitor counter index.
* @return None.*/
void sifive_ccache0_clr_pmevent_counter(uint32_t counter);
/*! @brief Reads specified cache performance counter.
* @param counter Cache performance monitor counter index.
* @return Counter value.*/
uint64_t sifive_ccache0_get_pmevent_counter(uint32_t counter);
/*! @brief Select cache clients to be excluded from performance monitoring.
* @param mask Client disable mask.
* @return None.*/
void sifive_ccache0_set_client_filter(uint64_t mask);
/*! @brief Get currently set cache client disable mask.
* @param None.
* @return Client disable mask.*/
uint64_t sifive_ccache0_get_client_filter(void);
/*! @brief Get interrupt IDs for the cache controller.
* @param src Interrupt trigger source index.
* @return Interrupt id.*/
int sifive_ccache0_get_interrupt_id(uint32_t src);
/*! @brief Get interrupt controller of the cache.
* The interrupt controller must be initialized before any interrupts can be
* registered or enabled with it.
* @param None.
* @return Handle for the interrupt controller.*/
struct metal_interrupt *sifive_ccache0_interrupt_controller(void);
#endif

View file

@ -7,21 +7,21 @@
#include <metal/compiler.h> #include <metal/compiler.h>
#include <metal/drivers/riscv_cpu.h> #include <metal/drivers/riscv_cpu.h>
#define METAL_CLIC_MAX_NMBITS 2 #define METAL_CLIC_MAX_NMBITS 2
#define METAL_CLIC_MAX_NLBITS 8 #define METAL_CLIC_MAX_NLBITS 8
#define METAL_CLIC_MAX_NVBITS 1 #define METAL_CLIC_MAX_NVBITS 1
#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MMODE 0x00 #define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MMODE 0x00
#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE1 0x20 #define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE1 0x20
#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE2 0x40 #define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE2 0x40
#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MASK 0x60 #define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MASK 0x60
#define METAL_SIFIVE_CLIC0_CLICCFG_NLBITS_MASK 0x1E #define METAL_SIFIVE_CLIC0_CLICCFG_NLBITS_MASK 0x1E
#define METAL_SIFIVE_CLIC0_CLICCFG_NVBIT_MASK 0x01 #define METAL_SIFIVE_CLIC0_CLICCFG_NVBIT_MASK 0x01
#define METAL_CLIC_ICTRL_SMODE1_MASK 0x7F /* b8 set imply M-mode */ #define METAL_CLIC_ICTRL_SMODE1_MASK 0x7F /* b8 set imply M-mode */
#define METAL_CLIC_ICTRL_SMODE2_MASK 0x3F /* b8 set M-mode, b7 clear U-mode */ #define METAL_CLIC_ICTRL_SMODE2_MASK 0x3F /* b8 set M-mode, b7 clear U-mode */
#define METAL_MAX_INTERRUPT_LEVEL ((1 << METAL_CLIC_MAX_NLBITS) - 1) #define METAL_MAX_INTERRUPT_LEVEL ((1 << METAL_CLIC_MAX_NLBITS) - 1)
struct __metal_driver_vtable_sifive_clic0 { struct __metal_driver_vtable_sifive_clic0 {
struct metal_interrupt_vtable clic_vtable; struct metal_interrupt_vtable clic_vtable;
@ -34,9 +34,15 @@ __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_clic0)
struct __metal_driver_sifive_clic0 { struct __metal_driver_sifive_clic0 {
struct metal_interrupt controller; struct metal_interrupt controller;
int init_done; int init_done;
metal_interrupt_handler_t metal_mtvt_table[__METAL_CLIC_SUBINTERRUPTS]; struct {
} __attribute__((aligned(64)));
metal_interrupt_vector_handler_t
metal_mtvt_table[__METAL_CLIC_SUBINTERRUPTS];
__metal_interrupt_data metal_exint_table[__METAL_CLIC_SUBINTERRUPTS]; __metal_interrupt_data metal_exint_table[__METAL_CLIC_SUBINTERRUPTS];
}; };
#undef __METAL_MACHINE_MACROS #undef __METAL_MACHINE_MACROS
int __metal_driver_sifive_clic0_command_request(
struct metal_interrupt *controller, int command, void *data);
#endif #endif

View file

@ -4,9 +4,9 @@
#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_HFROSC_H #ifndef METAL__DRIVERS__SIFIVE_FE310_G000_HFROSC_H
#define METAL__DRIVERS__SIFIVE_FE310_G000_HFROSC_H #define METAL__DRIVERS__SIFIVE_FE310_G000_HFROSC_H
#include <metal/drivers/sifive_fe310-g000_prci.h>
#include <metal/compiler.h>
#include <metal/clock.h> #include <metal/clock.h>
#include <metal/compiler.h>
#include <metal/drivers/sifive_fe310-g000_prci.h>
#include <metal/io.h> #include <metal/io.h>
struct __metal_driver_vtable_sifive_fe310_g000_hfrosc { struct __metal_driver_vtable_sifive_fe310_g000_hfrosc {

View file

@ -0,0 +1,21 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_LFROSC_H
#define METAL__DRIVERS__SIFIVE_FE310_G000_LFROSC_H
#include <metal/clock.h>
#include <metal/compiler.h>
#include <metal/io.h>
struct __metal_driver_vtable_sifive_fe310_g000_lfrosc {
struct __metal_clock_vtable clock;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_lfrosc)
struct __metal_driver_sifive_fe310_g000_lfrosc {
struct metal_clock clock;
};
#endif

View file

@ -10,14 +10,16 @@
struct __metal_driver_sifive_fe310_g000_prci; struct __metal_driver_sifive_fe310_g000_prci;
struct __metal_driver_vtable_sifive_fe310_g000_prci { struct __metal_driver_vtable_sifive_fe310_g000_prci {
long (*get_reg)(const struct __metal_driver_sifive_fe310_g000_prci *, long offset); long (*get_reg)(const struct __metal_driver_sifive_fe310_g000_prci *,
long (*set_reg)(const struct __metal_driver_sifive_fe310_g000_prci *, long offset, long value); long offset);
long (*set_reg)(const struct __metal_driver_sifive_fe310_g000_prci *,
long offset, long value);
}; };
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci) __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci)
struct __metal_driver_sifive_fe310_g000_prci { struct __metal_driver_sifive_fe310_g000_prci {
const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable;
}; };
#endif #endif

View file

@ -1,23 +0,0 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_FU540_C000_L2_H
#define METAL__DRIVERS__SIFIVE_FU540_C000_L2_H
struct __metal_driver_sifive_fu540_c000_l2;
#include <stdint.h>
#include <metal/cache.h>
struct __metal_driver_vtable_sifive_fu540_c000_l2 {
struct __metal_cache_vtable cache;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2)
struct __metal_driver_sifive_fu540_c000_l2 {
struct metal_cache cache;
};
#endif

View file

@ -4,12 +4,12 @@
#ifndef METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H #ifndef METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H
#define METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H #define METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H
#include <string.h>
#include <metal/button.h> #include <metal/button.h>
#include <metal/compiler.h> #include <metal/compiler.h>
#include <string.h>
struct __metal_driver_vtable_sifive_button { struct __metal_driver_vtable_sifive_button {
struct metal_button_vtable button_vtable; struct metal_button_vtable button_vtable;
}; };
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_button) __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_button)

View file

@ -4,12 +4,12 @@
#ifndef METAL__DRIVERS__SIFIVE_GPIO_LEDS_H #ifndef METAL__DRIVERS__SIFIVE_GPIO_LEDS_H
#define METAL__DRIVERS__SIFIVE_GPIO_LEDS_H #define METAL__DRIVERS__SIFIVE_GPIO_LEDS_H
#include <metal/compiler.h>
#include <metal/drivers/sifive_gpio0.h> #include <metal/drivers/sifive_gpio0.h>
#include <metal/led.h> #include <metal/led.h>
#include <metal/compiler.h>
struct __metal_driver_vtable_sifive_led { struct __metal_driver_vtable_sifive_led {
struct metal_led_vtable led_vtable; struct metal_led_vtable led_vtable;
}; };
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_led) __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_led)

View file

@ -4,12 +4,12 @@
#ifndef METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H #ifndef METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H
#define METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H #define METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H
#include <metal/compiler.h>
#include <metal/drivers/sifive_gpio0.h> #include <metal/drivers/sifive_gpio0.h>
#include <metal/switch.h> #include <metal/switch.h>
#include <metal/compiler.h>
struct __metal_driver_vtable_sifive_switch { struct __metal_driver_vtable_sifive_switch {
struct metal_switch_vtable switch_vtable; struct metal_switch_vtable switch_vtable;
}; };
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_switch) __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_switch)

View file

@ -11,7 +11,7 @@ struct __metal_driver_vtable_sifive_gpio0 {
const struct __metal_gpio_vtable gpio; const struct __metal_gpio_vtable gpio;
}; };
//struct __metal_driver_sifive_gpio0; // struct __metal_driver_sifive_gpio0;
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_gpio0) __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_gpio0)

View file

@ -0,0 +1,24 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_I2C0_H
#define METAL__DRIVERS__SIFIVE_I2C0_H
#include <metal/clock.h>
#include <metal/i2c.h>
struct __metal_driver_vtable_sifive_i2c0 {
const struct metal_i2c_vtable i2c;
};
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_i2c0)
struct __metal_driver_sifive_i2c0 {
struct metal_i2c i2c;
unsigned int init_done;
unsigned int baud_rate;
metal_clock_callback pre_rate_change_callback;
metal_clock_callback post_rate_change_callback;
};
#endif

View file

@ -0,0 +1,78 @@
/* Copyright 2020 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_L2PF0_H
#define METAL__DRIVERS__SIFIVE_L2PF0_H
/*!
* @file sifive_l2pf0.h
*
* @brief API for configuring the SiFive L2 prefetcher.
*/
#include <stdint.h>
/*! @brief L2 prefetcher configuration */
typedef struct {
/* Enable L2 hardware prefetcher */
uint8_t HwPrefetchEnable;
/* Only works when CrossPageEn === 0.
Cross Page optimization disable:
0 -> Entry goes into Pause state while crossing Page boundary.
Next time when the demand miss happens on the same page, it doesnt need
to train again. 1 -> The entry is invalidated in case of a cross page. */
uint8_t CrossPageOptmDisable;
/* Enable prefetches to cross pages */
uint8_t CrossPageEn;
/* Age-out mechanism enable */
uint8_t AgeOutEn;
uint32_t PrefetchDistance;
uint32_t MaxAllowedDistance;
/* Linear to exponential threshold */
uint32_t LinToExpThreshold;
/* No. of non-matching loads to edge out an entry */
uint32_t NumLdsToAgeOut;
/* Threshold no. of Fullness (L2 MSHRs used/ total available) to stop
* sending hits */
uint32_t QFullnessThreshold;
/* Threshold no. of CacheHits for evicting SPF entry */
uint32_t HitCacheThreshold;
/* Threshold no. of MSHR hits for increasing SPF distance */
uint32_t hitMSHRThreshold;
/* Size of the comparison window for address matching */
uint32_t Window;
} sifive_l2pf0_config;
/*! @brief Enable L2 hardware prefetcher unit.
* @param None.
* @return None.*/
void sifive_l2pf0_enable(void);
/*! @brief Disable L2 hardware prefetcher unit.
* @param None.
* @return None.*/
void sifive_l2pf0_disable(void);
/*! @brief Get currently active L2 prefetcher configuration.
* @param config Pointer to user specified configuration structure.
* @return None.*/
void sifive_l2pf0_get_config(sifive_l2pf0_config *config);
/*! @brief Enables fine grain access to L2 prefetcher configuration.
* @param config Pointer to user structure with values to be set.
* @return None.*/
void sifive_l2pf0_set_config(sifive_l2pf0_config *config);
#endif

View file

@ -18,5 +18,4 @@ struct __metal_driver_sifive_local_external_interrupts0 {
int init_done; int init_done;
}; };
#endif #endif

View file

@ -0,0 +1,29 @@
/* Copyright 2020 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_PWM0_H
#define METAL__DRIVERS__SIFIVE_PWM0_H
#include <metal/clock.h>
#include <metal/pwm.h>
struct __metal_driver_vtable_sifive_pwm0 {
const struct metal_pwm_vtable pwm;
};
/* Max possible PWM channel count */
#define METAL_MAX_PWM_CHANNELS 16
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_pwm0)
struct __metal_driver_sifive_pwm0 {
struct metal_pwm pwm;
unsigned int max_count;
unsigned int count_val;
unsigned int freq;
unsigned int duty[METAL_MAX_PWM_CHANNELS];
metal_clock_callback pre_rate_change_callback;
metal_clock_callback post_rate_change_callback;
};
#endif

View file

@ -0,0 +1,26 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_RTC0_H
#define METAL__DRIVERS__SIFIVE_RTC0_H
#include <metal/compiler.h>
#include <metal/io.h>
#include <metal/clock.h>
#include <metal/interrupt.h>
#include <metal/rtc.h>
struct __metal_driver_vtable_sifive_rtc0 {
const struct metal_rtc_vtable rtc;
};
struct __metal_driver_sifive_rtc0;
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_rtc0)
struct __metal_driver_sifive_rtc0 {
const struct metal_rtc rtc;
};
#endif

View file

@ -0,0 +1,29 @@
/* Copyright 2020 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_SIMUART0_H
#define METAL__DRIVERS__SIFIVE_SIMUART0_H
#include <metal/clock.h>
#include <metal/compiler.h>
#include <metal/drivers/riscv_plic0.h>
#include <metal/drivers/sifive_gpio0.h>
#include <metal/io.h>
#include <metal/uart.h>
struct __metal_driver_vtable_sifive_simuart0 {
const struct metal_uart_vtable uart;
};
struct __metal_driver_sifive_simuart0;
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_simuart0)
struct __metal_driver_sifive_simuart0 {
struct metal_uart uart;
unsigned long baud_rate;
metal_clock_callback pre_rate_change_callback;
metal_clock_callback post_rate_change_callback;
};
#endif

View file

@ -4,9 +4,9 @@
#ifndef METAL__DRIVERS__SIFIVE_SPI0_H #ifndef METAL__DRIVERS__SIFIVE_SPI0_H
#define METAL__DRIVERS__SIFIVE_SPI0_H #define METAL__DRIVERS__SIFIVE_SPI0_H
#include <metal/drivers/sifive_gpio0.h>
#include <metal/clock.h> #include <metal/clock.h>
#include <metal/compiler.h> #include <metal/compiler.h>
#include <metal/drivers/sifive_gpio0.h>
#include <metal/io.h> #include <metal/io.h>
#include <metal/spi.h> #include <metal/spi.h>
@ -19,6 +19,8 @@ __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_spi0)
struct __metal_driver_sifive_spi0 { struct __metal_driver_sifive_spi0 {
struct metal_spi spi; struct metal_spi spi;
unsigned long baud_rate; unsigned long baud_rate;
metal_clock_callback pre_rate_change_callback;
metal_clock_callback post_rate_change_callback;
}; };
#endif #endif

View file

@ -17,5 +17,4 @@ struct __metal_driver_sifive_test0 {
struct __metal_shutdown shutdown; struct __metal_shutdown shutdown;
}; };
#endif #endif

View file

@ -0,0 +1,23 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_TRACE_H
#define METAL__DRIVERS__SIFIVE_TRACE_H
#include <metal/compiler.h>
#include <metal/io.h>
#include <metal/uart.h>
struct __metal_driver_vtable_sifive_trace {
const struct metal_uart_vtable uart;
};
struct __metal_driver_sifive_trace;
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_trace)
struct __metal_driver_sifive_trace {
struct metal_uart uart;
};
#endif /* METAL__DRIVERS__SIFIVE_TRACE_H */

View file

@ -4,12 +4,12 @@
#ifndef METAL__DRIVERS__SIFIVE_UART0_H #ifndef METAL__DRIVERS__SIFIVE_UART0_H
#define METAL__DRIVERS__SIFIVE_UART0_H #define METAL__DRIVERS__SIFIVE_UART0_H
#include <metal/drivers/sifive_gpio0.h>
#include <metal/drivers/riscv_plic0.h>
#include <metal/clock.h> #include <metal/clock.h>
#include <metal/compiler.h>
#include <metal/drivers/riscv_plic0.h>
#include <metal/drivers/sifive_gpio0.h>
#include <metal/io.h> #include <metal/io.h>
#include <metal/uart.h> #include <metal/uart.h>
#include <metal/compiler.h>
struct __metal_driver_vtable_sifive_uart0 { struct __metal_driver_vtable_sifive_uart0 {
const struct metal_uart_vtable uart; const struct metal_uart_vtable uart;
@ -22,7 +22,8 @@ __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_uart0)
struct __metal_driver_sifive_uart0 { struct __metal_driver_sifive_uart0 {
struct metal_uart uart; struct metal_uart uart;
unsigned long baud_rate; unsigned long baud_rate;
metal_clock_callback pre_rate_change_callback;
metal_clock_callback post_rate_change_callback;
}; };
#endif #endif

View file

@ -0,0 +1,26 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__SIFIVE_WDOG0_H
#define METAL__DRIVERS__SIFIVE_WDOG0_H
#include <metal/compiler.h>
#include <metal/io.h>
#include <metal/clock.h>
#include <metal/interrupt.h>
#include <metal/watchdog.h>
struct __metal_driver_vtable_sifive_wdog0 {
const struct metal_watchdog_vtable watchdog;
};
struct __metal_driver_sifive_wdog0;
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_wdog0)
struct __metal_driver_sifive_wdog0 {
const struct metal_watchdog watchdog;
};
#endif

View file

@ -0,0 +1,48 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__DRIVERS__UCB_HTIF0_H
#define METAL__DRIVERS__UCB_HTIF0_H
#include <metal/compiler.h>
#include <metal/shutdown.h>
#include <metal/uart.h>
struct __metal_driver_vtable_ucb_htif0_shutdown {
const struct __metal_shutdown_vtable shutdown;
};
struct __metal_driver_vtable_ucb_htif0_uart {
const struct metal_uart_vtable uart;
};
struct __metal_driver_ucb_htif0;
void __metal_driver_ucb_htif0_exit(const struct __metal_shutdown *test,
int code) __attribute__((noreturn));
void __metal_driver_ucb_htif0_init(struct metal_uart *uart, int baud_rate);
int __metal_driver_ucb_htif0_putc(struct metal_uart *uart, int c);
int __metal_driver_ucb_htif0_getc(struct metal_uart *uart, int *c);
int __metal_driver_ucb_htif0_get_baud_rate(struct metal_uart *guart);
int __metal_driver_ucb_htif0_set_baud_rate(struct metal_uart *guart,
int baud_rate);
struct metal_interrupt *
__metal_driver_ucb_htif0_interrupt_controller(struct metal_uart *uart);
int __metal_driver_ucb_htif0_get_interrupt_id(struct metal_uart *uart);
__METAL_DECLARE_VTABLE(__metal_driver_vtable_ucb_htif0_shutdown)
__METAL_DECLARE_VTABLE(__metal_driver_vtable_ucb_htif0_uart)
struct __metal_driver_ucb_htif0_shutdown {
struct __metal_shutdown shutdown;
const struct __metal_driver_vtable_ucb_htif0_shutdown *vtable;
};
struct __metal_driver_ucb_htif0_uart {
struct metal_uart uart;
const struct __metal_driver_vtable_ucb_htif0_uart *vtable;
};
#endif

View file

@ -5,6 +5,7 @@
#define METAL__GPIO_H #define METAL__GPIO_H
#include <metal/compiler.h> #include <metal/compiler.h>
#include <metal/interrupt.h>
/*! /*!
* @file gpio.h * @file gpio.h
@ -15,20 +16,37 @@ struct metal_gpio;
struct __metal_gpio_vtable { struct __metal_gpio_vtable {
int (*disable_input)(struct metal_gpio *, long pins); int (*disable_input)(struct metal_gpio *, long pins);
int (*enable_input)(struct metal_gpio *, long pins);
long (*input)(struct metal_gpio *);
long (*output)(struct metal_gpio *); long (*output)(struct metal_gpio *);
int (*disable_output)(struct metal_gpio *, long pins);
int (*enable_output)(struct metal_gpio *, long pins); int (*enable_output)(struct metal_gpio *, long pins);
int (*output_set)(struct metal_gpio *, long value); int (*output_set)(struct metal_gpio *, long value);
int (*output_clear)(struct metal_gpio *, long value); int (*output_clear)(struct metal_gpio *, long value);
int (*output_toggle)(struct metal_gpio *, long value); int (*output_toggle)(struct metal_gpio *, long value);
int (*enable_io)(struct metal_gpio *, long pins, long dest); int (*enable_io)(struct metal_gpio *, long pins, long dest);
int (*disable_io)(struct metal_gpio *, long pins);
int (*config_int)(struct metal_gpio *, long pins, int intr_type);
int (*clear_int)(struct metal_gpio *, long pins, int intr_type);
struct metal_interrupt *(*interrupt_controller)(struct metal_gpio *gpio);
int (*get_interrupt_id)(struct metal_gpio *gpio, int pin);
}; };
#define METAL_GPIO_INT_DISABLE 0
#define METAL_GPIO_INT_RISING 1
#define METAL_GPIO_INT_FALLING 2
#define METAL_GPIO_INT_BOTH_EDGE 3
#define METAL_GPIO_INT_LOW 4
#define METAL_GPIO_INT_HIGH 5
#define METAL_GPIO_INT_BOTH_LEVEL 6
#define METAL_GPIO_INT_MAX 7
/*! /*!
* @struct metal_gpio * @struct metal_gpio
* @brief The handle for a GPIO interface * @brief The handle for a GPIO interface
*/ */
struct metal_gpio { struct metal_gpio {
const struct __metal_gpio_vtable *vtable; const struct __metal_gpio_vtable *vtable;
}; };
/*! /*!
@ -36,7 +54,21 @@ struct metal_gpio {
* @param device_num The GPIO device index * @param device_num The GPIO device index
* @return The GPIO device handle, or NULL if there is no device at that index * @return The GPIO device handle, or NULL if there is no device at that index
*/ */
struct metal_gpio *metal_gpio_get_device(int device_num); struct metal_gpio *metal_gpio_get_device(unsigned int device_num);
/*!
* @brief enable input on a pin
* @param gpio The handle for the GPIO interface
* @param pin The pin number indexed from 0
* @return 0 if the input is successfully enabled
*/
__inline__ int metal_gpio_enable_input(struct metal_gpio *gpio, int pin) {
if (!gpio) {
return 1;
}
return gpio->vtable->enable_input(gpio, (1 << pin));
}
/*! /*!
* @brief Disable input on a pin * @brief Disable input on a pin
@ -44,9 +76,9 @@ struct metal_gpio *metal_gpio_get_device(int device_num);
* @param pin The pin number indexed from 0 * @param pin The pin number indexed from 0
* @return 0 if the input is successfully disabled * @return 0 if the input is successfully disabled
*/ */
inline int metal_gpio_disable_input(struct metal_gpio *gpio, int pin) { __inline__ int metal_gpio_disable_input(struct metal_gpio *gpio, int pin) {
if(!gpio) { if (!gpio) {
return 1; return 1;
} }
return gpio->vtable->disable_input(gpio, (1 << pin)); return gpio->vtable->disable_input(gpio, (1 << pin));
@ -58,14 +90,28 @@ inline int metal_gpio_disable_input(struct metal_gpio *gpio, int pin) {
* @param pin The pin number indexed from 0 * @param pin The pin number indexed from 0
* @return 0 if the output is successfully enabled * @return 0 if the output is successfully enabled
*/ */
inline int metal_gpio_enable_output(struct metal_gpio *gpio, int pin) { __inline__ int metal_gpio_enable_output(struct metal_gpio *gpio, int pin) {
if(!gpio) { if (!gpio) {
return 1; return 1;
} }
return gpio->vtable->enable_output(gpio, (1 << pin)); return gpio->vtable->enable_output(gpio, (1 << pin));
} }
/*!
* @brief Disable output on a pin
* @param gpio The handle for the GPIO interface
* @param pin The pin number indexed from 0
* @return 0 if the output is successfully disabled
*/
__inline__ int metal_gpio_disable_output(struct metal_gpio *gpio, int pin) {
if (!gpio) {
return 1;
}
return gpio->vtable->disable_output(gpio, (1 << pin));
}
/*! /*!
* @brief Set the output value of a GPIO pin * @brief Set the output value of a GPIO pin
* @param gpio The handle for the GPIO interface * @param gpio The handle for the GPIO interface
@ -73,15 +119,15 @@ inline int metal_gpio_enable_output(struct metal_gpio *gpio, int pin) {
* @param value The value to set the pin to * @param value The value to set the pin to
* @return 0 if the output is successfully set * @return 0 if the output is successfully set
*/ */
inline int metal_gpio_set_pin(struct metal_gpio *gpio, int pin, int value) { __inline__ int metal_gpio_set_pin(struct metal_gpio *gpio, int pin, int value) {
if(!gpio) { if (!gpio) {
return 1; return 1;
} }
if(value == 0) { if (value == 0) {
return gpio->vtable->output_clear(gpio, (1 << pin)); return gpio->vtable->output_clear(gpio, (1 << pin));
} else { } else {
return gpio->vtable->output_set(gpio, (1 << pin)); return gpio->vtable->output_set(gpio, (1 << pin));
} }
} }
@ -91,17 +137,37 @@ inline int metal_gpio_set_pin(struct metal_gpio *gpio, int pin, int value) {
* @param pin The pin number indexed from 0 * @param pin The pin number indexed from 0
* @return The value of the GPIO pin * @return The value of the GPIO pin
*/ */
inline int metal_gpio_get_pin(struct metal_gpio *gpio, int pin) { __inline__ int metal_gpio_get_input_pin(struct metal_gpio *gpio, int pin) {
if(!gpio) { if (!gpio) {
return 0; return 0;
}
long value = gpio->vtable->input(gpio);
if (value & (1 << pin)) {
return 1;
} else {
return 0;
}
}
/*!
* @brief Get the value of the GPIO pin
* @param gpio The handle for the GPIO interface
* @param pin The pin number indexed from 0
* @return The value of the GPIO pin
*/
__inline__ int metal_gpio_get_output_pin(struct metal_gpio *gpio, int pin) {
if (!gpio) {
return 0;
} }
long value = gpio->vtable->output(gpio); long value = gpio->vtable->output(gpio);
if(value & (1 << pin)) { if (value & (1 << pin)) {
return 1; return 1;
} else { } else {
return 0; return 0;
} }
} }
@ -111,9 +177,9 @@ inline int metal_gpio_get_pin(struct metal_gpio *gpio, int pin) {
* @param pin The pin number indexed from 0 * @param pin The pin number indexed from 0
* @return 0 if the pin is successfully cleared * @return 0 if the pin is successfully cleared
*/ */
inline int metal_gpio_clear_pin(struct metal_gpio *gpio, int pin) { __inline__ int metal_gpio_clear_pin(struct metal_gpio *gpio, int pin) {
if(!gpio) { if (!gpio) {
return 1; return 1;
} }
return gpio->vtable->output_clear(gpio, (1 << pin)); return gpio->vtable->output_clear(gpio, (1 << pin));
@ -125,9 +191,9 @@ inline int metal_gpio_clear_pin(struct metal_gpio *gpio, int pin) {
* @param pin The pin number indexed from 0 * @param pin The pin number indexed from 0
* @return 0 if the pin is successfully toggled * @return 0 if the pin is successfully toggled
*/ */
inline int metal_gpio_toggle_pin(struct metal_gpio *gpio, int pin) { __inline__ int metal_gpio_toggle_pin(struct metal_gpio *gpio, int pin) {
if(!gpio) { if (!gpio) {
return 1; return 1;
} }
return gpio->vtable->output_toggle(gpio, (1 << pin)); return gpio->vtable->output_toggle(gpio, (1 << pin));
@ -140,12 +206,82 @@ inline int metal_gpio_toggle_pin(struct metal_gpio *gpio, int pin) {
* @param io_function The IO function to set * @param io_function The IO function to set
* @return 0 if the pinmux is successfully set * @return 0 if the pinmux is successfully set
*/ */
inline int metal_gpio_enable_pinmux(struct metal_gpio *gpio, int pin, int io_function) { __inline__ int metal_gpio_enable_pinmux(struct metal_gpio *gpio, int pin,
if(!gpio) { int io_function) {
return 1; if (!gpio) {
return 1;
} }
return gpio->vtable->enable_io(gpio, (1 << pin), (io_function << pin)); return gpio->vtable->enable_io(gpio, (1 << pin), (io_function << pin));
} }
/*!
* @brief Disables the pinmux for a GPIO pin
* @param gpio The handle for the GPIO interface
* @param pin The bitmask for the pin to disable pinmux on
* @return 0 if the pinmux is successfully set
*/
__inline__ int metal_gpio_disable_pinmux(struct metal_gpio *gpio, int pin) {
if (!gpio) {
return 1;
}
return gpio->vtable->disable_io(gpio, (1 << pin));
}
/*!
* @brief Config gpio interrupt type
* @param gpio The handle for the GPIO interface
* @param pin The bitmask for the pin to enable gpio interrupt
* @param intr_type The interrupt type
* @return 0 if the interrupt mode is setup properly
*/
__inline__ int metal_gpio_config_interrupt(struct metal_gpio *gpio, int pin,
int intr_type) {
if (!gpio) {
return 1;
}
return gpio->vtable->config_int(gpio, (1 << pin), intr_type);
}
/*!
* @brief Clear gpio interrupt status
* @param gpio The handle for the GPIO interface
* @param pin The bitmask for the pin to clear gpio interrupt
* @param intr_type The interrupt type to be clear
* @return 0 if the interrupt is cleared
*/
__inline__ int metal_gpio_clear_interrupt(struct metal_gpio *gpio, int pin,
int intr_type) {
if (!gpio) {
return 1;
}
return gpio->vtable->clear_int(gpio, (1 << pin), intr_type);
}
/*!
* @brief Get the interrupt controller for a gpio
*
* @param gpio The handle for the gpio
* @return A pointer to the interrupt controller responsible for handling
* gpio interrupts.
*/
__inline__ struct metal_interrupt *
metal_gpio_interrupt_controller(struct metal_gpio *gpio) {
return gpio->vtable->interrupt_controller(gpio);
}
/*!
* @brief Get the interrupt id for a gpio
*
* @param gpio The handle for the gpio
* @param pin The bitmask for the pin to get gpio interrupt id
* @return The interrupt id corresponding to a gpio.
*/
__inline__ int metal_gpio_get_interrupt_id(struct metal_gpio *gpio, int pin) {
return gpio->vtable->get_interrupt_id(gpio, pin);
}
#endif #endif

View file

@ -0,0 +1,146 @@
/* Copyright 2020 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__HPM_H
#define METAL__HPM_H
#include <metal/cpu.h>
/*! @brief Macros for valid Event IDs */
#define METAL_HPM_EVENTID_8 (1UL << 8)
#define METAL_HPM_EVENTID_9 (1UL << 9)
#define METAL_HPM_EVENTID_10 (1UL << 10)
#define METAL_HPM_EVENTID_11 (1UL << 11)
#define METAL_HPM_EVENTID_12 (1UL << 12)
#define METAL_HPM_EVENTID_13 (1UL << 13)
#define METAL_HPM_EVENTID_14 (1UL << 14)
#define METAL_HPM_EVENTID_15 (1UL << 15)
#define METAL_HPM_EVENTID_16 (1UL << 16)
#define METAL_HPM_EVENTID_17 (1UL << 17)
#define METAL_HPM_EVENTID_18 (1UL << 18)
#define METAL_HPM_EVENTID_19 (1UL << 19)
#define METAL_HPM_EVENTID_20 (1UL << 20)
#define METAL_HPM_EVENTID_21 (1UL << 21)
#define METAL_HPM_EVENTID_22 (1UL << 22)
#define METAL_HPM_EVENTID_23 (1UL << 23)
#define METAL_HPM_EVENTID_24 (1UL << 24)
#define METAL_HPM_EVENTID_25 (1UL << 25)
#define METAL_HPM_EVENTID_26 (1UL << 26)
#define METAL_HPM_EVENTID_27 (1UL << 27)
#define METAL_HPM_EVENTID_28 (1UL << 28)
#define METAL_HPM_EVENTID_29 (1UL << 29)
#define METAL_HPM_EVENTID_30 (1UL << 30)
#define METAL_HPM_EVENTID_31 (1UL << 31)
/*! @brief Macros for valid Event Class */
#define METAL_HPM_EVENTCLASS_0 (0UL)
#define METAL_HPM_EVENTCLASS_1 (1UL)
#define METAL_HPM_EVENTCLASS_2 (2UL)
#define METAL_HPM_EVENTCLASS_3 (3UL)
#define METAL_HPM_EVENTCLASS_4 (4UL)
#define METAL_HPM_EVENTCLASS_5 (5UL)
#define METAL_HPM_EVENTCLASS_6 (6UL)
#define METAL_HPM_EVENTCLASS_7 (7UL)
#define METAL_HPM_EVENTCLASS_8 (8UL)
/*! @brief Enums for available HPM counters */
typedef enum {
METAL_HPM_CYCLE = 0,
METAL_HPM_TIME = 1,
METAL_HPM_INSTRET = 2,
METAL_HPM_COUNTER_3 = 3,
METAL_HPM_COUNTER_4 = 4,
METAL_HPM_COUNTER_5 = 5,
METAL_HPM_COUNTER_6 = 6,
METAL_HPM_COUNTER_7 = 7,
METAL_HPM_COUNTER_8 = 8,
METAL_HPM_COUNTER_9 = 9,
METAL_HPM_COUNTER_10 = 10,
METAL_HPM_COUNTER_11 = 11,
METAL_HPM_COUNTER_12 = 12,
METAL_HPM_COUNTER_13 = 13,
METAL_HPM_COUNTER_14 = 14,
METAL_HPM_COUNTER_15 = 15,
METAL_HPM_COUNTER_16 = 16,
METAL_HPM_COUNTER_17 = 17,
METAL_HPM_COUNTER_18 = 18,
METAL_HPM_COUNTER_19 = 19,
METAL_HPM_COUNTER_20 = 20,
METAL_HPM_COUNTER_21 = 21,
METAL_HPM_COUNTER_22 = 22,
METAL_HPM_COUNTER_23 = 23,
METAL_HPM_COUNTER_24 = 24,
METAL_HPM_COUNTER_25 = 25,
METAL_HPM_COUNTER_26 = 26,
METAL_HPM_COUNTER_27 = 27,
METAL_HPM_COUNTER_28 = 28,
METAL_HPM_COUNTER_29 = 29,
METAL_HPM_COUNTER_30 = 30,
METAL_HPM_COUNTER_31 = 31
} metal_hpm_counter;
/*! @brief Initialize hardware performance monitor counters.
* @param cpu The CPU device handle.
* @return 0 If no error.*/
int metal_hpm_init(struct metal_cpu *cpu);
/*! @brief Disables hardware performance monitor counters.
* Note - Disabled HPM counters may reduce power consumption.
* @param cpu The CPU device handle.
* @return 0 If no error.*/
int metal_hpm_disable(struct metal_cpu *cpu);
/*! @brief Set events which will cause the specified counter to increment.
* Counter will start incrementing from the moment events are set.
* @param cpu The CPU device handle.
* @param counter Hardware counter to be incremented by selected events.
* @param bitmask Bit-mask to select events for a particular counter,
* refer core reference manual for selection of events.
* Event bit mask is partitioned as follows:
* [XLEN-1:8] - Event selection mask [7:0] - Event class
* @return 0 If no error.*/
int metal_hpm_set_event(struct metal_cpu *cpu, metal_hpm_counter counter,
unsigned int bitmask);
/*! @brief Get events selection mask set for specified counter.
* @param cpu The CPU device handle.
* @param counter Hardware counter.
* @return Event selection bit mask. refer core reference manual for details.*/
unsigned int metal_hpm_get_event(struct metal_cpu *cpu,
metal_hpm_counter counter);
/*! @brief Clear event selector bits as per specified bit-mask.
* @param cpu The CPU device handle.
* @param counter Hardware counter.
* @return 0 If no error.*/
int metal_hpm_clr_event(struct metal_cpu *cpu, metal_hpm_counter counter,
unsigned int bitmask);
/*! @brief Enable counter access to next lower privilege mode.
* @param cpu The CPU device handle.
* @param counter Hardware counter.
* @return 0 If no error.*/
int metal_hpm_enable_access(struct metal_cpu *cpu, metal_hpm_counter counter);
/*! @brief Disable counter access to next lower privilege mode.
* @param cpu The CPU device handle.
* @param counter Hardware counter.
* @return 0 If no error.*/
int metal_hpm_disable_access(struct metal_cpu *cpu, metal_hpm_counter counter);
/*! @brief Reads current value of specified hardware counter.
* Note: 'mtime' register is memory mapped into CLINT block.
* Use CLINT APIs to access this register.
* @param cpu The CPU device handle.
* @param counter Hardware counter.
* @return Current value of hardware counter on success, 0 on failure.*/
unsigned long long metal_hpm_read_counter(struct metal_cpu *cpu,
metal_hpm_counter counter);
/*! @brief Clears off specified counter.
* @param cpu The CPU device handle.
* @param counter Hardware counter.
* @return 0 If no error.*/
int metal_hpm_clear_counter(struct metal_cpu *cpu, metal_hpm_counter counter);
#endif

View file

@ -0,0 +1,112 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__I2C_H
#define METAL__I2C_H
/*! @brief Enums to enable/disable stop condition. */
typedef enum {
METAL_I2C_STOP_DISABLE = 0,
METAL_I2C_STOP_ENABLE = 1
} metal_i2c_stop_bit_t;
/*! @brief Enums to set up I2C device modes. */
typedef enum { METAL_I2C_SLAVE = 0, METAL_I2C_MASTER = 1 } metal_i2c_mode_t;
struct metal_i2c;
struct metal_i2c_vtable {
void (*init)(struct metal_i2c *i2c, unsigned int baud_rate,
metal_i2c_mode_t mode);
int (*write)(struct metal_i2c *i2c, unsigned int addr, unsigned int len,
unsigned char buf[], metal_i2c_stop_bit_t stop_bit);
int (*read)(struct metal_i2c *i2c, unsigned int addr, unsigned int len,
unsigned char buf[], metal_i2c_stop_bit_t stop_bit);
int (*transfer)(struct metal_i2c *i2c, unsigned int addr,
unsigned char txbuf[], unsigned int txlen,
unsigned char rxbuf[], unsigned int rxlen);
int (*get_baud_rate)(struct metal_i2c *i2c);
int (*set_baud_rate)(struct metal_i2c *i2c, unsigned int baud_rate);
};
/*! @brief A handle for a I2C device. */
struct metal_i2c {
const struct metal_i2c_vtable *vtable;
};
/*! @brief Get a handle for a I2C device.
* @param device_num The index of the desired I2C device.
* @return A handle to the I2C device, or NULL if the device does not exist.*/
struct metal_i2c *metal_i2c_get_device(unsigned int device_num);
/*! @brief Initialize a I2C device with a certain baud rate.
* @param i2c The handle for the I2C device to initialize.
* @param baud_rate The baud rate for the I2C device to operate at.
* @param mode I2C operation mode.
*/
inline void metal_i2c_init(struct metal_i2c *i2c, unsigned int baud_rate,
metal_i2c_mode_t mode) {
i2c->vtable->init(i2c, baud_rate, mode);
}
/*! @brief Perform a I2C write.
* @param i2c The handle for the I2C device to perform the write operation.
* @param addr The I2C slave address for the write operation.
* @param len The number of bytes to transfer.
* @param buf The buffer to send over the I2C bus. Must be len bytes long.
* @param stop_bit Enable / Disable STOP condition.
* @return 0 if the write succeeds.
*/
inline int metal_i2c_write(struct metal_i2c *i2c, unsigned int addr,
unsigned int len, unsigned char buf[],
metal_i2c_stop_bit_t stop_bit) {
return i2c->vtable->write(i2c, addr, len, buf, stop_bit);
}
/*! @brief Perform a I2C read.
* @param i2c The handle for the I2C device to perform the read operation.
* @param addr The I2C slave address for the read operation.
* @param len The number of bytes to transfer.
* @param buf The buffer to store data from I2C bus. Must be len bytes long.
* @param stop_bit Enable / Disable STOP condition.
* @return 0 if the read succeeds.
*/
inline int metal_i2c_read(struct metal_i2c *i2c, unsigned int addr,
unsigned int len, unsigned char buf[],
metal_i2c_stop_bit_t stop_bit) {
return i2c->vtable->read(i2c, addr, len, buf, stop_bit);
}
/*! @brief Performs back to back I2C write and read operations.
* @param i2c The handle for the I2C device to perform the transfer operation.
* @param addr The I2C slave address for the transfer operation.
* @param txbuf The data buffer to be transmitted over I2C bus.
* @param txlen The number of bytes to write over I2C.
* @param rxbuf The buffer to store data received over I2C bus.
* @param rxlen The number of bytes to read over I2C.
* @return 0 if the transfer succeeds.
*/
inline int metal_i2c_transfer(struct metal_i2c *i2c, unsigned int addr,
unsigned char txbuf[], unsigned int txlen,
unsigned char rxbuf[], unsigned int rxlen) {
return i2c->vtable->transfer(i2c, addr, txbuf, txlen, rxbuf, rxlen);
}
/*! @brief Get the current baud rate of the I2C device.
* @param i2c The handle for the I2C device.
* @return The baud rate in Hz.
*/
inline int metal_i2c_get_baud_rate(struct metal_i2c *i2c) {
return i2c->vtable->get_baud_rate(i2c);
}
/*! @brief Set the current baud rate of the I2C device.
* @param i2c The handle for the I2C device.
* @param baud_rate The desired baud rate of the I2C device.
* @return 0 If the baud rate is successfully changed.
*/
inline int metal_i2c_set_baud_rate(struct metal_i2c *i2c, int baud_rate) {
return i2c->vtable->set_baud_rate(i2c, baud_rate);
}
#endif

View file

@ -0,0 +1,130 @@
/* Copyright 2019 SiFive Inc. */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL_INIT
#define METAL_INIT
/*!
* @file init.h
* API for Metal constructors and destructors
*/
typedef void (*metal_constructor_t)(void);
typedef void (*metal_destructor_t)(void);
#define METAL_INIT_HIGHEST_PRIORITY 0
#define METAL_INIT_DEFAULT_PRIORITY 5000
#define METAL_INIT_LOWEST_PRIORITY 9999
/*! @def METAL_CONSTRUCTOR
* @brief Define a Metal constructor
*
* Functions defined with METAL_CONSTRUCTOR will be added to the list of
* Metal constructors. By default, these functions are called before main by
* the metal_init() function.
*/
#define METAL_CONSTRUCTOR(function_name) \
METAL_CONSTRUCTOR_PRIO(function_name, METAL_INIT_DEFAULT_PRIORITY)
/*! @def METAL_CONSTRUCTOR_PRIO
* @brief Define a Metal constructor with a given priority
*
* The priority argument should be an integer between 0 and 9999, where 0
* is the highest priority (runs first) and 9999 is the lowest priority
* (runs last).
*
* Functions defined with METAL_CONSTRUCTOR_PRIO will be added to the list of
* Metal constructors. By default, these functions are called before main by
* the metal_init() function.
*/
#define METAL_CONSTRUCTOR_PRIO(function_name, priority) \
__METAL_CONSTRUCTOR_PRIO(function_name, priority)
/* We use this wrapper for METAL_CONSTRUCTOR_PRIORITY so that macros passed
* as 'priority' are expanded before being stringified by the # operator.
* If we don't do this, then
* METAL_CONSTRUCTOR(my_fn_name, METAL_INIT_DEFAULT_PRIORITY)
* results in .metal.init_array.METAL_INIT_DEFAULT_PRIORITY instead of
* .metal.init_array.5000 */
#define __METAL_CONSTRUCTOR_PRIO(function_name, priority) \
__attribute__((section(".metal.ctors"))) void function_name(void); \
__attribute__((section(".metal.init_array." #priority))) \
metal_constructor_t _##function_name##_ptr = &function_name; \
void function_name(void)
/*! @def METAL_DESTRUCTOR
* @brief Define a Metal destructor
*
* Functions defined with METAL_DESTRUCTOR will be added to the list of
* Metal destructors. By default, these functions are called on exit by
* the metal_fini() function.
*/
#define METAL_DESTRUCTOR(function_name) \
METAL_DESTRUCTOR_PRIO(function_name, METAL_INIT_DEFAULT_PRIORITY)
/*! @def METAL_DESTRUCTOR_PRIO
* @brief Define a Metal destructor with a given priority
*
* The priority argument should be an integer between 0 and 9999, where 0
* is the highest priority (runs first) and 9999 is the lowest priority
* (runs last).
*
* Functions defined with METAL_DESTRUCTOR_PRIO will be added to the list of
* Metal destructors. By default, these functions are called on exit by
* the metal_fini() function.
*/
#define METAL_DESTRUCTOR_PRIO(function_name, priority) \
__METAL_DESTRUCTOR_PRIO(function_name, priority)
#define __METAL_DESTRUCTOR_PRIO(function_name, priority) \
__attribute__((section(".metal.dtors"))) void function_name(void); \
__attribute__((section(".metal.fini_array." #priority))) \
metal_destructor_t _##function_name##_ptr = &function_name; \
void function_name(void)
/*!
* @brief Call all Metal constructors
*
* Devices supported by Metal may define Metal constructors to perform
* initialization before main. This function iterates over the constructors
* and calls them in turn.
*
* You can add your own constructors to the functions called by metal_init()
* by defining functions with the METAL_CONSTRUCTOR() macro.
*
* This function is called before main by default by metal_init_run().
*/
void metal_init(void);
/*!
* @brief Call all Metal destructors
*
* Devices supported by Metal may define Metal destructors to perform
* initialization on exit. This function iterates over the destructors
* and calls them in turn.
*
* You can add your own destructors to the functions called by metal_fini()
* by defining functions with the METAL_DESTRUCTOR() macro.
*
* This function is called on exit by default by metal_fini_run().
*/
void metal_fini(void);
/*!
* @brief Weak function to call metal_init() before main
*
* This function calls metal_init() before main by default. If you wish to
* replace or augment this call to the Metal constructors, you can redefine
* metal_init_run()
*/
void metal_init_run(void);
/*!
* @brief Weak function to call metal_fini() before main
*
* This function calls metal_fini() at exit by default. If you wish to
* replace or augment this call to the Metal destructors, you can redefine
* metal_fini_run()
*/
void metal_fini_run(void);
#endif /* METAL_INIT */

View file

@ -10,34 +10,105 @@
#include <stddef.h> #include <stddef.h>
/*!
* @brief Possible interrupt controllers
*/
typedef enum metal_interrupt_controller_ {
METAL_CPU_CONTROLLER = 0,
METAL_CLINT_CONTROLLER = 1,
METAL_CLIC_CONTROLLER = 2,
METAL_PLIC_CONTROLLER = 3
} metal_intr_cntrl_type;
/*! /*!
* @brief Possible mode of interrupts to operate * @brief Possible mode of interrupts to operate
*/ */
typedef enum metal_vector_mode_ { typedef enum metal_vector_mode_ {
METAL_DIRECT_MODE = 0, METAL_DIRECT_MODE = 0,
METAL_VECTOR_MODE = 1, METAL_VECTOR_MODE = 1,
METAL_SELECTIVE_VECTOR_MODE = 2, METAL_SELECTIVE_NONVECTOR_MODE = 2,
METAL_HARDWARE_VECTOR_MODE = 3 METAL_SELECTIVE_VECTOR_MODE = 3,
METAL_HARDWARE_VECTOR_MODE = 4
} metal_vector_mode; } metal_vector_mode;
/*!
* @brief Possible mode of privilege interrupts to operate
*/
typedef enum metal_intr_priv_mode_ {
METAL_INTR_PRIV_M_MODE = 0,
METAL_INTR_PRIV_MU_MODE = 1,
METAL_INTR_PRIV_MSU_MODE = 2
} metal_intr_priv_mode;
/*!
* @brief The bitmask of hart context
*/
typedef struct metal_affinity_ {
unsigned long bitmask;
} metal_affinity;
#define for_each_metal_affinity(bit, metal_affinity) \
for (bit = 0; metal_affinity.bitmask; bit++, metal_affinity.bitmask >>= 1)
#define metal_affinity_set_val(metal_affinity, val) \
metal_affinity.bitmask = val;
#define metal_affinity_set_bit(metal_affinity, bit, val) \
metal_affinity.bitmask |= ((val & 0x1) << bit);
/*! /*!
* @brief Function signature for interrupt callback handlers * @brief Function signature for interrupt callback handlers
*/ */
typedef void (*metal_interrupt_handler_t) (int, void *); typedef void (*metal_interrupt_handler_t)(int, void *);
typedef void (*metal_interrupt_vector_handler_t)(void);
struct metal_interrupt; struct metal_interrupt;
struct metal_interrupt_vtable { struct metal_interrupt_vtable {
void (*interrupt_init)(struct metal_interrupt *controller); void (*interrupt_init)(struct metal_interrupt *controller);
int (*interrupt_set_vector_mode)(struct metal_interrupt *controller,
metal_vector_mode mode);
metal_vector_mode (*interrupt_get_vector_mode)(
struct metal_interrupt *controller);
int (*interrupt_set_privilege)(struct metal_interrupt *controller,
metal_intr_priv_mode priv);
metal_intr_priv_mode (*interrupt_get_privilege)(
struct metal_interrupt *controller);
int (*interrupt_clear)(struct metal_interrupt *controller, int id);
int (*interrupt_set)(struct metal_interrupt *controller, int id);
int (*interrupt_register)(struct metal_interrupt *controller, int id, int (*interrupt_register)(struct metal_interrupt *controller, int id,
metal_interrupt_handler_t isr, void *priv_data); metal_interrupt_handler_t isr, void *priv_data);
int (*interrupt_vector_register)(struct metal_interrupt *controller, int id,
metal_interrupt_vector_handler_t isr,
void *priv_data);
int (*interrupt_enable)(struct metal_interrupt *controller, int id); int (*interrupt_enable)(struct metal_interrupt *controller, int id);
int (*interrupt_disable)(struct metal_interrupt *controller, int id); int (*interrupt_disable)(struct metal_interrupt *controller, int id);
int (*interrupt_vector_enable)(struct metal_interrupt *controller, int (*interrupt_vector_enable)(struct metal_interrupt *controller, int id);
int id, metal_vector_mode mode);
int (*interrupt_vector_disable)(struct metal_interrupt *controller, int id); int (*interrupt_vector_disable)(struct metal_interrupt *controller, int id);
int (*command_request)(struct metal_interrupt *controller, int cmd, void *data); unsigned int (*interrupt_get_threshold)(struct metal_interrupt *controller);
int (*mtimecmp_set)(struct metal_interrupt *controller, int hartid, unsigned long long time); int (*interrupt_set_threshold)(struct metal_interrupt *controller,
unsigned int threshold);
unsigned int (*interrupt_get_priority)(struct metal_interrupt *controller,
int id);
int (*interrupt_set_priority)(struct metal_interrupt *controller, int id,
unsigned int priority);
unsigned int (*interrupt_get_preemptive_level)(
struct metal_interrupt *controller, int id);
int (*interrupt_set_preemptive_level)(struct metal_interrupt *controller,
int id, unsigned int level);
int (*command_request)(struct metal_interrupt *controller, int cmd,
void *data);
int (*mtimecmp_set)(struct metal_interrupt *controller, int hartid,
unsigned long long time);
metal_affinity (*interrupt_affinity_enable)(
struct metal_interrupt *controller, metal_affinity bitmask, int id);
metal_affinity (*interrupt_affinity_disable)(
struct metal_interrupt *controller, metal_affinity bitmask, int id);
metal_affinity (*interrupt_affinity_set_threshold)(
struct metal_interrupt *controller, metal_affinity bitmask,
unsigned int threshold);
unsigned int (*interrupt_affinity_get_threshold)(
struct metal_interrupt *controller, int context_id);
}; };
/*! /*!
@ -56,11 +127,104 @@ struct metal_interrupt {
* *
* @param controller The handle for the interrupt controller * @param controller The handle for the interrupt controller
*/ */
inline void metal_interrupt_init(struct metal_interrupt *controller) __inline__ void metal_interrupt_init(struct metal_interrupt *controller) {
{ controller->vtable->interrupt_init(controller);
return controller->vtable->interrupt_init(controller);
} }
/*!
* @brief Get the handle for an given interrupt controller type
* @param cntrl The type ofinterrupt controller
* @param id The instance of the interrupt controller
* @return A handle to the interrupt controller (CLINT, CLIC, PLIC), or
* NULL if none is found for the requested label
*/
struct metal_interrupt *
metal_interrupt_get_controller(metal_intr_cntrl_type cntrl, int id);
/*!
* @brief Configure vector mode for an interrupt controller
*
* Configure vector mode for an interrupt controller.
* This function must be called after initialization and before
* configuring individual interrupts, registering ISR.
*
* @param controller The handle for the interrupt controller
* @param mode The vector mode of the interrupt controller.
* @return 0 upon success
*/
__inline__ int
metal_interrupt_set_vector_mode(struct metal_interrupt *controller,
metal_vector_mode mode) {
return controller->vtable->interrupt_set_vector_mode(controller, mode);
}
/*!
* @brief Get vector mode of a given an interrupt controller
*
* Configure vector mode for an interrupt controller.
* This function must be called after initialization and before
* configuring individual interrupts, registering ISR.
*
* @param controller The handle for the interrupt controller
* @param mode The vector mode of the interrupt controller.
* @return The interrupt vector mode
*/
__inline__ metal_vector_mode
metal_interrupt_get_vector_mode(struct metal_interrupt *controller) {
return controller->vtable->interrupt_get_vector_mode(controller);
}
/*!
* @brief Configure privilege mode a of given interrupt controller
*
* Configure privilege mode for a given interrupt controller.
* This function must be called after initialization and before
* configuring individual interrupts, registering ISR.
*
* @param controller The handle for the interrupt controller
* @param privilege The privilege mode of the interrupt controller.
* @return 0 upon success
*/
__inline__ int metal_interrupt_set_privilege(struct metal_interrupt *controller,
metal_intr_priv_mode privilege) {
return controller->vtable->interrupt_set_privilege(controller, privilege);
}
/*!
* @brief Get privilege mode a of given interrupt controller
*
* Get privilege mode for a given interrupt controller.
* This function must be called after initialization and before
* configuring individual interrupts, registering ISR.
*
* @param controller The handle for the interrupt controller
* @return The interrupt privilege mode
*/
__inline__ metal_intr_priv_mode
metal_interrupt_get_privilege(struct metal_interrupt *controller) {
return controller->vtable->interrupt_get_privilege(controller);
}
/*!
* @brief clear an interrupt
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to trigger
* @return 0 upon success
*/
__inline__ int metal_interrupt_clear(struct metal_interrupt *controller,
int id) {
return controller->vtable->interrupt_clear(controller, id);
}
/*!
* @brief Set an interrupt
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to trigger
* @return 0 upon success
*/
__inline__ int metal_interrupt_set(struct metal_interrupt *controller, int id) {
return controller->vtable->interrupt_set(controller, id);
}
/*! /*!
* @brief Register an interrupt handler * @brief Register an interrupt handler
@ -70,12 +234,27 @@ inline void metal_interrupt_init(struct metal_interrupt *controller)
* @param priv_data Private data for the interrupt handler * @param priv_data Private data for the interrupt handler
* @return 0 upon success * @return 0 upon success
*/ */
inline int metal_interrupt_register_handler(struct metal_interrupt *controller, __inline__ int
int id, metal_interrupt_register_handler(struct metal_interrupt *controller, int id,
metal_interrupt_handler_t handler, metal_interrupt_handler_t handler,
void *priv_data) void *priv_data) {
{ return controller->vtable->interrupt_register(controller, id, handler,
return controller->vtable->interrupt_register(controller, id, handler, priv_data); priv_data);
}
/*!
* @brief Register an interrupt vector handler
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to register
* @param handler The interrupt vector handler callback
* @param priv_data Private data for the interrupt handler
* @return 0 upon success
*/
__inline__ int metal_interrupt_register_vector_handler(
struct metal_interrupt *controller, int id,
metal_interrupt_vector_handler_t handler, void *priv_data) {
return controller->vtable->interrupt_vector_register(controller, id,
handler, priv_data);
} }
/*! /*!
@ -84,8 +263,8 @@ inline int metal_interrupt_register_handler(struct metal_interrupt *controller,
* @param id The interrupt ID to enable * @param id The interrupt ID to enable
* @return 0 upon success * @return 0 upon success
*/ */
inline int metal_interrupt_enable(struct metal_interrupt *controller, int id) __inline__ int metal_interrupt_enable(struct metal_interrupt *controller,
{ int id) {
return controller->vtable->interrupt_enable(controller, id); return controller->vtable->interrupt_enable(controller, id);
} }
@ -95,22 +274,100 @@ inline int metal_interrupt_enable(struct metal_interrupt *controller, int id)
* @param id The interrupt ID to disable * @param id The interrupt ID to disable
* @return 0 upon success * @return 0 upon success
*/ */
inline int metal_interrupt_disable(struct metal_interrupt *controller, int id) __inline__ int metal_interrupt_disable(struct metal_interrupt *controller,
{ int id) {
return controller->vtable->interrupt_disable(controller, id); return controller->vtable->interrupt_disable(controller, id);
} }
/*!
* @brief Set interrupt threshold level
* @param controller The handle for the interrupt controller
* @param threshold The interrupt threshold level
* @return 0 upon success
*/
__inline__ int metal_interrupt_set_threshold(struct metal_interrupt *controller,
unsigned int level) {
return controller->vtable->interrupt_set_threshold(controller, level);
}
/*!
* @brief Get an interrupt threshold level
* @param controller The handle for the interrupt controller
* @return The interrupt threshold level
*/
__inline__ unsigned int
metal_interrupt_get_threshold(struct metal_interrupt *controller) {
return controller->vtable->interrupt_get_threshold(controller);
}
/*!
* @brief Set an interrupt priority level
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to enable
* @param priority The interrupt priority level
* @return 0 upon success
*/
__inline__ int metal_interrupt_set_priority(struct metal_interrupt *controller,
int id, unsigned int priority) {
return controller->vtable->interrupt_set_priority(controller, id, priority);
}
/*!
* @brief Get an interrupt priority level
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to enable
* @return The interrupt priority level
*/
__inline__ unsigned int
metal_interrupt_get_priority(struct metal_interrupt *controller, int id) {
return controller->vtable->interrupt_get_priority(controller, id);
}
/*!
* @brief Set preemptive level and priority for a given interrupt ID
*
* Set the preemptive level and priority for a given interrupt ID.
*
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to enable
* @param level The interrupt level and priority are encoded together
* @return 0 upon success
*/
__inline__ int
metal_interrupt_set_preemptive_level(struct metal_interrupt *controller, int id,
unsigned int level) {
if (controller->vtable->interrupt_set_preemptive_level)
return controller->vtable->interrupt_set_preemptive_level(controller,
id, level);
else
return 0;
}
/*!
* @brief Get an interrupt preemptive level
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to enable
* @return The interrupt level
*/
__inline__ unsigned int
metal_interrupt_get_preemptive_level(struct metal_interrupt *controller,
int id) {
if (controller->vtable->interrupt_get_preemptive_level)
return controller->vtable->interrupt_get_preemptive_level(controller,
id);
else
return 0;
}
/*! /*!
* @brief Enable an interrupt vector * @brief Enable an interrupt vector
* @param controller The handle for the interrupt controller * @param controller The handle for the interrupt controller
* @param id The interrupt ID to enable * @param id The interrupt ID to enable
* @param mode The interrupt mode type to enable
* @return 0 upon success * @return 0 upon success
*/ */
inline int metal_interrupt_vector_enable(struct metal_interrupt *controller, __inline__ int metal_interrupt_vector_enable(struct metal_interrupt *controller,
int id, metal_vector_mode mode) int id) {
{ return controller->vtable->interrupt_vector_enable(controller, id);
return controller->vtable->interrupt_vector_enable(controller, id, mode);
} }
/*! /*!
@ -119,16 +376,215 @@ inline int metal_interrupt_vector_enable(struct metal_interrupt *controller,
* @param id The interrupt ID to disable * @param id The interrupt ID to disable
* @return 0 upon success * @return 0 upon success
*/ */
inline int metal_interrupt_vector_disable(struct metal_interrupt *controller, int id) __inline__ int
{ metal_interrupt_vector_disable(struct metal_interrupt *controller, int id) {
return controller->vtable->interrupt_vector_disable(controller, id); return controller->vtable->interrupt_vector_disable(controller, id);
} }
/* Utilities function to controll, manages devices via a given interrupt controller */ /*!
inline int _metal_interrupt_command_request(struct metal_interrupt *controller, * @brief Default interrupt vector handler, that can be overriden by user
int cmd, void *data) * @param None
{ * @return None
*/
void __attribute__((weak, interrupt)) metal_interrupt_vector_handler(void);
/*!
* @brief Metal Software interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt))
metal_software_interrupt_vector_handler(void);
/*!
* @brief Metal Timer interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt))
metal_timer_interrupt_vector_handler(void);
/*!
* @brief Metal External interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt))
metal_external_interrupt_vector_handler(void);
/*!
* @brief Metal Local 0 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc0_interrupt_vector_handler(void);
/*!
* @brief Metal Local 1 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc1_interrupt_vector_handler(void);
/*!
* @brief Metal Local 2 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc2_interrupt_vector_handler(void);
/*!
* @brief Metal Local 3 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc3_interrupt_vector_handler(void);
/*!
* @brief Metal Local 4 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc4_interrupt_vector_handler(void);
/*!
* @brief Metal Local 5 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc5_interrupt_vector_handler(void);
/*!
* @brief Metal Local 6 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc6_interrupt_vector_handler(void);
/*!
* @brief Metal Local 7 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc7_interrupt_vector_handler(void);
/*!
* @brief Metal Local 8 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc8_interrupt_vector_handler(void);
/*!
* @brief Metal Local 9 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc9_interrupt_vector_handler(void);
/*!
* @brief Metal Local 10 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc10_interrupt_vector_handler(void);
/*!
* @brief Metal Local 11 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc11_interrupt_vector_handler(void);
/*!
* @brief Metal Local 12 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc12_interrupt_vector_handler(void);
/*!
* @brief Metal Local 13 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc13_interrupt_vector_handler(void);
/*!
* @brief Metal Local 14 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc14_interrupt_vector_handler(void);
/*!
* @brief Metal Local 15 interrupt vector handler, that can be overriden by user
* @param None
* @return None
*/
void __attribute__((weak, interrupt)) metal_lc15_interrupt_vector_handler(void);
/* Utilities function to controll, manages devices via a given interrupt
* controller */
__inline__ int
_metal_interrupt_command_request(struct metal_interrupt *controller, int cmd,
void *data) {
return controller->vtable->command_request(controller, cmd, data); return controller->vtable->command_request(controller, cmd, data);
} }
/*!
* @brief Enable an interrupt for the hart contexts
* @param controller The handle for the interrupt controller
* @param bitmask The bit mask of hart contexts to enable
* @param id The interrupt ID to enable
* @return The result of each hart context. 0 upon success at relevant bit.
*/
__inline__ metal_affinity
metal_interrupt_affinity_enable(struct metal_interrupt *controller,
metal_affinity bitmask, int id) {
return controller->vtable->interrupt_affinity_enable(controller, bitmask,
id);
}
/*!
* @brief Disable an interrupt for the hart contexts
* @param controller The handle for the interrupt controller
* @param bitmask The bit mask of hart contexts to disable
* @param id The interrupt ID to disable
* @return The result of each hart context. 0 upon success at relevant bit.
*/
__inline__ metal_affinity
metal_interrupt_affinity_disable(struct metal_interrupt *controller,
metal_affinity bitmask, int id) {
return controller->vtable->interrupt_affinity_disable(controller, bitmask,
id);
}
/*!
* @brief Set interrupt threshold level for the hart contexts
* @param controller The handle for the interrupt controller
* @param bitmask The bit mask of hart contexts to set threshold
* @param threshold The interrupt threshold level
* @return The result of each hart context. 0 upon success at relevant bit.
*/
__inline__ metal_affinity
metal_interrupt_affinity_set_threshold(struct metal_interrupt *controller,
metal_affinity bitmask,
unsigned int level) {
return controller->vtable->interrupt_affinity_set_threshold(controller,
bitmask, level);
}
/*!
* @brief Get an interrupt threshold level from the hart context
* @param controller The handle for the interrupt controller
* @param context_id The hart context ID to get threshold
* @return The interrupt threshold level
*/
__inline__ unsigned int
metal_interrupt_affinity_get_threshold(struct metal_interrupt *controller,
int context_id) {
return controller->vtable->interrupt_affinity_get_threshold(controller,
context_id);
}
#endif #endif

View file

@ -5,18 +5,19 @@
#define METAL__IO_H #define METAL__IO_H
/* This macro enforces that the compiler will not elide the given access. */ /* This macro enforces that the compiler will not elide the given access. */
#define __METAL_ACCESS_ONCE(x) (*(typeof(*x) volatile *)(x)) #define __METAL_ACCESS_ONCE(x) (*(__typeof__(*x) volatile *)(x))
/* Allows users to specify arbitrary fences. */ /* Allows users to specify arbitrary fences. */
#define __METAL_IO_FENCE(pred, succ) __asm__ volatile ("fence " #pred "," #succ ::: "memory"); #define __METAL_IO_FENCE(pred, succ) \
__asm__ volatile("fence " #pred "," #succ ::: "memory");
/* Types that explicitly describe an address as being used for memory-mapped /* Types that explicitly describe an address as being used for memory-mapped
* IO. These should only be accessed via __METAL_ACCESS_ONCE. */ * IO. These should only be accessed via __METAL_ACCESS_ONCE. */
typedef unsigned char __metal_io_u8; typedef unsigned char __metal_io_u8;
typedef unsigned short __metal_io_u16; typedef unsigned short __metal_io_u16;
typedef unsigned int __metal_io_u32; typedef unsigned int __metal_io_u32;
#if __riscv_xlen >= 64 #if __riscv_xlen >= 64
typedef unsigned long __metal_io_u64; typedef unsigned long __metal_io_u64;
#endif #endif
#endif #endif

View file

@ -9,13 +9,12 @@
* API for manipulating ITIM allocation * API for manipulating ITIM allocation
*/ */
/*! @def METAL_PLACE_IN_ITIM /*! @def METAL_PLACE_IN_ITIM
* @brief Link a function into the ITIM * @brief Link a function into the ITIM
* *
* Link a function into the ITIM (Instruction Tightly Integrated * Link a function into the ITIM (Instruction Tightly Integrated
* Memory) if the ITIM is present on the target device. * Memory) if the ITIM is present on the target device.
*/ */
#define METAL_PLACE_IN_ITIM __attribute__((section(".itim"))) #define METAL_PLACE_IN_ITIM __attribute__((section(".itim")))
#endif #endif

View file

@ -31,38 +31,47 @@ struct metal_led {
* @param label The DeviceTree label for the desired LED * @param label The DeviceTree label for the desired LED
* @return A handle to the LED, or NULL if none is found for the requested label * @return A handle to the LED, or NULL if none is found for the requested label
*/ */
struct metal_led* metal_led_get(char *label); struct metal_led *metal_led_get(char *label);
/*! /*!
* @brief Get a handle for a channel of an RGB LED * @brief Get a handle for a channel of an RGB LED
* @param label The DeviceTree label for the desired LED * @param label The DeviceTree label for the desired LED
* @param color The color for the LED in the DeviceTree * @param color The color for the LED in the DeviceTree
* @return A handle to the LED, or NULL if none is found for the requested label and color * @return A handle to the LED, or NULL if none is found for the requested label
* and color
*/ */
struct metal_led* metal_led_get_rgb(char *label, char *color); struct metal_led *metal_led_get_rgb(char *label, char *color);
/*! /*!
* @brief Enable an LED * @brief Enable an LED
* @param led The handle for the LED * @param led The handle for the LED
*/ */
inline void metal_led_enable(struct metal_led *led) { led->vtable->led_enable(led); } __inline__ void metal_led_enable(struct metal_led *led) {
led->vtable->led_enable(led);
}
/*! /*!
* @brief Turn an LED on * @brief Turn an LED on
* @param led The handle for the LED * @param led The handle for the LED
*/ */
inline void metal_led_on(struct metal_led *led) { led->vtable->led_on(led); } __inline__ void metal_led_on(struct metal_led *led) {
led->vtable->led_on(led);
}
/*! /*!
* @brief Turn an LED off * @brief Turn an LED off
* @param led The handle for the LED * @param led The handle for the LED
*/ */
inline void metal_led_off(struct metal_led *led) { led->vtable->led_off(led); } __inline__ void metal_led_off(struct metal_led *led) {
led->vtable->led_off(led);
}
/*! /*!
* @brief Toggle the on/off state of an LED * @brief Toggle the on/off state of an LED
* @param led The handle for the LED * @param led The handle for the LED
*/ */
inline void metal_led_toggle(struct metal_led *led) { led->vtable->led_toggle(led); } __inline__ void metal_led_toggle(struct metal_led *led) {
led->vtable->led_toggle(led);
}
#endif #endif

View file

@ -0,0 +1,20 @@
/* Copyright 2020 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__LIM_H
#define METAL__LIM_H
/*! @file lim.h
*
* API for manipulating LIM allocation
*/
/*! @def METAL_PLACE_IN_LIM
* @brief Link a function into the LIM
*
* Link a function into the LIM (Loosely Integrated
* Memory) if the LIM is present on the target device.
*/
#define METAL_PLACE_IN_LIM __attribute__((section(".lim")))
#endif

View file

@ -4,8 +4,9 @@
#ifndef METAL__LOCK_H #ifndef METAL__LOCK_H
#define METAL__LOCK_H #define METAL__LOCK_H
#include <metal/memory.h>
#include <metal/compiler.h> #include <metal/compiler.h>
#include <metal/machine.h>
#include <metal/memory.h>
/*! /*!
* @file lock.h * @file lock.h
@ -15,6 +16,9 @@
/* TODO: How can we make the exception code platform-independant? */ /* TODO: How can we make the exception code platform-independant? */
#define _METAL_STORE_AMO_ACCESS_FAULT 7 #define _METAL_STORE_AMO_ACCESS_FAULT 7
#define METAL_LOCK_BACKOFF_CYCLES 32
#define METAL_LOCK_BACKOFF_EXPONENT 2
/*! /*!
* @def METAL_LOCK_DECLARE * @def METAL_LOCK_DECLARE
* @brief Declare a lock * @brief Declare a lock
@ -22,35 +26,36 @@
* Locks must be declared with METAL_LOCK_DECLARE to ensure that the lock * Locks must be declared with METAL_LOCK_DECLARE to ensure that the lock
* is linked into a memory region which supports atomic memory operations. * is linked into a memory region which supports atomic memory operations.
*/ */
#define METAL_LOCK_DECLARE(name) \ #define METAL_LOCK_DECLARE(name) \
__attribute__((section(".data.locks"))) \ __attribute__((section(".data.locks"))) struct metal_lock name
struct metal_lock name
/*! /*!
* @brief A handle for a lock * @brief A handle for a lock
*/ */
struct metal_lock { struct metal_lock {
int _state; int _state;
}; };
/*! /*!
* @brief Initialize a lock * @brief Initialize a lock
* @param lock The handle for a lock * @param lock The handle for a lock
* @return 0 if the lock is successfully initialized. A non-zero code indicates failure. * @return 0 if the lock is successfully initialized. A non-zero code indicates
* failure.
* *
* If the lock cannot be initialized, attempts to take or give the lock * If the lock cannot be initialized, attempts to take or give the lock
* will result in a Store/AMO access fault. * will result in a Store/AMO access fault.
*/ */
inline int metal_lock_init(struct metal_lock *lock) { __inline__ int metal_lock_init(struct metal_lock *lock) {
#ifdef __riscv_atomic #ifdef __riscv_atomic
/* Get a handle for the memory which holds the lock state */ /* Get a handle for the memory which holds the lock state */
struct metal_memory *lock_mem = metal_get_memory_from_address((uintptr_t) &(lock->_state)); struct metal_memory *lock_mem =
if(!lock_mem) { metal_get_memory_from_address((uintptr_t) & (lock->_state));
if (!lock_mem) {
return 1; return 1;
} }
/* If the memory doesn't support atomics, report an error */ /* If the memory doesn't support atomics, report an error */
if(!metal_memory_supports_atomics(lock_mem)) { if (!metal_memory_supports_atomics(lock_mem)) {
return 2; return 2;
} }
@ -70,23 +75,37 @@ inline int metal_lock_init(struct metal_lock *lock) {
* If the lock initialization failed, attempts to take a lock will result in * If the lock initialization failed, attempts to take a lock will result in
* a Store/AMO access fault. * a Store/AMO access fault.
*/ */
inline int metal_lock_take(struct metal_lock *lock) { __inline__ int metal_lock_take(struct metal_lock *lock) {
#ifdef __riscv_atomic #ifdef __riscv_atomic
int old = 1; int old = 1;
int new = 1; int new = 1;
while(old != 0) { int backoff = 1;
const int max_backoff = METAL_LOCK_BACKOFF_CYCLES * METAL_MAX_CORES;
while (1) {
__asm__ volatile("amoswap.w.aq %[old], %[new], (%[state])" __asm__ volatile("amoswap.w.aq %[old], %[new], (%[state])"
: [old] "=r" (old) : [old] "=r"(old)
: [new] "r" (new), [state] "r" (&(lock->_state)) : [new] "r"(new), [state] "r"(&(lock->_state))
: "memory"); : "memory");
if (old == 0) {
break;
}
for (int i = 0; i < backoff; i++) {
__asm__ volatile("");
}
if (backoff < max_backoff) {
backoff *= METAL_LOCK_BACKOFF_EXPONENT;
}
} }
return 0; return 0;
#else #else
/* Store the memory address in mtval like a normal store/amo access fault */ /* Store the memory address in mtval like a normal store/amo access fault */
__asm__ ("csrw mtval, %[state]" __asm__("csrw mtval, %[state]" ::[state] "r"(&(lock->_state)));
:: [state] "r" (&(lock->_state)));
/* Trigger a Store/AMO access fault */ /* Trigger a Store/AMO access fault */
_metal_trap(_METAL_STORE_AMO_ACCESS_FAULT); _metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);
@ -104,17 +123,16 @@ inline int metal_lock_take(struct metal_lock *lock) {
* If the lock initialization failed, attempts to give a lock will result in * If the lock initialization failed, attempts to give a lock will result in
* a Store/AMO access fault. * a Store/AMO access fault.
*/ */
inline int metal_lock_give(struct metal_lock *lock) { __inline__ int metal_lock_give(struct metal_lock *lock) {
#ifdef __riscv_atomic #ifdef __riscv_atomic
__asm__ volatile("amoswap.w.rl x0, x0, (%[state])" __asm__ volatile(
:: [state] "r" (&(lock->_state)) "amoswap.w.rl x0, x0, (%[state])" ::[state] "r"(&(lock->_state))
: "memory"); : "memory");
return 0; return 0;
#else #else
/* Store the memory address in mtval like a normal store/amo access fault */ /* Store the memory address in mtval like a normal store/amo access fault */
__asm__ ("csrw mtval, %[state]" __asm__("csrw mtval, %[state]" ::[state] "r"(&(lock->_state)));
:: [state] "r" (&(lock->_state)));
/* Trigger a Store/AMO access fault */ /* Trigger a Store/AMO access fault */
_metal_trap(_METAL_STORE_AMO_ACCESS_FAULT); _metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);

View file

@ -5,128 +5,181 @@
#ifndef ASSEMBLY #ifndef ASSEMBLY
#ifndef SIFIVE_HIFIVE1_REVB____METAL_INLINE_H #ifndef METAL_INLINE_H
#define SIFIVE_HIFIVE1_REVB____METAL_INLINE_H #define METAL_INLINE_H
#include <metal/machine.h> #include <metal/machine.h>
/* --------------------- fixed_clock ------------ */ /* --------------------- fixed_clock ------------ */
extern inline unsigned long __metal_driver_fixed_clock_rate(const struct metal_clock *clock); extern __inline__ unsigned long __metal_driver_fixed_clock_rate(const struct metal_clock *clock);
/* --------------------- fixed_factor_clock ------------ */ /* --------------------- fixed_factor_clock ------------ */
/* --------------------- sifive_clint0 ------------ */ /* --------------------- sifive_clint0 ------------ */
extern inline unsigned long __metal_driver_sifive_clint0_control_base(struct metal_interrupt *controller); extern __inline__ unsigned long __metal_driver_sifive_clint0_control_base(struct metal_interrupt *controller);
extern inline unsigned long __metal_driver_sifive_clint0_control_size(struct metal_interrupt *controller); extern __inline__ unsigned long __metal_driver_sifive_clint0_control_size(struct metal_interrupt *controller);
extern inline int __metal_driver_sifive_clint0_num_interrupts(struct metal_interrupt *controller); extern __inline__ int __metal_driver_sifive_clint0_num_interrupts(struct metal_interrupt *controller);
extern inline struct metal_interrupt * __metal_driver_sifive_clint0_interrupt_parents(struct metal_interrupt *controller, int idx); extern __inline__ struct metal_interrupt * __metal_driver_sifive_clint0_interrupt_parents(struct metal_interrupt *controller, int idx);
extern inline int __metal_driver_sifive_clint0_interrupt_lines(struct metal_interrupt *controller, int idx); extern __inline__ int __metal_driver_sifive_clint0_interrupt_lines(struct metal_interrupt *controller, int idx);
/* --------------------- cpu ------------ */ /* --------------------- cpu ------------ */
extern inline int __metal_driver_cpu_hartid(struct metal_cpu *cpu); extern __inline__ int __metal_driver_cpu_hartid(struct metal_cpu *cpu);
extern inline int __metal_driver_cpu_timebase(struct metal_cpu *cpu); extern __inline__ int __metal_driver_cpu_timebase(struct metal_cpu *cpu);
extern inline struct metal_interrupt * __metal_driver_cpu_interrupt_controller(struct metal_cpu *cpu); extern __inline__ struct metal_interrupt * __metal_driver_cpu_interrupt_controller(struct metal_cpu *cpu);
extern inline int __metal_driver_cpu_num_pmp_regions(struct metal_cpu *cpu); extern __inline__ int __metal_driver_cpu_num_pmp_regions(struct metal_cpu *cpu);
extern __inline__ struct metal_buserror * __metal_driver_cpu_buserror(struct metal_cpu *cpu);
/* --------------------- sifive_plic0 ------------ */ /* --------------------- sifive_plic0 ------------ */
extern inline unsigned long __metal_driver_sifive_plic0_control_base(struct metal_interrupt *controller); extern __inline__ unsigned long __metal_driver_sifive_plic0_control_base(struct metal_interrupt *controller);
extern inline unsigned long __metal_driver_sifive_plic0_control_size(struct metal_interrupt *controller); extern __inline__ unsigned long __metal_driver_sifive_plic0_control_size(struct metal_interrupt *controller);
extern inline int __metal_driver_sifive_plic0_num_interrupts(struct metal_interrupt *controller); extern __inline__ int __metal_driver_sifive_plic0_num_interrupts(struct metal_interrupt *controller);
extern inline int __metal_driver_sifive_plic0_max_priority(struct metal_interrupt *controller); extern __inline__ int __metal_driver_sifive_plic0_max_priority(struct metal_interrupt *controller);
extern inline struct metal_interrupt * __metal_driver_sifive_plic0_interrupt_parents(struct metal_interrupt *controller, int idx); extern __inline__ struct metal_interrupt * __metal_driver_sifive_plic0_interrupt_parents(struct metal_interrupt *controller, int idx);
extern inline int __metal_driver_sifive_plic0_interrupt_lines(struct metal_interrupt *controller, int idx); extern __inline__ int __metal_driver_sifive_plic0_interrupt_lines(struct metal_interrupt *controller, int idx);
extern __inline__ int __metal_driver_sifive_plic0_context_ids(int hartid);
/* --------------------- sifive_buserror0 ------------ */
/* --------------------- sifive_clic0 ------------ */ /* --------------------- sifive_clic0 ------------ */
/* --------------------- sifive_local_external_interrupts0 ------------ */ /* --------------------- sifive_local_external_interrupts0 ------------ */
extern inline struct metal_interrupt * __metal_driver_sifive_local_external_interrupts0_interrupt_parent(struct metal_interrupt *controller);
extern inline int __metal_driver_sifive_local_external_interrupts0_num_interrupts(struct metal_interrupt *controller);
extern inline int __metal_driver_sifive_local_external_interrupts0_interrupt_lines(struct metal_interrupt *controller, int idx);
/* --------------------- sifive_global_external_interrupts0 ------------ */ /* --------------------- sifive_global_external_interrupts0 ------------ */
/* --------------------- sifive_gpio0 ------------ */ /* --------------------- sifive_gpio0 ------------ */
extern inline unsigned long __metal_driver_sifive_gpio0_base(struct metal_gpio *gpio); extern __inline__ unsigned long __metal_driver_sifive_gpio0_base(struct metal_gpio *gpio);
extern inline unsigned long __metal_driver_sifive_gpio0_size(struct metal_gpio *gpio); extern __inline__ unsigned long __metal_driver_sifive_gpio0_size(struct metal_gpio *gpio);
extern inline int __metal_driver_sifive_gpio0_num_interrupts(struct metal_gpio *gpio); extern __inline__ int __metal_driver_sifive_gpio0_num_interrupts(struct metal_gpio *gpio);
extern inline struct metal_interrupt * __metal_driver_sifive_gpio0_interrupt_parent(struct metal_gpio *gpio); extern __inline__ struct metal_interrupt * __metal_driver_sifive_gpio0_interrupt_parent(struct metal_gpio *gpio);
extern inline int __metal_driver_sifive_gpio0_interrupt_lines(struct metal_gpio *gpio, int idx); extern __inline__ int __metal_driver_sifive_gpio0_interrupt_lines(struct metal_gpio *gpio, int idx);
/* --------------------- sifive_gpio_button ------------ */ /* --------------------- sifive_gpio_button ------------ */
/* --------------------- sifive_gpio_led ------------ */ /* --------------------- sifive_gpio_led ------------ */
extern inline struct metal_gpio * __metal_driver_sifive_gpio_led_gpio(struct metal_led *led); extern __inline__ struct metal_gpio * __metal_driver_sifive_gpio_led_gpio(struct metal_led *led);
extern inline int __metal_driver_sifive_gpio_led_pin(struct metal_led *led); extern __inline__ int __metal_driver_sifive_gpio_led_pin(struct metal_led *led);
extern inline char * __metal_driver_sifive_gpio_led_label(struct metal_led *led); extern __inline__ char * __metal_driver_sifive_gpio_led_label(struct metal_led *led);
/* --------------------- sifive_gpio_switch ------------ */ /* --------------------- sifive_gpio_switch ------------ */
/* --------------------- sifive_i2c0 ------------ */
extern __inline__ unsigned long __metal_driver_sifive_i2c0_control_base(struct metal_i2c *i2c);
extern __inline__ unsigned long __metal_driver_sifive_i2c0_control_size(struct metal_i2c *i2c);
extern __inline__ int __metal_driver_sifive_i2c0_num_interrupts(struct metal_i2c *i2c);
extern __inline__ struct metal_interrupt * __metal_driver_sifive_i2c0_interrupt_parent(struct metal_i2c *i2c);
extern __inline__ int __metal_driver_sifive_i2c0_interrupt_line(struct metal_i2c *i2c);
extern __inline__ struct metal_clock * __metal_driver_sifive_i2c0_clock(struct metal_i2c *i2c);
extern __inline__ struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_i2c0_pinmux(struct metal_i2c *i2c);
extern __inline__ unsigned long __metal_driver_sifive_i2c0_pinmux_output_selector(struct metal_i2c *i2c);
extern __inline__ unsigned long __metal_driver_sifive_i2c0_pinmux_source_selector(struct metal_i2c *i2c);
/* --------------------- sifive_pwm0 ------------ */
extern __inline__ unsigned long __metal_driver_sifive_pwm0_control_base(struct metal_pwm *pwm);
extern __inline__ unsigned long __metal_driver_sifive_pwm0_control_size(struct metal_pwm *pwm);
extern __inline__ int __metal_driver_sifive_pwm0_num_interrupts(struct metal_pwm *pwm);
extern __inline__ struct metal_interrupt * __metal_driver_sifive_pwm0_interrupt_parent(struct metal_pwm *pwm);
extern __inline__ int __metal_driver_sifive_pwm0_interrupt_lines(struct metal_pwm *pwm, int idx);
extern __inline__ struct metal_clock * __metal_driver_sifive_pwm0_clock(struct metal_pwm *pwm);
extern __inline__ struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_pwm0_pinmux(struct metal_pwm *pwm);
extern __inline__ unsigned long __metal_driver_sifive_pwm0_pinmux_output_selector(struct metal_pwm *pwm);
extern __inline__ unsigned long __metal_driver_sifive_pwm0_pinmux_source_selector(struct metal_pwm *pwm);
extern __inline__ int __metal_driver_sifive_pwm0_compare_width(struct metal_pwm *pwm);
extern __inline__ int __metal_driver_sifive_pwm0_comparator_count(struct metal_pwm *pwm);
/* --------------------- sifive_rtc0 ------------ */
extern __inline__ unsigned long __metal_driver_sifive_rtc0_control_base(const struct metal_rtc *const rtc);
extern __inline__ unsigned long __metal_driver_sifive_rtc0_control_size(const struct metal_rtc *const rtc);
extern __inline__ struct metal_interrupt * __metal_driver_sifive_rtc0_interrupt_parent(const struct metal_rtc *const rtc);
extern __inline__ int __metal_driver_sifive_rtc0_interrupt_line(const struct metal_rtc *const rtc);
extern __inline__ struct metal_clock * __metal_driver_sifive_rtc0_clock(const struct metal_rtc *const rtc);
/* --------------------- sifive_spi0 ------------ */ /* --------------------- sifive_spi0 ------------ */
extern inline unsigned long __metal_driver_sifive_spi0_control_base(struct metal_spi *spi); extern __inline__ unsigned long __metal_driver_sifive_spi0_control_base(struct metal_spi *spi);
extern inline unsigned long __metal_driver_sifive_spi0_control_size(struct metal_spi *spi); extern __inline__ unsigned long __metal_driver_sifive_spi0_control_size(struct metal_spi *spi);
extern inline struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_spi0_pinmux(struct metal_spi *spi); extern __inline__ struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_spi0_pinmux(struct metal_spi *spi);
extern inline unsigned long __metal_driver_sifive_spi0_pinmux_output_selector(struct metal_spi *spi); extern __inline__ unsigned long __metal_driver_sifive_spi0_pinmux_output_selector(struct metal_spi *spi);
extern inline unsigned long __metal_driver_sifive_spi0_pinmux_source_selector(struct metal_spi *spi); extern __inline__ unsigned long __metal_driver_sifive_spi0_pinmux_source_selector(struct metal_spi *spi);
/* --------------------- sifive_test0 ------------ */ /* --------------------- sifive_test0 ------------ */
/* --------------------- sifive_trace ------------ */
/* --------------------- sifive_uart0 ------------ */ /* --------------------- sifive_uart0 ------------ */
extern inline unsigned long __metal_driver_sifive_uart0_control_base(struct metal_uart *uart); extern __inline__ unsigned long __metal_driver_sifive_uart0_control_base(struct metal_uart *uart);
extern inline unsigned long __metal_driver_sifive_uart0_control_size(struct metal_uart *uart); extern __inline__ unsigned long __metal_driver_sifive_uart0_control_size(struct metal_uart *uart);
extern inline int __metal_driver_sifive_uart0_num_interrupts(struct metal_uart *uart); extern __inline__ int __metal_driver_sifive_uart0_num_interrupts(struct metal_uart *uart);
extern inline struct metal_interrupt * __metal_driver_sifive_uart0_interrupt_parent(struct metal_uart *uart); extern __inline__ struct metal_interrupt * __metal_driver_sifive_uart0_interrupt_parent(struct metal_uart *uart);
extern inline int __metal_driver_sifive_uart0_interrupt_line(struct metal_uart *uart); extern __inline__ int __metal_driver_sifive_uart0_interrupt_line(struct metal_uart *uart);
extern inline struct metal_clock * __metal_driver_sifive_uart0_clock(struct metal_uart *uart); extern __inline__ struct metal_clock * __metal_driver_sifive_uart0_clock(struct metal_uart *uart);
extern inline struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_uart0_pinmux(struct metal_uart *uart); extern __inline__ struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_uart0_pinmux(struct metal_uart *uart);
extern inline unsigned long __metal_driver_sifive_uart0_pinmux_output_selector(struct metal_uart *uart); extern __inline__ unsigned long __metal_driver_sifive_uart0_pinmux_output_selector(struct metal_uart *uart);
extern inline unsigned long __metal_driver_sifive_uart0_pinmux_source_selector(struct metal_uart *uart); extern __inline__ unsigned long __metal_driver_sifive_uart0_pinmux_source_selector(struct metal_uart *uart);
/* --------------------- sifive_simuart0 ------------ */
/* --------------------- sifive_wdog0 ------------ */
extern __inline__ unsigned long __metal_driver_sifive_wdog0_control_base(const struct metal_watchdog *const watchdog);
extern __inline__ unsigned long __metal_driver_sifive_wdog0_control_size(const struct metal_watchdog *const watchdog);
extern __inline__ struct metal_interrupt * __metal_driver_sifive_wdog0_interrupt_parent(const struct metal_watchdog *const watchdog);
extern __inline__ int __metal_driver_sifive_wdog0_interrupt_line(const struct metal_watchdog *const watchdog);
extern __inline__ struct metal_clock * __metal_driver_sifive_wdog0_clock(const struct metal_watchdog *const watchdog);
/* --------------------- sifive_fe310_g000_hfrosc ------------ */ /* --------------------- sifive_fe310_g000_hfrosc ------------ */
extern inline struct metal_clock * __metal_driver_sifive_fe310_g000_hfrosc_ref(const struct metal_clock *clock); extern __inline__ struct metal_clock * __metal_driver_sifive_fe310_g000_hfrosc_ref(const struct metal_clock *clock);
extern inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_base(const struct metal_clock *clock); extern __inline__ struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_base(const struct metal_clock *clock);
extern inline const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_vtable(struct metal_clock *clock); extern __inline__ const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_vtable(struct metal_clock *clock);
extern inline long __metal_driver_sifive_fe310_g000_hfrosc_config_offset(const struct metal_clock *clock); extern __inline__ long __metal_driver_sifive_fe310_g000_hfrosc_config_offset(const struct metal_clock *clock);
/* --------------------- sifive_fe310_g000_hfxosc ------------ */ /* --------------------- sifive_fe310_g000_hfxosc ------------ */
extern inline struct metal_clock * __metal_driver_sifive_fe310_g000_hfxosc_ref(const struct metal_clock *clock); extern __inline__ struct metal_clock * __metal_driver_sifive_fe310_g000_hfxosc_ref(const struct metal_clock *clock);
extern inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfxosc_config_base(const struct metal_clock *clock); extern __inline__ struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfxosc_config_base(const struct metal_clock *clock);
extern inline long __metal_driver_sifive_fe310_g000_hfxosc_config_offset(const struct metal_clock *clock); extern __inline__ long __metal_driver_sifive_fe310_g000_hfxosc_config_offset(const struct metal_clock *clock);
/* --------------------- sifive_fe310_g000_lfrosc ------------ */
extern __inline__ struct metal_clock * __metal_driver_sifive_fe310_g000_lfrosc_lfrosc(const struct metal_clock *clock);
extern __inline__ struct metal_clock * __metal_driver_sifive_fe310_g000_lfrosc_psdlfaltclk(const struct metal_clock *clock);
extern __inline__ unsigned long int __metal_driver_sifive_fe310_g000_lfrosc_config_reg(const struct metal_clock *clock);
extern __inline__ unsigned long int __metal_driver_sifive_fe310_g000_lfrosc_mux_reg(const struct metal_clock *clock);
/* --------------------- sifive_fe310_g000_pll ------------ */ /* --------------------- sifive_fe310_g000_pll ------------ */
extern inline struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllsel0(const struct metal_clock *clock); extern __inline__ struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllsel0(const struct metal_clock *clock);
extern inline struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllref(const struct metal_clock *clock); extern __inline__ struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllref(const struct metal_clock *clock);
extern inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_config_base( ); extern __inline__ struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_config_base( );
extern inline long __metal_driver_sifive_fe310_g000_pll_config_offset( ); extern __inline__ long __metal_driver_sifive_fe310_g000_pll_config_offset( );
extern inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_divider_base(const struct metal_clock *clock); extern __inline__ struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_divider_base(const struct metal_clock *clock);
extern inline long __metal_driver_sifive_fe310_g000_pll_divider_offset(const struct metal_clock *clock); extern __inline__ long __metal_driver_sifive_fe310_g000_pll_divider_offset(const struct metal_clock *clock);
extern inline long __metal_driver_sifive_fe310_g000_pll_init_rate( ); extern __inline__ long __metal_driver_sifive_fe310_g000_pll_init_rate( );
/* --------------------- fe310_g000_prci ------------ */ /* --------------------- fe310_g000_prci ------------ */
extern inline long __metal_driver_sifive_fe310_g000_prci_base( ); extern __inline__ long __metal_driver_sifive_fe310_g000_prci_base( );
extern inline long __metal_driver_sifive_fe310_g000_prci_size( ); extern __inline__ long __metal_driver_sifive_fe310_g000_prci_size( );
extern inline const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_prci_vtable( ); extern __inline__ const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_prci_vtable( );
/* --------------------- sifive_fu540_c000_l2 ------------ */
/* From clock@0 */ /* From clock@0 */
@ -144,6 +197,11 @@ struct __metal_driver_fixed_clock __metal_dt_clock_5 = {
.clock.vtable = &__metal_driver_vtable_fixed_clock.clock, .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
}; };
/* From clock@6 */
struct __metal_driver_fixed_clock __metal_dt_clock_6 = {
.clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
};
struct metal_memory __metal_dt_mem_dtim_80000000 = { struct metal_memory __metal_dt_mem_dtim_80000000 = {
._base_address = 2147483648UL, ._base_address = 2147483648UL,
._size = 16384UL, ._size = 16384UL,
@ -155,6 +213,17 @@ struct metal_memory __metal_dt_mem_dtim_80000000 = {
.A = 1}, .A = 1},
}; };
struct metal_memory __metal_dt_mem_itim_8000000 = {
._base_address = 134217728UL,
._size = 8192UL,
._attrs = {
.R = 1,
.W = 1,
.X = 1,
.C = 1,
.A = 1},
};
struct metal_memory __metal_dt_mem_spi_10014000 = { struct metal_memory __metal_dt_mem_spi_10014000 = {
._base_address = 536870912UL, ._base_address = 536870912UL,
._size = 500000UL, ._size = 500000UL,
@ -166,6 +235,24 @@ struct metal_memory __metal_dt_mem_spi_10014000 = {
.A = 1}, .A = 1},
}; };
struct metal_memory __metal_dt_mem_spi_10024000 = {
._attrs = {
.R = 1,
.W = 1,
.X = 1,
.C = 1,
.A = 1},
};
struct metal_memory __metal_dt_mem_spi_10034000 = {
._attrs = {
.R = 1,
.W = 1,
.X = 1,
.C = 1,
.A = 1},
};
/* From clint@2000000 */ /* From clint@2000000 */
struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000 = { struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000 = {
.controller.vtable = &__metal_driver_vtable_riscv_clint0.clint_vtable, .controller.vtable = &__metal_driver_vtable_riscv_clint0.clint_vtable,
@ -175,6 +262,7 @@ struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000 = {
/* From cpu@0 */ /* From cpu@0 */
struct __metal_driver_cpu __metal_dt_cpu_0 = { struct __metal_driver_cpu __metal_dt_cpu_0 = {
.cpu.vtable = &__metal_driver_vtable_cpu.cpu_vtable, .cpu.vtable = &__metal_driver_vtable_cpu.cpu_vtable,
.hpm_count = 0,
}; };
/* From interrupt_controller */ /* From interrupt_controller */
@ -189,42 +277,83 @@ struct __metal_driver_riscv_plic0 __metal_dt_interrupt_controller_c000000 = {
.init_done = 0, .init_done = 0,
}; };
/* From local_external_interrupts_0 */ struct metal_pmp __metal_dt_pmp;
struct __metal_driver_sifive_local_external_interrupts0 __metal_dt_local_external_interrupts_0 = {
.irc.vtable = &__metal_driver_vtable_sifive_local_external_interrupts0.local0_vtable,
.init_done = 0,
};
/* From gpio@10012000 */ /* From gpio@10012000 */
struct __metal_driver_sifive_gpio0 __metal_dt_gpio_10012000 = { struct __metal_driver_sifive_gpio0 __metal_dt_gpio_10012000 = {
.gpio.vtable = &__metal_driver_vtable_sifive_gpio0.gpio, .gpio.vtable = &__metal_driver_vtable_sifive_gpio0.gpio,
}; };
/* From led@0red */ /* From led@0 */
struct __metal_driver_sifive_gpio_led __metal_dt_led_0red = { struct __metal_driver_sifive_gpio_led __metal_dt_led_0 = {
.led.vtable = &__metal_driver_vtable_sifive_led.led_vtable, .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
}; };
/* From led@0green */ /* From led@1 */
struct __metal_driver_sifive_gpio_led __metal_dt_led_0green = { struct __metal_driver_sifive_gpio_led __metal_dt_led_1 = {
.led.vtable = &__metal_driver_vtable_sifive_led.led_vtable, .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
}; };
/* From led@0blue */ /* From led@2 */
struct __metal_driver_sifive_gpio_led __metal_dt_led_0blue = { struct __metal_driver_sifive_gpio_led __metal_dt_led_2 = {
.led.vtable = &__metal_driver_vtable_sifive_led.led_vtable, .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
}; };
/* From i2c@10016000 */
struct __metal_driver_sifive_i2c0 __metal_dt_i2c_10016000 = {
.i2c.vtable = &__metal_driver_vtable_sifive_i2c0.i2c,
};
/* From pwm@10015000 */
struct __metal_driver_sifive_pwm0 __metal_dt_pwm_10015000 = {
.pwm.vtable = &__metal_driver_vtable_sifive_pwm0.pwm,
};
/* From pwm@10025000 */
struct __metal_driver_sifive_pwm0 __metal_dt_pwm_10025000 = {
.pwm.vtable = &__metal_driver_vtable_sifive_pwm0.pwm,
};
/* From pwm@10035000 */
struct __metal_driver_sifive_pwm0 __metal_dt_pwm_10035000 = {
.pwm.vtable = &__metal_driver_vtable_sifive_pwm0.pwm,
};
/* From aon@10000000 */
struct __metal_driver_sifive_rtc0 __metal_dt_rtc_10000000 = {
.rtc.vtable = &__metal_driver_vtable_sifive_rtc0.rtc,
};
/* From spi@10014000 */ /* From spi@10014000 */
struct __metal_driver_sifive_spi0 __metal_dt_spi_10014000 = { struct __metal_driver_sifive_spi0 __metal_dt_spi_10014000 = {
.spi.vtable = &__metal_driver_vtable_sifive_spi0.spi, .spi.vtable = &__metal_driver_vtable_sifive_spi0.spi,
}; };
/* From spi@10024000 */
struct __metal_driver_sifive_spi0 __metal_dt_spi_10024000 = {
.spi.vtable = &__metal_driver_vtable_sifive_spi0.spi,
};
/* From spi@10034000 */
struct __metal_driver_sifive_spi0 __metal_dt_spi_10034000 = {
.spi.vtable = &__metal_driver_vtable_sifive_spi0.spi,
};
/* From serial@10013000 */ /* From serial@10013000 */
struct __metal_driver_sifive_uart0 __metal_dt_serial_10013000 = { struct __metal_driver_sifive_uart0 __metal_dt_serial_10013000 = {
.uart.vtable = &__metal_driver_vtable_sifive_uart0.uart, .uart.vtable = &__metal_driver_vtable_sifive_uart0.uart,
}; };
/* From serial@10023000 */
struct __metal_driver_sifive_uart0 __metal_dt_serial_10023000 = {
.uart.vtable = &__metal_driver_vtable_sifive_uart0.uart,
};
/* From aon@10000000 */
struct __metal_driver_sifive_wdog0 __metal_dt_aon_10000000 = {
.watchdog.vtable = &__metal_driver_vtable_sifive_wdog0.watchdog,
};
/* From clock@3 */ /* From clock@3 */
struct __metal_driver_sifive_fe310_g000_hfrosc __metal_dt_clock_3 = { struct __metal_driver_sifive_fe310_g000_hfrosc __metal_dt_clock_3 = {
.clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfrosc.clock, .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfrosc.clock,
@ -235,6 +364,11 @@ struct __metal_driver_sifive_fe310_g000_hfxosc __metal_dt_clock_1 = {
.clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfxosc.clock, .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfxosc.clock,
}; };
/* From clock@7 */
struct __metal_driver_sifive_fe310_g000_lfrosc __metal_dt_clock_7 = {
.clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_lfrosc.clock,
};
/* From clock@4 */ /* From clock@4 */
struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4 = { struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4 = {
.clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_pll.clock, .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_pll.clock,
@ -242,8 +376,9 @@ struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4 = {
/* From prci@10008000 */ /* From prci@10008000 */
struct __metal_driver_sifive_fe310_g000_prci __metal_dt_prci_10008000 = { struct __metal_driver_sifive_fe310_g000_prci __metal_dt_prci_10008000 = {
.vtable = &__metal_driver_vtable_sifive_fe310_g000_prci,
}; };
#endif /* SIFIVE_HIFIVE1_REVB____METAL_INLINE_H*/ #endif /* METAL_INLINE_H*/
#endif /* ! ASSEMBLY */ #endif /* ! ASSEMBLY */

View file

@ -3,8 +3,8 @@
/* ----------------------------------- */ /* ----------------------------------- */
/* ----------------------------------- */ /* ----------------------------------- */
#ifndef SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H #ifndef METAL_PLATFORM_H
#define SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H #define METAL_PLATFORM_H
/* From clock@0 */ /* From clock@0 */
#define METAL_FIXED_CLOCK_0_CLOCK_FREQUENCY 16000000UL #define METAL_FIXED_CLOCK_0_CLOCK_FREQUENCY 16000000UL
@ -13,7 +13,10 @@
#define METAL_FIXED_CLOCK_2_CLOCK_FREQUENCY 72000000UL #define METAL_FIXED_CLOCK_2_CLOCK_FREQUENCY 72000000UL
/* From clock@5 */ /* From clock@5 */
#define METAL_FIXED_CLOCK_5_CLOCK_FREQUENCY 32000000UL #define METAL_FIXED_CLOCK_5_CLOCK_FREQUENCY 32768UL
/* From clock@6 */
#define METAL_FIXED_CLOCK_6_CLOCK_FREQUENCY 32768UL
#define METAL_FIXED_CLOCK #define METAL_FIXED_CLOCK
@ -35,15 +38,18 @@
#define METAL_RISCV_PLIC0_0_SIZE 67108864UL #define METAL_RISCV_PLIC0_0_SIZE 67108864UL
#define METAL_RISCV_PLIC0_C000000_RISCV_MAX_PRIORITY 7UL #define METAL_RISCV_PLIC0_C000000_RISCV_MAX_PRIORITY 7UL
#define METAL_RISCV_PLIC0_0_RISCV_MAX_PRIORITY 7UL #define METAL_RISCV_PLIC0_0_RISCV_MAX_PRIORITY 7UL
#define METAL_RISCV_PLIC0_C000000_RISCV_NDEV 27UL #define METAL_RISCV_PLIC0_C000000_RISCV_NDEV 53UL
#define METAL_RISCV_PLIC0_0_RISCV_NDEV 27UL #define METAL_RISCV_PLIC0_0_RISCV_NDEV 53UL
#define METAL_RISCV_PLIC0 #define METAL_RISCV_PLIC0
#define METAL_RISCV_PLIC0_PRIORITY_BASE 0UL #define METAL_RISCV_PLIC0_PRIORITY_BASE 0UL
#define METAL_RISCV_PLIC0_PENDING_BASE 4096UL #define METAL_RISCV_PLIC0_PENDING_BASE 4096UL
#define METAL_RISCV_PLIC0_ENABLE_BASE 8192UL #define METAL_RISCV_PLIC0_ENABLE_BASE 8192UL
#define METAL_RISCV_PLIC0_THRESHOLD 2097152UL #define METAL_RISCV_PLIC0_ENABLE_PER_HART 128UL
#define METAL_RISCV_PLIC0_CLAIM 2097156UL #define METAL_RISCV_PLIC0_CONTEXT_BASE 2097152UL
#define METAL_RISCV_PLIC0_CONTEXT_PER_HART 4096UL
#define METAL_RISCV_PLIC0_CONTEXT_THRESHOLD 0UL
#define METAL_RISCV_PLIC0_CONTEXT_CLAIM 4UL
/* From aon@10000000 */ /* From aon@10000000 */
#define METAL_SIFIVE_AON0_10000000_BASE_ADDRESS 268435456UL #define METAL_SIFIVE_AON0_10000000_BASE_ADDRESS 268435456UL
@ -111,6 +117,10 @@
#define METAL_SIFIVE_FE310_G000_HFXOSC #define METAL_SIFIVE_FE310_G000_HFXOSC
/* From clock@7 */
#define METAL_SIFIVE_FE310_G000_LFROSC
/* From prci@10008000 */ /* From prci@10008000 */
#define METAL_SIFIVE_FE310_G000_PRCI_10008000_BASE_ADDRESS 268468224UL #define METAL_SIFIVE_FE310_G000_PRCI_10008000_BASE_ADDRESS 268468224UL
#define METAL_SIFIVE_FE310_G000_PRCI_0_BASE_ADDRESS 268468224UL #define METAL_SIFIVE_FE310_G000_PRCI_0_BASE_ADDRESS 268468224UL
@ -153,11 +163,11 @@
#define METAL_SIFIVE_GPIO0_IOF_SEL 60UL #define METAL_SIFIVE_GPIO0_IOF_SEL 60UL
#define METAL_SIFIVE_GPIO0_OUT_XOR 64UL #define METAL_SIFIVE_GPIO0_OUT_XOR 64UL
/* From led@0red */ /* From led@0 */
/* From led@0green */ /* From led@1 */
/* From led@0blue */ /* From led@2 */
#define METAL_SIFIVE_GPIO_LEDS #define METAL_SIFIVE_GPIO_LEDS
@ -176,16 +186,24 @@
#define METAL_SIFIVE_I2C0_COMMAND 16UL #define METAL_SIFIVE_I2C0_COMMAND 16UL
#define METAL_SIFIVE_I2C0_STATUS 16UL #define METAL_SIFIVE_I2C0_STATUS 16UL
/* From local_external_interrupts_0 */
#define METAL_SIFIVE_LOCAL_EXTERNAL_INTERRUPTS0
/* From pwm@10015000 */ /* From pwm@10015000 */
#define METAL_SIFIVE_PWM0_10015000_BASE_ADDRESS 268521472UL #define METAL_SIFIVE_PWM0_10015000_BASE_ADDRESS 268521472UL
#define METAL_SIFIVE_PWM0_0_BASE_ADDRESS 268521472UL #define METAL_SIFIVE_PWM0_0_BASE_ADDRESS 268521472UL
#define METAL_SIFIVE_PWM0_10015000_SIZE 4096UL #define METAL_SIFIVE_PWM0_10015000_SIZE 4096UL
#define METAL_SIFIVE_PWM0_0_SIZE 4096UL #define METAL_SIFIVE_PWM0_0_SIZE 4096UL
/* From pwm@10025000 */
#define METAL_SIFIVE_PWM0_10025000_BASE_ADDRESS 268587008UL
#define METAL_SIFIVE_PWM0_1_BASE_ADDRESS 268587008UL
#define METAL_SIFIVE_PWM0_10025000_SIZE 4096UL
#define METAL_SIFIVE_PWM0_1_SIZE 4096UL
/* From pwm@10035000 */
#define METAL_SIFIVE_PWM0_10035000_BASE_ADDRESS 268652544UL
#define METAL_SIFIVE_PWM0_2_BASE_ADDRESS 268652544UL
#define METAL_SIFIVE_PWM0_10035000_SIZE 4096UL
#define METAL_SIFIVE_PWM0_2_SIZE 4096UL
#define METAL_SIFIVE_PWM0 #define METAL_SIFIVE_PWM0
#define METAL_SIFIVE_PWM0_PWMCFG 0UL #define METAL_SIFIVE_PWM0_PWMCFG 0UL
#define METAL_SIFIVE_PWM0_PWMCOUNT 8UL #define METAL_SIFIVE_PWM0_PWMCOUNT 8UL
@ -195,12 +213,37 @@
#define METAL_SIFIVE_PWM0_PWMCMP2 40UL #define METAL_SIFIVE_PWM0_PWMCMP2 40UL
#define METAL_SIFIVE_PWM0_PWMCMP3 44UL #define METAL_SIFIVE_PWM0_PWMCMP3 44UL
/* From aon@10000000 */
#define METAL_SIFIVE_AON0_10000000_BASE_ADDRESS 268435456UL
#define METAL_SIFIVE_AON0_0_BASE_ADDRESS 268435456UL
#define METAL_SIFIVE_AON0_10000000_SIZE 32768UL
#define METAL_SIFIVE_AON0_0_SIZE 32768UL
#define METAL_SIFIVE_RTC0
#define METAL_SIFIVE_RTC0_RTCCFG 64UL
#define METAL_SIFIVE_RTC0_RTCCOUNTLO 72UL
#define METAL_SIFIVE_RTC0_RTCCOUNTHI 76UL
#define METAL_SIFIVE_RTC0_RTCS 80UL
#define METAL_SIFIVE_RTC0_RTCCMP0 96UL
/* From spi@10014000 */ /* From spi@10014000 */
#define METAL_SIFIVE_SPI0_10014000_BASE_ADDRESS 268517376UL #define METAL_SIFIVE_SPI0_10014000_BASE_ADDRESS 268517376UL
#define METAL_SIFIVE_SPI0_0_BASE_ADDRESS 268517376UL #define METAL_SIFIVE_SPI0_0_BASE_ADDRESS 268517376UL
#define METAL_SIFIVE_SPI0_10014000_SIZE 4096UL #define METAL_SIFIVE_SPI0_10014000_SIZE 4096UL
#define METAL_SIFIVE_SPI0_0_SIZE 4096UL #define METAL_SIFIVE_SPI0_0_SIZE 4096UL
/* From spi@10024000 */
#define METAL_SIFIVE_SPI0_10024000_BASE_ADDRESS 268582912UL
#define METAL_SIFIVE_SPI0_1_BASE_ADDRESS 268582912UL
#define METAL_SIFIVE_SPI0_10024000_SIZE 4096UL
#define METAL_SIFIVE_SPI0_1_SIZE 4096UL
/* From spi@10034000 */
#define METAL_SIFIVE_SPI0_10034000_BASE_ADDRESS 268648448UL
#define METAL_SIFIVE_SPI0_2_BASE_ADDRESS 268648448UL
#define METAL_SIFIVE_SPI0_10034000_SIZE 4096UL
#define METAL_SIFIVE_SPI0_2_SIZE 4096UL
#define METAL_SIFIVE_SPI0 #define METAL_SIFIVE_SPI0
#define METAL_SIFIVE_SPI0_SCKDIV 0UL #define METAL_SIFIVE_SPI0_SCKDIV 0UL
#define METAL_SIFIVE_SPI0_SCKMODE 4UL #define METAL_SIFIVE_SPI0_SCKMODE 4UL
@ -225,6 +268,12 @@
#define METAL_SIFIVE_UART0_10013000_SIZE 4096UL #define METAL_SIFIVE_UART0_10013000_SIZE 4096UL
#define METAL_SIFIVE_UART0_0_SIZE 4096UL #define METAL_SIFIVE_UART0_0_SIZE 4096UL
/* From serial@10023000 */
#define METAL_SIFIVE_UART0_10023000_BASE_ADDRESS 268578816UL
#define METAL_SIFIVE_UART0_1_BASE_ADDRESS 268578816UL
#define METAL_SIFIVE_UART0_10023000_SIZE 4096UL
#define METAL_SIFIVE_UART0_1_SIZE 4096UL
#define METAL_SIFIVE_UART0 #define METAL_SIFIVE_UART0
#define METAL_SIFIVE_UART0_TXDATA 0UL #define METAL_SIFIVE_UART0_TXDATA 0UL
#define METAL_SIFIVE_UART0_RXDATA 4UL #define METAL_SIFIVE_UART0_RXDATA 4UL
@ -234,4 +283,20 @@
#define METAL_SIFIVE_UART0_IP 20UL #define METAL_SIFIVE_UART0_IP 20UL
#define METAL_SIFIVE_UART0_DIV 24UL #define METAL_SIFIVE_UART0_DIV 24UL
#endif /* SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H*/ /* From aon@10000000 */
#define METAL_SIFIVE_AON0_10000000_BASE_ADDRESS 268435456UL
#define METAL_SIFIVE_AON0_0_BASE_ADDRESS 268435456UL
#define METAL_SIFIVE_AON0_10000000_SIZE 32768UL
#define METAL_SIFIVE_AON0_0_SIZE 32768UL
#define METAL_SIFIVE_WDOG0
#define METAL_SIFIVE_WDOG0_MAGIC_KEY 5370206UL
#define METAL_SIFIVE_WDOG0_MAGIC_FOOD 218755085UL
#define METAL_SIFIVE_WDOG0_WDOGCFG 0UL
#define METAL_SIFIVE_WDOG0_WDOGCOUNT 8UL
#define METAL_SIFIVE_WDOG0_WDOGS 16UL
#define METAL_SIFIVE_WDOG0_WDOGFEED 24UL
#define METAL_SIFIVE_WDOG0_WDOGKEY 28UL
#define METAL_SIFIVE_WDOG0_WDOGCMP 32UL
#endif /* METAL_PLATFORM_H*/

View file

@ -4,8 +4,8 @@
#ifndef METAL__MEMORY_H #ifndef METAL__MEMORY_H
#define METAL__MEMORY_H #define METAL__MEMORY_H
#include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
/*! /*!
* @file memory.h * @file memory.h
@ -14,20 +14,20 @@
*/ */
struct _metal_memory_attributes { struct _metal_memory_attributes {
int R : 1; unsigned int R : 1;
int W : 1; unsigned int W : 1;
int X : 1; unsigned int X : 1;
int C : 1; unsigned int C : 1;
int A : 1; unsigned int A : 1;
}; };
/*! /*!
* @brief A handle for a memory block * @brief A handle for a memory block
*/ */
struct metal_memory { struct metal_memory {
const uintptr_t _base_address; const uintptr_t _base_address;
const size_t _size; const size_t _size;
const struct _metal_memory_attributes _attrs; const struct _metal_memory_attributes _attrs;
}; };
/*! /*!
@ -37,7 +37,8 @@ struct metal_memory {
* that address is mapped. * that address is mapped.
* *
* @param address The address to query * @param address The address to query
* @return The memory block handle, or NULL if the address is not mapped to a memory block * @return The memory block handle, or NULL if the address is not mapped to a
* memory block
*/ */
struct metal_memory *metal_get_memory_from_address(const uintptr_t address); struct metal_memory *metal_get_memory_from_address(const uintptr_t address);
@ -46,8 +47,9 @@ struct metal_memory *metal_get_memory_from_address(const uintptr_t address);
* @param memory The handle for the memory block * @param memory The handle for the memory block
* @return The base address of the memory block * @return The base address of the memory block
*/ */
inline uintptr_t metal_memory_get_base_address(const struct metal_memory *memory) { __inline__ uintptr_t
return memory->_base_address; metal_memory_get_base_address(const struct metal_memory *memory) {
return memory->_base_address;
} }
/*! /*!
@ -55,8 +57,8 @@ inline uintptr_t metal_memory_get_base_address(const struct metal_memory *memory
* @param memory The handle for the memory block * @param memory The handle for the memory block
* @return The size of the memory block * @return The size of the memory block
*/ */
inline size_t metal_memory_get_size(const struct metal_memory *memory) { __inline__ size_t metal_memory_get_size(const struct metal_memory *memory) {
return memory->_size; return memory->_size;
} }
/*! /*!
@ -64,8 +66,9 @@ inline size_t metal_memory_get_size(const struct metal_memory *memory) {
* @param memory The handle for the memory block * @param memory The handle for the memory block
* @return nonzero if the memory block supports atomic operations * @return nonzero if the memory block supports atomic operations
*/ */
inline int metal_memory_supports_atomics(const struct metal_memory *memory) { __inline__ int
return memory->_attrs.A; metal_memory_supports_atomics(const struct metal_memory *memory) {
return memory->_attrs.A;
} }
/*! /*!
@ -73,9 +76,8 @@ inline int metal_memory_supports_atomics(const struct metal_memory *memory) {
* @param memory The handle for the memory block * @param memory The handle for the memory block
* @return nonzero if the memory block is cachable * @return nonzero if the memory block is cachable
*/ */
inline int metal_memory_is_cachable(const struct metal_memory *memory) { __inline__ int metal_memory_is_cachable(const struct metal_memory *memory) {
return memory->_attrs.C; return memory->_attrs.C;
} }
#endif /* METAL__MEMORY_H */ #endif /* METAL__MEMORY_H */

View file

@ -18,8 +18,8 @@
* can be found by reading the RISC-V Privileged Architecture Specification. * can be found by reading the RISC-V Privileged Architecture Specification.
*/ */
#include <stddef.h>
#include <metal/machine.h> #include <metal/machine.h>
#include <stddef.h>
struct metal_pmp; struct metal_pmp;
@ -28,11 +28,11 @@ struct metal_pmp;
*/ */
enum metal_pmp_address_mode { enum metal_pmp_address_mode {
/*! @brief Disable the PMP region */ /*! @brief Disable the PMP region */
METAL_PMP_OFF = 0, METAL_PMP_OFF = 0,
/*! @brief Use Top-of-Range mode */ /*! @brief Use Top-of-Range mode */
METAL_PMP_TOR = 1, METAL_PMP_TOR = 1,
/*! @brief Use naturally-aligned 4-byte region mode */ /*! @brief Use naturally-aligned 4-byte region mode */
METAL_PMP_NA4 = 2, METAL_PMP_NA4 = 2,
/*! @brief Use naturally-aligned power-of-two mode */ /*! @brief Use naturally-aligned power-of-two mode */
METAL_PMP_NAPOT = 3 METAL_PMP_NAPOT = 3
}; };
@ -42,11 +42,11 @@ enum metal_pmp_address_mode {
*/ */
struct metal_pmp_config { struct metal_pmp_config {
/*! @brief Sets whether reads to the PMP region succeed */ /*! @brief Sets whether reads to the PMP region succeed */
int R : 1; unsigned int R : 1;
/*! @brief Sets whether writes to the PMP region succeed */ /*! @brief Sets whether writes to the PMP region succeed */
int W : 1; unsigned int W : 1;
/*! @brief Sets whether the PMP region is executable */ /*! @brief Sets whether the PMP region is executable */
int X : 1; unsigned int X : 1;
/*! @brief Sets the addressing mode of the PMP region */ /*! @brief Sets the addressing mode of the PMP region */
enum metal_pmp_address_mode A : 2; enum metal_pmp_address_mode A : 2;
@ -56,7 +56,7 @@ struct metal_pmp_config {
/*! @brief Sets whether the PMP region is locked */ /*! @brief Sets whether the PMP region is locked */
enum metal_pmp_locked { enum metal_pmp_locked {
METAL_PMP_UNLOCKED = 0, METAL_PMP_UNLOCKED = 0,
METAL_PMP_LOCKED = 1 METAL_PMP_LOCKED = 1
} L : 1; } L : 1;
}; };
@ -73,6 +73,11 @@ struct metal_pmp {
*/ */
struct metal_pmp *metal_pmp_get_device(void); struct metal_pmp *metal_pmp_get_device(void);
/*!
* @brief Get the number of pmp regions for the hartid
*/
int metal_pmp_num_regions(int hartid);
/*! /*!
* @brief Initialize the PMP * @brief Initialize the PMP
* @param pmp The PMP device handle to be initialized * @param pmp The PMP device handle to be initialized
@ -96,7 +101,8 @@ void metal_pmp_init(struct metal_pmp *pmp);
* @param address The desired address of the PMP region * @param address The desired address of the PMP region
* @return 0 upon success * @return 0 upon success
*/ */
int metal_pmp_set_region(struct metal_pmp *pmp, unsigned int region, struct metal_pmp_config config, size_t address); int metal_pmp_set_region(struct metal_pmp *pmp, unsigned int region,
struct metal_pmp_config config, size_t address);
/*! /*!
* @brief Get the configuration for a PMP region * @brief Get the configuration for a PMP region
@ -106,7 +112,8 @@ int metal_pmp_set_region(struct metal_pmp *pmp, unsigned int region, struct meta
* @param address Variable to store the PMP region address * @param address Variable to store the PMP region address
* @return 0 if the region is read successfully * @return 0 if the region is read successfully
*/ */
int metal_pmp_get_region(struct metal_pmp *pmp, unsigned int region, struct metal_pmp_config *config, size_t *address); int metal_pmp_get_region(struct metal_pmp *pmp, unsigned int region,
struct metal_pmp_config *config, size_t *address);
/*! /*!
* @brief Lock a PMP region * @brief Lock a PMP region
@ -123,7 +130,8 @@ int metal_pmp_lock(struct metal_pmp *pmp, unsigned int region);
* @param address The desired address of the PMP region * @param address The desired address of the PMP region
* @return 0 if the address is successfully set * @return 0 if the address is successfully set
*/ */
int metal_pmp_set_address(struct metal_pmp *pmp, unsigned int region, size_t address); int metal_pmp_set_address(struct metal_pmp *pmp, unsigned int region,
size_t address);
/*! /*!
* @brief Get the address of a PMP region * @brief Get the address of a PMP region
@ -140,7 +148,8 @@ size_t metal_pmp_get_address(struct metal_pmp *pmp, unsigned int region);
* @param mode The PMP addressing mode to set * @param mode The PMP addressing mode to set
* @return 0 if the addressing mode is successfully set * @return 0 if the addressing mode is successfully set
*/ */
int metal_pmp_set_address_mode(struct metal_pmp *pmp, unsigned int region, enum metal_pmp_address_mode mode); int metal_pmp_set_address_mode(struct metal_pmp *pmp, unsigned int region,
enum metal_pmp_address_mode mode);
/*! /*!
* @brief Get the addressing mode of a PMP region * @brief Get the addressing mode of a PMP region
@ -148,7 +157,8 @@ int metal_pmp_set_address_mode(struct metal_pmp *pmp, unsigned int region, enum
* @param region The PMP region to read * @param region The PMP region to read
* @return The address mode of the PMP region * @return The address mode of the PMP region
*/ */
enum metal_pmp_address_mode metal_pmp_get_address_mode(struct metal_pmp *pmp, unsigned int region); enum metal_pmp_address_mode metal_pmp_get_address_mode(struct metal_pmp *pmp,
unsigned int region);
/*! /*!
* @brief Set the executable bit for a PMP region * @brief Set the executable bit for a PMP region

View file

@ -16,9 +16,9 @@
#include <stdint.h> #include <stdint.h>
enum metal_privilege_mode { enum metal_privilege_mode {
METAL_PRIVILEGE_USER = 0, METAL_PRIVILEGE_USER = 0,
METAL_PRIVILEGE_SUPERVISOR = 1, METAL_PRIVILEGE_SUPERVISOR = 1,
METAL_PRIVELEGE_MACHINE = 3, METAL_PRIVILEGE_MACHINE = 3,
}; };
#if __riscv_xlen == 32 #if __riscv_xlen == 32
@ -34,89 +34,89 @@ typedef uint64_t metal_freg_t;
#endif #endif
struct metal_register_file { struct metal_register_file {
metal_xreg_t ra; metal_xreg_t ra;
metal_xreg_t sp; metal_xreg_t sp;
metal_xreg_t gp; metal_xreg_t gp;
metal_xreg_t tp; metal_xreg_t tp;
metal_xreg_t t0; metal_xreg_t t0;
metal_xreg_t t1; metal_xreg_t t1;
metal_xreg_t t2; metal_xreg_t t2;
metal_xreg_t s0; metal_xreg_t s0;
metal_xreg_t s1; metal_xreg_t s1;
metal_xreg_t a0; metal_xreg_t a0;
metal_xreg_t a1; metal_xreg_t a1;
metal_xreg_t a2; metal_xreg_t a2;
metal_xreg_t a3; metal_xreg_t a3;
metal_xreg_t a4; metal_xreg_t a4;
metal_xreg_t a5; metal_xreg_t a5;
#ifndef __riscv_32e #ifndef __riscv_32e
metal_xreg_t a6; metal_xreg_t a6;
metal_xreg_t a7; metal_xreg_t a7;
metal_xreg_t s2; metal_xreg_t s2;
metal_xreg_t s3; metal_xreg_t s3;
metal_xreg_t s4; metal_xreg_t s4;
metal_xreg_t s5; metal_xreg_t s5;
metal_xreg_t s6; metal_xreg_t s6;
metal_xreg_t s7; metal_xreg_t s7;
metal_xreg_t s8; metal_xreg_t s8;
metal_xreg_t s9; metal_xreg_t s9;
metal_xreg_t s10; metal_xreg_t s10;
metal_xreg_t s11; metal_xreg_t s11;
metal_xreg_t t3; metal_xreg_t t3;
metal_xreg_t t4; metal_xreg_t t4;
metal_xreg_t t5; metal_xreg_t t5;
metal_xreg_t t6; metal_xreg_t t6;
#endif /* __riscv_32e */ #endif /* __riscv_32e */
#ifdef __riscv_flen #ifdef __riscv_flen
metal_freg_t ft0; metal_freg_t ft0;
metal_freg_t ft1; metal_freg_t ft1;
metal_freg_t ft2; metal_freg_t ft2;
metal_freg_t ft3; metal_freg_t ft3;
metal_freg_t ft4; metal_freg_t ft4;
metal_freg_t ft5; metal_freg_t ft5;
metal_freg_t ft6; metal_freg_t ft6;
metal_freg_t ft7; metal_freg_t ft7;
metal_freg_t fs0; metal_freg_t fs0;
metal_freg_t fs1; metal_freg_t fs1;
metal_freg_t fa0; metal_freg_t fa0;
metal_freg_t fa1; metal_freg_t fa1;
metal_freg_t fa2; metal_freg_t fa2;
metal_freg_t fa3; metal_freg_t fa3;
metal_freg_t fa4; metal_freg_t fa4;
metal_freg_t fa5; metal_freg_t fa5;
metal_freg_t fa6; metal_freg_t fa6;
metal_freg_t fa7; metal_freg_t fa7;
metal_freg_t fs2; metal_freg_t fs2;
metal_freg_t fs3; metal_freg_t fs3;
metal_freg_t fs4; metal_freg_t fs4;
metal_freg_t fs5; metal_freg_t fs5;
metal_freg_t fs6; metal_freg_t fs6;
metal_freg_t fs7; metal_freg_t fs7;
metal_freg_t fs8; metal_freg_t fs8;
metal_freg_t fs9; metal_freg_t fs9;
metal_freg_t fs10; metal_freg_t fs10;
metal_freg_t fs11; metal_freg_t fs11;
metal_freg_t ft8; metal_freg_t ft8;
metal_freg_t ft9; metal_freg_t ft9;
metal_freg_t ft10; metal_freg_t ft10;
metal_freg_t ft11; metal_freg_t ft11;
#endif /* __riscv_flen */ #endif /* __riscv_flen */
}; };
typedef void (*metal_privilege_entry_point_t)(); typedef void (*metal_privilege_entry_point_t)(void);
void metal_privilege_drop_to_mode(enum metal_privilege_mode mode, void metal_privilege_drop_to_mode(enum metal_privilege_mode mode,
struct metal_register_file regfile, struct metal_register_file regfile,
metal_privilege_entry_point_t entry_point); metal_privilege_entry_point_t entry_point);
#endif #endif

View file

@ -0,0 +1,162 @@
/* Copyright 2020 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__PWM_H
#define METAL__PWM_H
/*! @brief Enums for PWM running modes. */
typedef enum {
METAL_PWM_CONTINUOUS = 0,
METAL_PWM_ONE_SHOT = 1
} metal_pwm_run_mode_t;
/*! @brief Enums for Phase correct PWM. */
typedef enum {
METAL_PWM_PHASE_CORRECT_DISABLE = 0,
METAL_PWM_PHASE_CORRECT_ENABLE = 1,
} metal_pwm_phase_correct_t;
/*! @brief Enums for Interrupts enable/disable. */
typedef enum {
METAL_PWM_INTERRUPT_DISABLE = 0,
METAL_PWM_INTERRUPT_ENABLE = 1,
} metal_pwm_interrupt_t;
struct metal_pwm;
/*! @brief vtable for PWM. */
struct metal_pwm_vtable {
int (*enable)(struct metal_pwm *pwm);
int (*disable)(struct metal_pwm *pwm);
int (*set_freq)(struct metal_pwm *pwm, unsigned int idx, unsigned int freq);
int (*set_duty)(struct metal_pwm *pwm, unsigned int idx, unsigned int duty,
metal_pwm_phase_correct_t phase_corr);
unsigned int (*get_duty)(struct metal_pwm *pwm, unsigned int idx);
unsigned int (*get_freq)(struct metal_pwm *pwm, unsigned int idx);
int (*trigger)(struct metal_pwm *pwm, unsigned int idx,
metal_pwm_run_mode_t mode);
int (*stop)(struct metal_pwm *pwm, unsigned int idx);
int (*cfg_interrupt)(struct metal_pwm *pwm, metal_pwm_interrupt_t flag);
int (*clr_interrupt)(struct metal_pwm *pwm, unsigned int idx);
struct metal_interrupt *(*get_interrupt_controller)(struct metal_pwm *pwm);
int (*get_interrupt_id)(struct metal_pwm *pwm, unsigned int idx);
};
/*! @brief A handle for a PWM device. */
struct metal_pwm {
const struct metal_pwm_vtable *vtable;
};
/*! @brief Gets a PWM device handle.
* @param device_num The index of the desired PWM device.
* @return A handle to the PWM device, or NULL if the device does not exist.*/
struct metal_pwm *metal_pwm_get_device(unsigned int device_num);
/*! @brief Enables PWM operation.
* @param pwm The handle for the PWM device to initialize.
* @return 0 If no error.*/
inline int metal_pwm_enable(struct metal_pwm *pwm) {
return pwm->vtable->enable(pwm);
}
/*! @brief Disables PWM operation.
* @param pwm The handle for the PWM device to be disabled.
* @return 0 If no error.*/
inline int metal_pwm_disable(struct metal_pwm *pwm) {
return pwm->vtable->disable(pwm);
}
/*! @brief Sets frequency in Hz for a given PWM instance.
* @param pwm PWM device handle.
* @param idx PWM channel id.
* @param freq PWM frequency in Hz.
* @return 0 If no error.*/
inline int metal_pwm_set_freq(struct metal_pwm *pwm, unsigned int idx,
unsigned int freq) {
return pwm->vtable->set_freq(pwm, idx, freq);
}
/*! @brief Sets duty cycle in percent values [0 - 100] for a given PWM instance.
* Phase correct mode provides center aligned PWM waveform output.
* @param pwm PWM device handle.
* @param idx PWM channel id.
* @param duty PWM duty cycle value.
* @param phase_corr Enable / Disable phase correct mode.
* @return 0 If no error.*/
inline int metal_pwm_set_duty(struct metal_pwm *pwm, unsigned int idx,
unsigned int duty,
metal_pwm_phase_correct_t phase_corr) {
return pwm->vtable->set_duty(pwm, idx, duty, phase_corr);
}
/*! @brief Gets duty cycle in percent values [0 - 100] for a given PWM instance.
* @param pwm PWM device handle.
* @param idx PWM channel id.
* @return PWM duty cycle value.*/
inline unsigned int metal_pwm_get_duty(struct metal_pwm *pwm,
unsigned int idx) {
return pwm->vtable->get_duty(pwm, idx);
}
/*! @brief Gets frequency in Hz for a given PWM instance.
* @param pwm PWM device handle.
* @param idx PWM channel id.
* @return PWM frequency in Hz.*/
inline unsigned int metal_pwm_get_freq(struct metal_pwm *pwm,
unsigned int idx) {
return pwm->vtable->get_freq(pwm, idx);
}
/*! @brief Starts a PWM instance in selected run mode (continuous/one shot).
* @param pwm PWM device handle.
* @param idx PWM channel id.
* @return 0 If no error.*/
inline int metal_pwm_trigger(struct metal_pwm *pwm, unsigned int idx,
metal_pwm_run_mode_t mode) {
return pwm->vtable->trigger(pwm, idx, mode);
}
/*! @brief Stops a running PWM instance in continuous mode.
* @param pwm PWM device handle.
* @param idx PWM channel id.
* @return 0 If no error.*/
inline int metal_pwm_stop(struct metal_pwm *pwm, unsigned int idx) {
return pwm->vtable->stop(pwm, idx);
}
/*! @brief Enable or Disable PWM interrupts.
* @param pwm PWM device handle.
* @param flag PWM interrupt enable flag.
* @return 0 If no error.*/
inline int metal_pwm_cfg_interrupt(struct metal_pwm *pwm,
metal_pwm_interrupt_t flag) {
return pwm->vtable->cfg_interrupt(pwm, flag);
}
/*! @brief Clears pending interrupt flags.
* @param pwm PWM device handle.
* @param idx PWM channel id.
* @return 0 If no error.*/
inline int metal_pwm_clr_interrupt(struct metal_pwm *pwm, unsigned int idx) {
return pwm->vtable->clr_interrupt(pwm, idx);
}
/*! @brief Get the interrupt controller of the PWM peripheral.
* The interrupt controller must be initialized before any interrupts can be
* registered or enabled with it.
* @param pwm PWM device handle.
* @return The handle for the PWM interrupt controller.*/
inline struct metal_interrupt *
metal_pwm_interrupt_controller(struct metal_pwm *pwm) {
return pwm->vtable->get_interrupt_controller(pwm);
}
/*! @brief Get the interrupt ID of the PWM peripheral.
* @param pwm PWM device handle.
* @param idx PWM channel id.
* @return The PWM interrupt id.*/
inline int metal_pwm_get_interrupt_id(struct metal_pwm *pwm, unsigned int idx) {
return pwm->vtable->get_interrupt_id(pwm, idx);
}
#endif

View file

@ -0,0 +1,137 @@
/* Copyright 2019 SiFive, Inc. */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__RTC_H
#define METAL__RTC_H
#include <stdint.h>
/*!
* @file rtc.h
* @brief API for Real-Time Clocks
*/
struct metal_rtc;
/*!
* @brief List of RTC run behaviors
*/
enum metal_rtc_run_option {
METAL_RTC_STOP = 0,
METAL_RTC_RUN,
};
struct metal_rtc_vtable {
uint64_t (*get_rate)(const struct metal_rtc *const rtc);
uint64_t (*set_rate)(const struct metal_rtc *const rtc,
const uint64_t rate);
uint64_t (*get_compare)(const struct metal_rtc *const rtc);
uint64_t (*set_compare)(const struct metal_rtc *const rtc,
const uint64_t compare);
uint64_t (*get_count)(const struct metal_rtc *const rtc);
uint64_t (*set_count)(const struct metal_rtc *const rtc,
const uint64_t count);
int (*run)(const struct metal_rtc *const rtc,
const enum metal_rtc_run_option option);
struct metal_interrupt *(*get_interrupt)(const struct metal_rtc *const rtc);
int (*get_interrupt_id)(const struct metal_rtc *const rtc);
};
/*!
* @brief Handle for a Real-Time Clock
*/
struct metal_rtc {
const struct metal_rtc_vtable *vtable;
};
/*!
* @brief Get the rate of the RTC
* @return The rate in Hz
*/
inline uint64_t metal_rtc_get_rate(const struct metal_rtc *const rtc) {
return rtc->vtable->get_rate(rtc);
}
/*!
* @brief Set (if possible) the rate of the RTC
* @return The new rate of the RTC (not guaranteed to be the same as requested)
*/
inline uint64_t metal_rtc_set_rate(const struct metal_rtc *const rtc,
const uint64_t rate) {
return rtc->vtable->set_rate(rtc, rate);
}
/*!
* @brief Get the compare value of the RTC
* @return The compare value
*/
inline uint64_t metal_rtc_get_compare(const struct metal_rtc *const rtc) {
return rtc->vtable->get_compare(rtc);
}
/*!
* @brief Set the compare value of the RTC
* @return The set compare value (not guaranteed to be exactly the requested
* value)
*
* The RTC device might impose limits on the maximum compare value or the
* granularity of the compare value.
*/
inline uint64_t metal_rtc_set_compare(const struct metal_rtc *const rtc,
const uint64_t compare) {
return rtc->vtable->set_compare(rtc, compare);
}
/*!
* @brief Get the current count of the RTC
* @return The count
*/
inline uint64_t metal_rtc_get_count(const struct metal_rtc *const rtc) {
return rtc->vtable->get_count(rtc);
}
/*!
* @brief Set the current count of the RTC
* @return The set value of the count (not guaranteed to be exactly the
* requested value)
*
* The RTC device might impose limits on the maximum value of the count
*/
inline uint64_t metal_rtc_set_count(const struct metal_rtc *const rtc,
const uint64_t count) {
return rtc->vtable->set_count(rtc, count);
}
/*!
* @brief Start or stop the RTC
* @return 0 if the RTC was successfully started/stopped
*/
inline int metal_rtc_run(const struct metal_rtc *const rtc,
const enum metal_rtc_run_option option) {
return rtc->vtable->run(rtc, option);
}
/*!
* @brief Get the interrupt handle for the RTC compare
* @return The interrupt handle
*/
inline struct metal_interrupt *
metal_rtc_get_interrupt(const struct metal_rtc *const rtc) {
return rtc->vtable->get_interrupt(rtc);
}
/*!
* @brief Get the interrupt ID for the RTC compare
* @return The interrupt ID
*/
inline int metal_rtc_get_interrupt_id(const struct metal_rtc *const rtc) {
return rtc->vtable->get_interrupt_id(rtc);
}
/*!
* @brief Get the handle for an RTC by index
* @return The RTC handle, or NULL if none is available at that index
*/
struct metal_rtc *metal_rtc_get_device(int index);
#endif

View file

@ -0,0 +1,13 @@
/* Copyright 2020 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__SCRUB_H
#define METAL__SCRUB_H
/*! @brief Writes specified memory region with zeros.
* @param address Start memory address for zero-scrub.
* @param size Memory region size in bytes.
* @return None.*/
void metal_mem_scrub(void *address, int size);
#endif

View file

@ -12,15 +12,20 @@
struct __metal_shutdown; struct __metal_shutdown;
struct __metal_shutdown_vtable { struct __metal_shutdown_vtable {
void (*exit)(const struct __metal_shutdown *sd, int code) __attribute__((noreturn)); void (*exit)(const struct __metal_shutdown *sd, int code)
__attribute__((noreturn));
}; };
struct __metal_shutdown { struct __metal_shutdown {
const struct __metal_shutdown_vtable *vtable; const struct __metal_shutdown_vtable *vtable;
}; };
inline void __metal_shutdown_exit(const struct __metal_shutdown *sd, int code) __attribute__((noreturn)); __inline__ void __metal_shutdown_exit(const struct __metal_shutdown *sd,
inline void __metal_shutdown_exit(const struct __metal_shutdown *sd, int code) { sd->vtable->exit(sd, code); } int code) __attribute__((noreturn));
__inline__ void __metal_shutdown_exit(const struct __metal_shutdown *sd,
int code) {
sd->vtable->exit(sd, code);
}
/*! /*!
* @brief The public METAL shutdown interface * @brief The public METAL shutdown interface

View file

@ -9,11 +9,7 @@ struct metal_spi;
/*! @brief The configuration for a SPI transfer */ /*! @brief The configuration for a SPI transfer */
struct metal_spi_config { struct metal_spi_config {
/*! @brief The protocol for the SPI transfer */ /*! @brief The protocol for the SPI transfer */
enum { enum { METAL_SPI_SINGLE, METAL_SPI_DUAL, METAL_SPI_QUAD } protocol;
METAL_SPI_SINGLE,
METAL_SPI_DUAL,
METAL_SPI_QUAD
} protocol;
/*! @brief The polarity of the SPI transfer, equivalent to CPOL */ /*! @brief The polarity of the SPI transfer, equivalent to CPOL */
unsigned int polarity : 1; unsigned int polarity : 1;
@ -25,11 +21,24 @@ struct metal_spi_config {
unsigned int cs_active_high : 1; unsigned int cs_active_high : 1;
/*! @brief The chip select ID to activate for the SPI transfer */ /*! @brief The chip select ID to activate for the SPI transfer */
unsigned int csid; unsigned int csid;
/*! @brief The spi command frame number (cycles = num * frame_len) */
unsigned int cmd_num;
/*! @brief The spi address frame number */
unsigned int addr_num;
/*! @brief The spi dummy frame number */
unsigned int dummy_num;
/*! @brief The Dual/Quad spi mode selection.*/
enum {
MULTI_WIRE_ALL,
MULTI_WIRE_DATA_ONLY,
MULTI_WIRE_ADDR_DATA
} multi_wire;
}; };
struct metal_spi_vtable { struct metal_spi_vtable {
void (*init)(struct metal_spi *spi, int baud_rate); void (*init)(struct metal_spi *spi, int baud_rate);
int (*transfer)(struct metal_spi *spi, struct metal_spi_config *config, size_t len, char *tx_buf, char *rx_buf); int (*transfer)(struct metal_spi *spi, struct metal_spi_config *config,
size_t len, char *tx_buf, char *rx_buf);
int (*get_baud_rate)(struct metal_spi *spi); int (*get_baud_rate)(struct metal_spi *spi);
int (*set_baud_rate)(struct metal_spi *spi, int baud_rate); int (*set_baud_rate)(struct metal_spi *spi, int baud_rate);
}; };
@ -42,23 +51,29 @@ struct metal_spi {
/*! @brief Get a handle for a SPI device /*! @brief Get a handle for a SPI device
* @param device_num The index of the desired SPI device * @param device_num The index of the desired SPI device
* @return A handle to the SPI device, or NULL if the device does not exist*/ * @return A handle to the SPI device, or NULL if the device does not exist*/
struct metal_spi *metal_spi_get_device(int device_num); struct metal_spi *metal_spi_get_device(unsigned int device_num);
/*! @brief Initialize a SPI device with a certain baud rate /*! @brief Initialize a SPI device with a certain baud rate
* @param spi The handle for the SPI device to initialize * @param spi The handle for the SPI device to initialize
* @param baud_rate The baud rate to set the SPI device to * @param baud_rate The baud rate to set the SPI device to
*/ */
inline void metal_spi_init(struct metal_spi *spi, int baud_rate) { spi->vtable->init(spi, baud_rate); } __inline__ void metal_spi_init(struct metal_spi *spi, int baud_rate) {
spi->vtable->init(spi, baud_rate);
}
/*! @brief Perform a SPI transfer /*! @brief Perform a SPI transfer
* @param spi The handle for the SPI device to perform the transfer * @param spi The handle for the SPI device to perform the transfer
* @param config The configuration for the SPI transfer. * @param config The configuration for the SPI transfer.
* @param len The number of bytes to transfer * @param len The number of bytes to transfer
* @param tx_buf The buffer to send over the SPI bus. Must be len bytes long. If NULL, the SPI will transfer the value 0. * @param tx_buf The buffer to send over the SPI bus. Must be len bytes long. If
* @param rx_buf The buffer to receive data into. Must be len bytes long. If NULL, the SPI will ignore received bytes. * NULL, the SPI will transfer the value 0.
* @param rx_buf The buffer to receive data into. Must be len bytes long. If
* NULL, the SPI will ignore received bytes.
* @return 0 if the transfer succeeds * @return 0 if the transfer succeeds
*/ */
inline int metal_spi_transfer(struct metal_spi *spi, struct metal_spi_config *config, size_t len, char *tx_buf, char *rx_buf) { __inline__ int metal_spi_transfer(struct metal_spi *spi,
struct metal_spi_config *config, size_t len,
char *tx_buf, char *rx_buf) {
return spi->vtable->transfer(spi, config, len, tx_buf, rx_buf); return spi->vtable->transfer(spi, config, len, tx_buf, rx_buf);
} }
@ -66,13 +81,17 @@ inline int metal_spi_transfer(struct metal_spi *spi, struct metal_spi_config *co
* @param spi The handle for the SPI device * @param spi The handle for the SPI device
* @return The baud rate in Hz * @return The baud rate in Hz
*/ */
inline int metal_spi_get_baud_rate(struct metal_spi *spi) { return spi->vtable->get_baud_rate(spi); } __inline__ int metal_spi_get_baud_rate(struct metal_spi *spi) {
return spi->vtable->get_baud_rate(spi);
}
/*! @brief Set the current baud rate of the SPI device /*! @brief Set the current baud rate of the SPI device
* @param spi The handle for the SPI device * @param spi The handle for the SPI device
* @param baud_rate The desired baud rate of the SPI device * @param baud_rate The desired baud rate of the SPI device
* @return 0 if the baud rate is successfully changed * @return 0 if the baud rate is successfully changed
*/ */
inline int metal_spi_set_baud_rate(struct metal_spi *spi, int baud_rate) { return spi->vtable->set_baud_rate(spi, baud_rate); } __inline__ int metal_spi_set_baud_rate(struct metal_spi *spi, int baud_rate) {
return spi->vtable->set_baud_rate(spi, baud_rate);
}
#endif #endif

View file

@ -15,7 +15,7 @@ struct metal_switch;
struct metal_switch_vtable { struct metal_switch_vtable {
int (*switch_exist)(struct metal_switch *sw, char *label); int (*switch_exist)(struct metal_switch *sw, char *label);
struct metal_interrupt* (*interrupt_controller)(struct metal_switch *sw); struct metal_interrupt *(*interrupt_controller)(struct metal_switch *sw);
int (*get_interrupt_id)(struct metal_switch *sw); int (*get_interrupt_id)(struct metal_switch *sw);
}; };
@ -29,23 +29,28 @@ struct metal_switch {
/*! /*!
* @brief Get a handle for a switch * @brief Get a handle for a switch
* @param label The DeviceTree label for the desired switch * @param label The DeviceTree label for the desired switch
* @return A handle to the switch, or NULL if none is found for the requested label * @return A handle to the switch, or NULL if none is found for the requested
* label
*/ */
struct metal_switch* metal_switch_get(char *label); struct metal_switch *metal_switch_get(char *label);
/*! /*!
* @brief Get the interrupt controller for a switch * @brief Get the interrupt controller for a switch
* @param sw The handle for the switch * @param sw The handle for the switch
* @return The interrupt controller handle * @return The interrupt controller handle
*/ */
inline struct metal_interrupt* __inline__ struct metal_interrupt *
metal_switch_interrupt_controller(struct metal_switch *sw) { return sw->vtable->interrupt_controller(sw); } metal_switch_interrupt_controller(struct metal_switch *sw) {
return sw->vtable->interrupt_controller(sw);
}
/*! /*!
* @brief Get the interrupt id for a switch * @brief Get the interrupt id for a switch
* @param sw The handle for the switch * @param sw The handle for the switch
* @return The interrupt ID for the switch * @return The interrupt ID for the switch
*/ */
inline int metal_switch_get_interrupt_id(struct metal_switch *sw) { return sw->vtable->get_interrupt_id(sw); } __inline__ int metal_switch_get_interrupt_id(struct metal_switch *sw) {
return sw->vtable->get_interrupt_id(sw);
}
#endif #endif

View file

@ -0,0 +1,21 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__TIME_H
#define METAL__TIME_H
#include <time.h>
#ifndef __SEGGER_LIBC__
#include <sys/time.h>
#endif
/*!
* @file time.h
* @brief API for dealing with time
*/
int metal_gettimeofday(struct timeval *tp, void *tzp);
time_t metal_time(void);
#endif

View file

@ -23,7 +23,8 @@ int metal_timer_get_cyclecount(int hartid, unsigned long long *cyclecount);
* @param timebase The variable to hold the value * @param timebase The variable to hold the value
* @return 0 upon success * @return 0 upon success
*/ */
int metal_timer_get_timebase_frequency(int hartid, unsigned long long *timebase); int metal_timer_get_timebase_frequency(int hartid,
unsigned long long *timebase);
/*! /*!
* @brief Set the machine timer tick interval in seconds * @brief Set the machine timer tick interval in seconds

View file

@ -18,6 +18,18 @@
* @param c The character to write to the terminal * @param c The character to write to the terminal
* @return 0 on success, or -1 on failure. * @return 0 on success, or -1 on failure.
*/ */
int metal_tty_putc(unsigned char c); int metal_tty_putc(int c);
/*!
* @brief Get a byte from the default output device
*
* The default output device, is typically the UART serial port.
*
* This call is non-blocking, if nothing is ready c==-1
* if something is ready, then c=[0x00 to 0xff] byte value.
*
* @return 0 on success, or -1 on failure.
*/
int metal_tty_getc(int *c);
#endif #endif

View file

@ -12,15 +12,25 @@
#include <metal/interrupt.h> #include <metal/interrupt.h>
struct metal_uart; struct metal_uart;
#undef getc
#undef putc
struct metal_uart_vtable { struct metal_uart_vtable {
void (*init)(struct metal_uart *uart, int baud_rate); void (*init)(struct metal_uart *uart, int baud_rate);
int (*putc)(struct metal_uart *uart, unsigned char c); int (*putc)(struct metal_uart *uart, int c);
int (*getc)(struct metal_uart *uart, unsigned char *c); int (*txready)(struct metal_uart *uart);
int (*getc)(struct metal_uart *uart, int *c);
int (*get_baud_rate)(struct metal_uart *uart); int (*get_baud_rate)(struct metal_uart *uart);
int (*set_baud_rate)(struct metal_uart *uart, int baud_rate); int (*set_baud_rate)(struct metal_uart *uart, int baud_rate);
struct metal_interrupt* (*controller_interrupt)(struct metal_uart *uart); struct metal_interrupt *(*controller_interrupt)(struct metal_uart *uart);
int (*get_interrupt_id)(struct metal_uart *uart); int (*get_interrupt_id)(struct metal_uart *uart);
int (*tx_interrupt_enable)(struct metal_uart *uart);
int (*tx_interrupt_disable)(struct metal_uart *uart);
int (*rx_interrupt_enable)(struct metal_uart *uart);
int (*rx_interrupt_disable)(struct metal_uart *uart);
int (*set_tx_watermark)(struct metal_uart *uart, size_t length);
size_t (*get_tx_watermark)(struct metal_uart *uart);
int (*set_rx_watermark)(struct metal_uart *uart, size_t length);
size_t (*get_rx_watermark)(struct metal_uart *uart);
}; };
/*! /*!
@ -30,16 +40,25 @@ struct metal_uart {
const struct metal_uart_vtable *vtable; const struct metal_uart_vtable *vtable;
}; };
/*! @brief Get a handle for a UART device
* @param device_num The index of the desired UART device
* @return A handle to the UART device, or NULL if the device does not exist*/
struct metal_uart *metal_uart_get_device(unsigned int device_num);
/*! /*!
* @brief Initialize UART device * @brief Initialize UART device
* Initialize the UART device described by the UART handle. This function must be called before any * Initialize the UART device described by the UART handle. This function must
* other method on the UART can be invoked. It is invalid to initialize a UART more than once. be called before any
* other method on the UART can be invoked. It is invalid to initialize a UART
more than once.
* *
* @param uart The UART device handle * @param uart The UART device handle
* @param baud_rate the baud rate to set the UART to * @param baud_rate the baud rate to set the UART to
*/ */
inline void metal_uart_init(struct metal_uart *uart, int baud_rate) { return uart->vtable->init(uart, baud_rate); } __inline__ void metal_uart_init(struct metal_uart *uart, int baud_rate) {
uart->vtable->init(uart, baud_rate);
}
/*! /*!
* @brief Output a character over the UART * @brief Output a character over the UART
@ -47,22 +66,40 @@ inline void metal_uart_init(struct metal_uart *uart, int baud_rate) { return uar
* @param c The character to send over the UART * @param c The character to send over the UART
* @return 0 upon success * @return 0 upon success
*/ */
inline int metal_uart_putc(struct metal_uart *uart, unsigned char c) { return uart->vtable->putc(uart, c); } __inline__ int metal_uart_putc(struct metal_uart *uart, int c) {
return uart->vtable->putc(uart, c);
}
/*!
* @brief Test, determine if tx output is blocked(full/busy)
* @param uart The UART device handle
* @return 0 not blocked
*/
__inline__ int metal_uart_txready(struct metal_uart *uart) {
return uart->vtable->txready(uart);
}
/*! /*!
* @brief Read a character sent over the UART * @brief Read a character sent over the UART
* @param uart The UART device handle * @param uart The UART device handle
* @param c The varible to hold the read character * @param c The varible to hold the read character
* @return 0 upon success * @return 0 upon success
*
* If "c == -1" no char was ready.
* If "c != -1" then C == byte value (0x00 to 0xff)
*/ */
inline int metal_uart_getc(struct metal_uart *uart, unsigned char *c) { return uart->vtable->getc(uart, c); } __inline__ int metal_uart_getc(struct metal_uart *uart, int *c) {
return uart->vtable->getc(uart, c);
}
/*! /*!
* @brief Get the baud rate of the UART peripheral * @brief Get the baud rate of the UART peripheral
* @param uart The UART device handle * @param uart The UART device handle
* @return The current baud rate of the UART * @return The current baud rate of the UART
*/ */
inline int metal_uart_get_baud_rate(struct metal_uart *uart) { return uart->vtable->get_baud_rate(uart); } __inline__ int metal_uart_get_baud_rate(struct metal_uart *uart) {
return uart->vtable->get_baud_rate(uart);
}
/*! /*!
* @brief Set the baud rate of the UART peripheral * @brief Set the baud rate of the UART peripheral
@ -70,7 +107,10 @@ inline int metal_uart_get_baud_rate(struct metal_uart *uart) { return uart->vtab
* @param baud_rate The baud rate to configure * @param baud_rate The baud rate to configure
* @return the new baud rate of the UART * @return the new baud rate of the UART
*/ */
inline int metal_uart_set_baud_rate(struct metal_uart *uart, int baud_rate) { return uart->vtable->set_baud_rate(uart, baud_rate); } __inline__ int metal_uart_set_baud_rate(struct metal_uart *uart,
int baud_rate) {
return uart->vtable->set_baud_rate(uart, baud_rate);
}
/*! /*!
* @brief Get the interrupt controller of the UART peripheral * @brief Get the interrupt controller of the UART peripheral
@ -82,13 +122,94 @@ inline int metal_uart_set_baud_rate(struct metal_uart *uart, int baud_rate) { re
* @param uart The UART device handle * @param uart The UART device handle
* @return The handle for the UART interrupt controller * @return The handle for the UART interrupt controller
*/ */
inline struct metal_interrupt* metal_uart_interrupt_controller(struct metal_uart *uart) { return uart->vtable->controller_interrupt(uart); } __inline__ struct metal_interrupt *
metal_uart_interrupt_controller(struct metal_uart *uart) {
return uart->vtable->controller_interrupt(uart);
}
/*! /*!
* @brief Get the interrupt ID of the UART controller * @brief Get the interrupt ID of the UART controller
* @param uart The UART device handle * @param uart The UART device handle
* @return The UART interrupt id * @return The UART interrupt id
*/ */
inline int metal_uart_get_interrupt_id(struct metal_uart *uart) { return uart->vtable->get_interrupt_id(uart); } __inline__ int metal_uart_get_interrupt_id(struct metal_uart *uart) {
return uart->vtable->get_interrupt_id(uart);
}
/*!
* @brief Enable the UART transmit interrupt
* @param uart The UART device handle
* @return 0 upon success
*/
__inline__ int metal_uart_transmit_interrupt_enable(struct metal_uart *uart) {
return uart->vtable->tx_interrupt_enable(uart);
}
/*!
* @brief Disable the UART transmit interrupt
* @param uart The UART device handle
* @return 0 upon success
*/
__inline__ int metal_uart_transmit_interrupt_disable(struct metal_uart *uart) {
return uart->vtable->tx_interrupt_disable(uart);
}
/*!
* @brief Enable the UART receive interrupt
* @param uart The UART device handle
* @return 0 upon success
*/
__inline__ int metal_uart_receive_interrupt_enable(struct metal_uart *uart) {
return uart->vtable->rx_interrupt_enable(uart);
}
/*!
* @brief Disable the UART receive interrupt
* @param uart The UART device handle
* @return 0 upon success
*/
__inline__ int metal_uart_receive_interrupt_disable(struct metal_uart *uart) {
return uart->vtable->rx_interrupt_disable(uart);
}
/*!
* @brief Set the transmit watermark level of the UART controller
* @param uart The UART device handle
* @param level The UART transmit watermark level
* @return 0 upon success
*/
__inline__ int metal_uart_set_transmit_watermark(struct metal_uart *uart,
size_t level) {
return uart->vtable->set_tx_watermark(uart, level);
}
/*!
* @brief Get the transmit watermark level of the UART controller
* @param uart The UART device handle
* @return The UART transmit watermark level
*/
__inline__ size_t metal_uart_get_transmit_watermark(struct metal_uart *uart) {
return uart->vtable->get_tx_watermark(uart);
}
/*!
* @brief Set the receive watermark level of the UART controller
* @param uart The UART device handle
* @param level The UART transmit watermark level
* @return 0 upon success
*/
__inline__ int metal_uart_set_receive_watermark(struct metal_uart *uart,
size_t level) {
return uart->vtable->set_rx_watermark(uart, level);
}
/*!
* @brief Get the receive watermark level of the UART controller
* @param uart The UART device handle
* @return The UART transmit watermark level
*/
__inline__ size_t metal_uart_get_receive_watermark(struct metal_uart *uart) {
return uart->vtable->get_rx_watermark(uart);
}
#endif #endif

View file

@ -0,0 +1,168 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef METAL__WATCHDOG_H
#define METAL__WATCHDOG_H
/*!
* @file watchdog.h
*
* @brief API for configuring watchdog timers
*/
#include <metal/interrupt.h>
struct metal_watchdog;
/*!
* @brief List of watchdog timer count behaviors
*/
enum metal_watchdog_run_option {
METAL_WATCHDOG_STOP = 0, /*!< Stop the watchdog */
METAL_WATCHDOG_RUN_ALWAYS, /*!< Run the watchdog continuously, even during
sleep */
METAL_WATCHDOG_RUN_AWAKE, /*!< Run the watchdog only while the CPU is awake
*/
};
/*!
* @brief List of behaviors when a watchdog triggers
*/
enum metal_watchdog_result {
METAL_WATCHDOG_NO_RESULT = 0, /*!< When the watchdog triggers, do nothing */
METAL_WATCHDOG_INTERRUPT, /*!< When the watchdog triggers, fire an interrupt
*/
METAL_WATCHDOG_FULL_RESET, /*!< When the watchdog triggers, cause a full
system reset */
};
struct metal_watchdog_vtable {
int (*feed)(const struct metal_watchdog *const wdog);
long int (*get_rate)(const struct metal_watchdog *const wdog);
long int (*set_rate)(const struct metal_watchdog *const wdog,
const long int rate);
long int (*get_timeout)(const struct metal_watchdog *const wdog);
long int (*set_timeout)(const struct metal_watchdog *const wdog,
const long int timeout);
int (*set_result)(const struct metal_watchdog *const wdog,
const enum metal_watchdog_result result);
int (*run)(const struct metal_watchdog *const wdog,
const enum metal_watchdog_run_option option);
struct metal_interrupt *(*get_interrupt)(
const struct metal_watchdog *const wdog);
int (*get_interrupt_id)(const struct metal_watchdog *const wdog);
int (*clear_interrupt)(const struct metal_watchdog *const wdog);
};
/*!
* @brief Handle for a Watchdog Timer
*/
struct metal_watchdog {
const struct metal_watchdog_vtable *vtable;
};
/*!
* @brief Feed the watchdog timer
*/
inline int metal_watchdog_feed(const struct metal_watchdog *const wdog) {
return wdog->vtable->feed(wdog);
}
/*!
* @brief Get the rate of the watchdog timer in Hz
*
* @return the rate of the watchdog timer
*/
inline long int
metal_watchdog_get_rate(const struct metal_watchdog *const wdog) {
return wdog->vtable->get_rate(wdog);
}
/*!
* @brief Set the rate of the watchdog timer in Hz
*
* There is no guarantee that the new rate will match the requested rate.
*
* @return the new rate of the watchdog timer
*/
inline long int metal_watchdog_set_rate(const struct metal_watchdog *const wdog,
const long int rate) {
return wdog->vtable->set_rate(wdog, rate);
}
/*!
* @brief Get the timeout of the watchdog timer
*
* @return the watchdog timeout value
*/
inline long int
metal_watchdog_get_timeout(const struct metal_watchdog *const wdog) {
return wdog->vtable->get_timeout(wdog);
}
/*!
* @brief Set the timeout of the watchdog timer
*
* The set rate will be the minimimum of the requested and maximum supported
* rates.
*
* @return the new watchdog timeout value
*/
inline long int
metal_watchdog_set_timeout(const struct metal_watchdog *const wdog,
const long int timeout) {
return wdog->vtable->set_timeout(wdog, timeout);
}
/*!
* @brief Sets the result behavior of a watchdog timer timeout
*
* @return 0 if the requested result behavior is supported
*/
inline int metal_watchdog_set_result(const struct metal_watchdog *const wdog,
const enum metal_watchdog_result result) {
return wdog->vtable->set_result(wdog, result);
}
/*!
* @brief Set the run behavior of the watchdog
*
* Used to enable/disable the watchdog timer
*
* @return 0 if the watchdog was successfully started/stopped
*/
inline int metal_watchdog_run(const struct metal_watchdog *const wdog,
const enum metal_watchdog_run_option option) {
return wdog->vtable->run(wdog, option);
}
/*!
* @brief Get the interrupt controller for the watchdog interrupt
*/
inline struct metal_interrupt *
metal_watchdog_get_interrupt(const struct metal_watchdog *const wdog) {
return wdog->vtable->get_interrupt(wdog);
}
/*!
* @Brief Get the interrupt id for the watchdog interrupt
*/
inline int
metal_watchdog_get_interrupt_id(const struct metal_watchdog *const wdog) {
return wdog->vtable->get_interrupt_id(wdog);
}
/*!
* @brief Clear the watchdog interrupt
*/
inline int
metal_watchdog_clear_interrupt(const struct metal_watchdog *const wdog) {
return wdog->vtable->clear_interrupt(wdog);
}
/*!
* @brief Get a watchdog handle
*/
struct metal_watchdog *metal_watchdog_get_device(const int index);
#endif /* METAL__WATCHDOG_H */

View file

@ -5,128 +5,181 @@
#ifndef ASSEMBLY #ifndef ASSEMBLY
#ifndef SIFIVE_HIFIVE1_REVB____METAL_INLINE_H #ifndef METAL_INLINE_H
#define SIFIVE_HIFIVE1_REVB____METAL_INLINE_H #define METAL_INLINE_H
#include <metal/machine.h> #include <metal/machine.h>
/* --------------------- fixed_clock ------------ */ /* --------------------- fixed_clock ------------ */
extern inline unsigned long __metal_driver_fixed_clock_rate(const struct metal_clock *clock); extern __inline__ unsigned long __metal_driver_fixed_clock_rate(const struct metal_clock *clock);
/* --------------------- fixed_factor_clock ------------ */ /* --------------------- fixed_factor_clock ------------ */
/* --------------------- sifive_clint0 ------------ */ /* --------------------- sifive_clint0 ------------ */
extern inline unsigned long __metal_driver_sifive_clint0_control_base(struct metal_interrupt *controller); extern __inline__ unsigned long __metal_driver_sifive_clint0_control_base(struct metal_interrupt *controller);
extern inline unsigned long __metal_driver_sifive_clint0_control_size(struct metal_interrupt *controller); extern __inline__ unsigned long __metal_driver_sifive_clint0_control_size(struct metal_interrupt *controller);
extern inline int __metal_driver_sifive_clint0_num_interrupts(struct metal_interrupt *controller); extern __inline__ int __metal_driver_sifive_clint0_num_interrupts(struct metal_interrupt *controller);
extern inline struct metal_interrupt * __metal_driver_sifive_clint0_interrupt_parents(struct metal_interrupt *controller, int idx); extern __inline__ struct metal_interrupt * __metal_driver_sifive_clint0_interrupt_parents(struct metal_interrupt *controller, int idx);
extern inline int __metal_driver_sifive_clint0_interrupt_lines(struct metal_interrupt *controller, int idx); extern __inline__ int __metal_driver_sifive_clint0_interrupt_lines(struct metal_interrupt *controller, int idx);
/* --------------------- cpu ------------ */ /* --------------------- cpu ------------ */
extern inline int __metal_driver_cpu_hartid(struct metal_cpu *cpu); extern __inline__ int __metal_driver_cpu_hartid(struct metal_cpu *cpu);
extern inline int __metal_driver_cpu_timebase(struct metal_cpu *cpu); extern __inline__ int __metal_driver_cpu_timebase(struct metal_cpu *cpu);
extern inline struct metal_interrupt * __metal_driver_cpu_interrupt_controller(struct metal_cpu *cpu); extern __inline__ struct metal_interrupt * __metal_driver_cpu_interrupt_controller(struct metal_cpu *cpu);
extern inline int __metal_driver_cpu_num_pmp_regions(struct metal_cpu *cpu); extern __inline__ int __metal_driver_cpu_num_pmp_regions(struct metal_cpu *cpu);
extern __inline__ struct metal_buserror * __metal_driver_cpu_buserror(struct metal_cpu *cpu);
/* --------------------- sifive_plic0 ------------ */ /* --------------------- sifive_plic0 ------------ */
extern inline unsigned long __metal_driver_sifive_plic0_control_base(struct metal_interrupt *controller); extern __inline__ unsigned long __metal_driver_sifive_plic0_control_base(struct metal_interrupt *controller);
extern inline unsigned long __metal_driver_sifive_plic0_control_size(struct metal_interrupt *controller); extern __inline__ unsigned long __metal_driver_sifive_plic0_control_size(struct metal_interrupt *controller);
extern inline int __metal_driver_sifive_plic0_num_interrupts(struct metal_interrupt *controller); extern __inline__ int __metal_driver_sifive_plic0_num_interrupts(struct metal_interrupt *controller);
extern inline int __metal_driver_sifive_plic0_max_priority(struct metal_interrupt *controller); extern __inline__ int __metal_driver_sifive_plic0_max_priority(struct metal_interrupt *controller);
extern inline struct metal_interrupt * __metal_driver_sifive_plic0_interrupt_parents(struct metal_interrupt *controller, int idx); extern __inline__ struct metal_interrupt * __metal_driver_sifive_plic0_interrupt_parents(struct metal_interrupt *controller, int idx);
extern inline int __metal_driver_sifive_plic0_interrupt_lines(struct metal_interrupt *controller, int idx); extern __inline__ int __metal_driver_sifive_plic0_interrupt_lines(struct metal_interrupt *controller, int idx);
extern __inline__ int __metal_driver_sifive_plic0_context_ids(int hartid);
/* --------------------- sifive_buserror0 ------------ */
/* --------------------- sifive_clic0 ------------ */ /* --------------------- sifive_clic0 ------------ */
/* --------------------- sifive_local_external_interrupts0 ------------ */ /* --------------------- sifive_local_external_interrupts0 ------------ */
extern inline struct metal_interrupt * __metal_driver_sifive_local_external_interrupts0_interrupt_parent(struct metal_interrupt *controller);
extern inline int __metal_driver_sifive_local_external_interrupts0_num_interrupts(struct metal_interrupt *controller);
extern inline int __metal_driver_sifive_local_external_interrupts0_interrupt_lines(struct metal_interrupt *controller, int idx);
/* --------------------- sifive_global_external_interrupts0 ------------ */ /* --------------------- sifive_global_external_interrupts0 ------------ */
/* --------------------- sifive_gpio0 ------------ */ /* --------------------- sifive_gpio0 ------------ */
extern inline unsigned long __metal_driver_sifive_gpio0_base(struct metal_gpio *gpio); extern __inline__ unsigned long __metal_driver_sifive_gpio0_base(struct metal_gpio *gpio);
extern inline unsigned long __metal_driver_sifive_gpio0_size(struct metal_gpio *gpio); extern __inline__ unsigned long __metal_driver_sifive_gpio0_size(struct metal_gpio *gpio);
extern inline int __metal_driver_sifive_gpio0_num_interrupts(struct metal_gpio *gpio); extern __inline__ int __metal_driver_sifive_gpio0_num_interrupts(struct metal_gpio *gpio);
extern inline struct metal_interrupt * __metal_driver_sifive_gpio0_interrupt_parent(struct metal_gpio *gpio); extern __inline__ struct metal_interrupt * __metal_driver_sifive_gpio0_interrupt_parent(struct metal_gpio *gpio);
extern inline int __metal_driver_sifive_gpio0_interrupt_lines(struct metal_gpio *gpio, int idx); extern __inline__ int __metal_driver_sifive_gpio0_interrupt_lines(struct metal_gpio *gpio, int idx);
/* --------------------- sifive_gpio_button ------------ */ /* --------------------- sifive_gpio_button ------------ */
/* --------------------- sifive_gpio_led ------------ */ /* --------------------- sifive_gpio_led ------------ */
extern inline struct metal_gpio * __metal_driver_sifive_gpio_led_gpio(struct metal_led *led); extern __inline__ struct metal_gpio * __metal_driver_sifive_gpio_led_gpio(struct metal_led *led);
extern inline int __metal_driver_sifive_gpio_led_pin(struct metal_led *led); extern __inline__ int __metal_driver_sifive_gpio_led_pin(struct metal_led *led);
extern inline char * __metal_driver_sifive_gpio_led_label(struct metal_led *led); extern __inline__ char * __metal_driver_sifive_gpio_led_label(struct metal_led *led);
/* --------------------- sifive_gpio_switch ------------ */ /* --------------------- sifive_gpio_switch ------------ */
/* --------------------- sifive_i2c0 ------------ */
extern __inline__ unsigned long __metal_driver_sifive_i2c0_control_base(struct metal_i2c *i2c);
extern __inline__ unsigned long __metal_driver_sifive_i2c0_control_size(struct metal_i2c *i2c);
extern __inline__ int __metal_driver_sifive_i2c0_num_interrupts(struct metal_i2c *i2c);
extern __inline__ struct metal_interrupt * __metal_driver_sifive_i2c0_interrupt_parent(struct metal_i2c *i2c);
extern __inline__ int __metal_driver_sifive_i2c0_interrupt_line(struct metal_i2c *i2c);
extern __inline__ struct metal_clock * __metal_driver_sifive_i2c0_clock(struct metal_i2c *i2c);
extern __inline__ struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_i2c0_pinmux(struct metal_i2c *i2c);
extern __inline__ unsigned long __metal_driver_sifive_i2c0_pinmux_output_selector(struct metal_i2c *i2c);
extern __inline__ unsigned long __metal_driver_sifive_i2c0_pinmux_source_selector(struct metal_i2c *i2c);
/* --------------------- sifive_pwm0 ------------ */
extern __inline__ unsigned long __metal_driver_sifive_pwm0_control_base(struct metal_pwm *pwm);
extern __inline__ unsigned long __metal_driver_sifive_pwm0_control_size(struct metal_pwm *pwm);
extern __inline__ int __metal_driver_sifive_pwm0_num_interrupts(struct metal_pwm *pwm);
extern __inline__ struct metal_interrupt * __metal_driver_sifive_pwm0_interrupt_parent(struct metal_pwm *pwm);
extern __inline__ int __metal_driver_sifive_pwm0_interrupt_lines(struct metal_pwm *pwm, int idx);
extern __inline__ struct metal_clock * __metal_driver_sifive_pwm0_clock(struct metal_pwm *pwm);
extern __inline__ struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_pwm0_pinmux(struct metal_pwm *pwm);
extern __inline__ unsigned long __metal_driver_sifive_pwm0_pinmux_output_selector(struct metal_pwm *pwm);
extern __inline__ unsigned long __metal_driver_sifive_pwm0_pinmux_source_selector(struct metal_pwm *pwm);
extern __inline__ int __metal_driver_sifive_pwm0_compare_width(struct metal_pwm *pwm);
extern __inline__ int __metal_driver_sifive_pwm0_comparator_count(struct metal_pwm *pwm);
/* --------------------- sifive_rtc0 ------------ */
extern __inline__ unsigned long __metal_driver_sifive_rtc0_control_base(const struct metal_rtc *const rtc);
extern __inline__ unsigned long __metal_driver_sifive_rtc0_control_size(const struct metal_rtc *const rtc);
extern __inline__ struct metal_interrupt * __metal_driver_sifive_rtc0_interrupt_parent(const struct metal_rtc *const rtc);
extern __inline__ int __metal_driver_sifive_rtc0_interrupt_line(const struct metal_rtc *const rtc);
extern __inline__ struct metal_clock * __metal_driver_sifive_rtc0_clock(const struct metal_rtc *const rtc);
/* --------------------- sifive_spi0 ------------ */ /* --------------------- sifive_spi0 ------------ */
extern inline unsigned long __metal_driver_sifive_spi0_control_base(struct metal_spi *spi); extern __inline__ unsigned long __metal_driver_sifive_spi0_control_base(struct metal_spi *spi);
extern inline unsigned long __metal_driver_sifive_spi0_control_size(struct metal_spi *spi); extern __inline__ unsigned long __metal_driver_sifive_spi0_control_size(struct metal_spi *spi);
extern inline struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_spi0_pinmux(struct metal_spi *spi); extern __inline__ struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_spi0_pinmux(struct metal_spi *spi);
extern inline unsigned long __metal_driver_sifive_spi0_pinmux_output_selector(struct metal_spi *spi); extern __inline__ unsigned long __metal_driver_sifive_spi0_pinmux_output_selector(struct metal_spi *spi);
extern inline unsigned long __metal_driver_sifive_spi0_pinmux_source_selector(struct metal_spi *spi); extern __inline__ unsigned long __metal_driver_sifive_spi0_pinmux_source_selector(struct metal_spi *spi);
/* --------------------- sifive_test0 ------------ */ /* --------------------- sifive_test0 ------------ */
/* --------------------- sifive_trace ------------ */
/* --------------------- sifive_uart0 ------------ */ /* --------------------- sifive_uart0 ------------ */
extern inline unsigned long __metal_driver_sifive_uart0_control_base(struct metal_uart *uart); extern __inline__ unsigned long __metal_driver_sifive_uart0_control_base(struct metal_uart *uart);
extern inline unsigned long __metal_driver_sifive_uart0_control_size(struct metal_uart *uart); extern __inline__ unsigned long __metal_driver_sifive_uart0_control_size(struct metal_uart *uart);
extern inline int __metal_driver_sifive_uart0_num_interrupts(struct metal_uart *uart); extern __inline__ int __metal_driver_sifive_uart0_num_interrupts(struct metal_uart *uart);
extern inline struct metal_interrupt * __metal_driver_sifive_uart0_interrupt_parent(struct metal_uart *uart); extern __inline__ struct metal_interrupt * __metal_driver_sifive_uart0_interrupt_parent(struct metal_uart *uart);
extern inline int __metal_driver_sifive_uart0_interrupt_line(struct metal_uart *uart); extern __inline__ int __metal_driver_sifive_uart0_interrupt_line(struct metal_uart *uart);
extern inline struct metal_clock * __metal_driver_sifive_uart0_clock(struct metal_uart *uart); extern __inline__ struct metal_clock * __metal_driver_sifive_uart0_clock(struct metal_uart *uart);
extern inline struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_uart0_pinmux(struct metal_uart *uart); extern __inline__ struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_uart0_pinmux(struct metal_uart *uart);
extern inline unsigned long __metal_driver_sifive_uart0_pinmux_output_selector(struct metal_uart *uart); extern __inline__ unsigned long __metal_driver_sifive_uart0_pinmux_output_selector(struct metal_uart *uart);
extern inline unsigned long __metal_driver_sifive_uart0_pinmux_source_selector(struct metal_uart *uart); extern __inline__ unsigned long __metal_driver_sifive_uart0_pinmux_source_selector(struct metal_uart *uart);
/* --------------------- sifive_simuart0 ------------ */
/* --------------------- sifive_wdog0 ------------ */
extern __inline__ unsigned long __metal_driver_sifive_wdog0_control_base(const struct metal_watchdog *const watchdog);
extern __inline__ unsigned long __metal_driver_sifive_wdog0_control_size(const struct metal_watchdog *const watchdog);
extern __inline__ struct metal_interrupt * __metal_driver_sifive_wdog0_interrupt_parent(const struct metal_watchdog *const watchdog);
extern __inline__ int __metal_driver_sifive_wdog0_interrupt_line(const struct metal_watchdog *const watchdog);
extern __inline__ struct metal_clock * __metal_driver_sifive_wdog0_clock(const struct metal_watchdog *const watchdog);
/* --------------------- sifive_fe310_g000_hfrosc ------------ */ /* --------------------- sifive_fe310_g000_hfrosc ------------ */
extern inline struct metal_clock * __metal_driver_sifive_fe310_g000_hfrosc_ref(const struct metal_clock *clock); extern __inline__ struct metal_clock * __metal_driver_sifive_fe310_g000_hfrosc_ref(const struct metal_clock *clock);
extern inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_base(const struct metal_clock *clock); extern __inline__ struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_base(const struct metal_clock *clock);
extern inline const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_vtable(struct metal_clock *clock); extern __inline__ const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_vtable(struct metal_clock *clock);
extern inline long __metal_driver_sifive_fe310_g000_hfrosc_config_offset(const struct metal_clock *clock); extern __inline__ long __metal_driver_sifive_fe310_g000_hfrosc_config_offset(const struct metal_clock *clock);
/* --------------------- sifive_fe310_g000_hfxosc ------------ */ /* --------------------- sifive_fe310_g000_hfxosc ------------ */
extern inline struct metal_clock * __metal_driver_sifive_fe310_g000_hfxosc_ref(const struct metal_clock *clock); extern __inline__ struct metal_clock * __metal_driver_sifive_fe310_g000_hfxosc_ref(const struct metal_clock *clock);
extern inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfxosc_config_base(const struct metal_clock *clock); extern __inline__ struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfxosc_config_base(const struct metal_clock *clock);
extern inline long __metal_driver_sifive_fe310_g000_hfxosc_config_offset(const struct metal_clock *clock); extern __inline__ long __metal_driver_sifive_fe310_g000_hfxosc_config_offset(const struct metal_clock *clock);
/* --------------------- sifive_fe310_g000_lfrosc ------------ */
extern __inline__ struct metal_clock * __metal_driver_sifive_fe310_g000_lfrosc_lfrosc(const struct metal_clock *clock);
extern __inline__ struct metal_clock * __metal_driver_sifive_fe310_g000_lfrosc_psdlfaltclk(const struct metal_clock *clock);
extern __inline__ unsigned long int __metal_driver_sifive_fe310_g000_lfrosc_config_reg(const struct metal_clock *clock);
extern __inline__ unsigned long int __metal_driver_sifive_fe310_g000_lfrosc_mux_reg(const struct metal_clock *clock);
/* --------------------- sifive_fe310_g000_pll ------------ */ /* --------------------- sifive_fe310_g000_pll ------------ */
extern inline struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllsel0(const struct metal_clock *clock); extern __inline__ struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllsel0(const struct metal_clock *clock);
extern inline struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllref(const struct metal_clock *clock); extern __inline__ struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllref(const struct metal_clock *clock);
extern inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_config_base( ); extern __inline__ struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_config_base( );
extern inline long __metal_driver_sifive_fe310_g000_pll_config_offset( ); extern __inline__ long __metal_driver_sifive_fe310_g000_pll_config_offset( );
extern inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_divider_base(const struct metal_clock *clock); extern __inline__ struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_divider_base(const struct metal_clock *clock);
extern inline long __metal_driver_sifive_fe310_g000_pll_divider_offset(const struct metal_clock *clock); extern __inline__ long __metal_driver_sifive_fe310_g000_pll_divider_offset(const struct metal_clock *clock);
extern inline long __metal_driver_sifive_fe310_g000_pll_init_rate( ); extern __inline__ long __metal_driver_sifive_fe310_g000_pll_init_rate( );
/* --------------------- fe310_g000_prci ------------ */ /* --------------------- fe310_g000_prci ------------ */
extern inline long __metal_driver_sifive_fe310_g000_prci_base( ); extern __inline__ long __metal_driver_sifive_fe310_g000_prci_base( );
extern inline long __metal_driver_sifive_fe310_g000_prci_size( ); extern __inline__ long __metal_driver_sifive_fe310_g000_prci_size( );
extern inline const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_prci_vtable( ); extern __inline__ const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_prci_vtable( );
/* --------------------- sifive_fu540_c000_l2 ------------ */
/* From clock@0 */ /* From clock@0 */
@ -144,6 +197,11 @@ struct __metal_driver_fixed_clock __metal_dt_clock_5 = {
.clock.vtable = &__metal_driver_vtable_fixed_clock.clock, .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
}; };
/* From clock@6 */
struct __metal_driver_fixed_clock __metal_dt_clock_6 = {
.clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
};
struct metal_memory __metal_dt_mem_dtim_80000000 = { struct metal_memory __metal_dt_mem_dtim_80000000 = {
._base_address = 2147483648UL, ._base_address = 2147483648UL,
._size = 16384UL, ._size = 16384UL,
@ -155,6 +213,17 @@ struct metal_memory __metal_dt_mem_dtim_80000000 = {
.A = 1}, .A = 1},
}; };
struct metal_memory __metal_dt_mem_itim_8000000 = {
._base_address = 134217728UL,
._size = 8192UL,
._attrs = {
.R = 1,
.W = 1,
.X = 1,
.C = 1,
.A = 1},
};
struct metal_memory __metal_dt_mem_spi_10014000 = { struct metal_memory __metal_dt_mem_spi_10014000 = {
._base_address = 536870912UL, ._base_address = 536870912UL,
._size = 500000UL, ._size = 500000UL,
@ -166,6 +235,24 @@ struct metal_memory __metal_dt_mem_spi_10014000 = {
.A = 1}, .A = 1},
}; };
struct metal_memory __metal_dt_mem_spi_10024000 = {
._attrs = {
.R = 1,
.W = 1,
.X = 1,
.C = 1,
.A = 1},
};
struct metal_memory __metal_dt_mem_spi_10034000 = {
._attrs = {
.R = 1,
.W = 1,
.X = 1,
.C = 1,
.A = 1},
};
/* From clint@2000000 */ /* From clint@2000000 */
struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000 = { struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000 = {
.controller.vtable = &__metal_driver_vtable_riscv_clint0.clint_vtable, .controller.vtable = &__metal_driver_vtable_riscv_clint0.clint_vtable,
@ -175,6 +262,7 @@ struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000 = {
/* From cpu@0 */ /* From cpu@0 */
struct __metal_driver_cpu __metal_dt_cpu_0 = { struct __metal_driver_cpu __metal_dt_cpu_0 = {
.cpu.vtable = &__metal_driver_vtable_cpu.cpu_vtable, .cpu.vtable = &__metal_driver_vtable_cpu.cpu_vtable,
.hpm_count = 0,
}; };
/* From interrupt_controller */ /* From interrupt_controller */
@ -189,42 +277,83 @@ struct __metal_driver_riscv_plic0 __metal_dt_interrupt_controller_c000000 = {
.init_done = 0, .init_done = 0,
}; };
/* From local_external_interrupts_0 */ struct metal_pmp __metal_dt_pmp;
struct __metal_driver_sifive_local_external_interrupts0 __metal_dt_local_external_interrupts_0 = {
.irc.vtable = &__metal_driver_vtable_sifive_local_external_interrupts0.local0_vtable,
.init_done = 0,
};
/* From gpio@10012000 */ /* From gpio@10012000 */
struct __metal_driver_sifive_gpio0 __metal_dt_gpio_10012000 = { struct __metal_driver_sifive_gpio0 __metal_dt_gpio_10012000 = {
.gpio.vtable = &__metal_driver_vtable_sifive_gpio0.gpio, .gpio.vtable = &__metal_driver_vtable_sifive_gpio0.gpio,
}; };
/* From led@0red */ /* From led@0 */
struct __metal_driver_sifive_gpio_led __metal_dt_led_0red = { struct __metal_driver_sifive_gpio_led __metal_dt_led_0 = {
.led.vtable = &__metal_driver_vtable_sifive_led.led_vtable, .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
}; };
/* From led@0green */ /* From led@1 */
struct __metal_driver_sifive_gpio_led __metal_dt_led_0green = { struct __metal_driver_sifive_gpio_led __metal_dt_led_1 = {
.led.vtable = &__metal_driver_vtable_sifive_led.led_vtable, .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
}; };
/* From led@0blue */ /* From led@2 */
struct __metal_driver_sifive_gpio_led __metal_dt_led_0blue = { struct __metal_driver_sifive_gpio_led __metal_dt_led_2 = {
.led.vtable = &__metal_driver_vtable_sifive_led.led_vtable, .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
}; };
/* From i2c@10016000 */
struct __metal_driver_sifive_i2c0 __metal_dt_i2c_10016000 = {
.i2c.vtable = &__metal_driver_vtable_sifive_i2c0.i2c,
};
/* From pwm@10015000 */
struct __metal_driver_sifive_pwm0 __metal_dt_pwm_10015000 = {
.pwm.vtable = &__metal_driver_vtable_sifive_pwm0.pwm,
};
/* From pwm@10025000 */
struct __metal_driver_sifive_pwm0 __metal_dt_pwm_10025000 = {
.pwm.vtable = &__metal_driver_vtable_sifive_pwm0.pwm,
};
/* From pwm@10035000 */
struct __metal_driver_sifive_pwm0 __metal_dt_pwm_10035000 = {
.pwm.vtable = &__metal_driver_vtable_sifive_pwm0.pwm,
};
/* From aon@10000000 */
struct __metal_driver_sifive_rtc0 __metal_dt_rtc_10000000 = {
.rtc.vtable = &__metal_driver_vtable_sifive_rtc0.rtc,
};
/* From spi@10014000 */ /* From spi@10014000 */
struct __metal_driver_sifive_spi0 __metal_dt_spi_10014000 = { struct __metal_driver_sifive_spi0 __metal_dt_spi_10014000 = {
.spi.vtable = &__metal_driver_vtable_sifive_spi0.spi, .spi.vtable = &__metal_driver_vtable_sifive_spi0.spi,
}; };
/* From spi@10024000 */
struct __metal_driver_sifive_spi0 __metal_dt_spi_10024000 = {
.spi.vtable = &__metal_driver_vtable_sifive_spi0.spi,
};
/* From spi@10034000 */
struct __metal_driver_sifive_spi0 __metal_dt_spi_10034000 = {
.spi.vtable = &__metal_driver_vtable_sifive_spi0.spi,
};
/* From serial@10013000 */ /* From serial@10013000 */
struct __metal_driver_sifive_uart0 __metal_dt_serial_10013000 = { struct __metal_driver_sifive_uart0 __metal_dt_serial_10013000 = {
.uart.vtable = &__metal_driver_vtable_sifive_uart0.uart, .uart.vtable = &__metal_driver_vtable_sifive_uart0.uart,
}; };
/* From serial@10023000 */
struct __metal_driver_sifive_uart0 __metal_dt_serial_10023000 = {
.uart.vtable = &__metal_driver_vtable_sifive_uart0.uart,
};
/* From aon@10000000 */
struct __metal_driver_sifive_wdog0 __metal_dt_aon_10000000 = {
.watchdog.vtable = &__metal_driver_vtable_sifive_wdog0.watchdog,
};
/* From clock@3 */ /* From clock@3 */
struct __metal_driver_sifive_fe310_g000_hfrosc __metal_dt_clock_3 = { struct __metal_driver_sifive_fe310_g000_hfrosc __metal_dt_clock_3 = {
.clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfrosc.clock, .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfrosc.clock,
@ -235,6 +364,11 @@ struct __metal_driver_sifive_fe310_g000_hfxosc __metal_dt_clock_1 = {
.clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfxosc.clock, .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfxosc.clock,
}; };
/* From clock@7 */
struct __metal_driver_sifive_fe310_g000_lfrosc __metal_dt_clock_7 = {
.clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_lfrosc.clock,
};
/* From clock@4 */ /* From clock@4 */
struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4 = { struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4 = {
.clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_pll.clock, .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_pll.clock,
@ -242,8 +376,9 @@ struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4 = {
/* From prci@10008000 */ /* From prci@10008000 */
struct __metal_driver_sifive_fe310_g000_prci __metal_dt_prci_10008000 = { struct __metal_driver_sifive_fe310_g000_prci __metal_dt_prci_10008000 = {
.vtable = &__metal_driver_vtable_sifive_fe310_g000_prci,
}; };
#endif /* SIFIVE_HIFIVE1_REVB____METAL_INLINE_H*/ #endif /* METAL_INLINE_H*/
#endif /* ! ASSEMBLY */ #endif /* ! ASSEMBLY */

View file

@ -3,8 +3,8 @@
/* ----------------------------------- */ /* ----------------------------------- */
/* ----------------------------------- */ /* ----------------------------------- */
#ifndef SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H #ifndef METAL_PLATFORM_H
#define SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H #define METAL_PLATFORM_H
/* From clock@0 */ /* From clock@0 */
#define METAL_FIXED_CLOCK_0_CLOCK_FREQUENCY 16000000UL #define METAL_FIXED_CLOCK_0_CLOCK_FREQUENCY 16000000UL
@ -13,7 +13,10 @@
#define METAL_FIXED_CLOCK_2_CLOCK_FREQUENCY 72000000UL #define METAL_FIXED_CLOCK_2_CLOCK_FREQUENCY 72000000UL
/* From clock@5 */ /* From clock@5 */
#define METAL_FIXED_CLOCK_5_CLOCK_FREQUENCY 32000000UL #define METAL_FIXED_CLOCK_5_CLOCK_FREQUENCY 32768UL
/* From clock@6 */
#define METAL_FIXED_CLOCK_6_CLOCK_FREQUENCY 32768UL
#define METAL_FIXED_CLOCK #define METAL_FIXED_CLOCK
@ -35,15 +38,18 @@
#define METAL_RISCV_PLIC0_0_SIZE 67108864UL #define METAL_RISCV_PLIC0_0_SIZE 67108864UL
#define METAL_RISCV_PLIC0_C000000_RISCV_MAX_PRIORITY 7UL #define METAL_RISCV_PLIC0_C000000_RISCV_MAX_PRIORITY 7UL
#define METAL_RISCV_PLIC0_0_RISCV_MAX_PRIORITY 7UL #define METAL_RISCV_PLIC0_0_RISCV_MAX_PRIORITY 7UL
#define METAL_RISCV_PLIC0_C000000_RISCV_NDEV 27UL #define METAL_RISCV_PLIC0_C000000_RISCV_NDEV 53UL
#define METAL_RISCV_PLIC0_0_RISCV_NDEV 27UL #define METAL_RISCV_PLIC0_0_RISCV_NDEV 53UL
#define METAL_RISCV_PLIC0 #define METAL_RISCV_PLIC0
#define METAL_RISCV_PLIC0_PRIORITY_BASE 0UL #define METAL_RISCV_PLIC0_PRIORITY_BASE 0UL
#define METAL_RISCV_PLIC0_PENDING_BASE 4096UL #define METAL_RISCV_PLIC0_PENDING_BASE 4096UL
#define METAL_RISCV_PLIC0_ENABLE_BASE 8192UL #define METAL_RISCV_PLIC0_ENABLE_BASE 8192UL
#define METAL_RISCV_PLIC0_THRESHOLD 2097152UL #define METAL_RISCV_PLIC0_ENABLE_PER_HART 128UL
#define METAL_RISCV_PLIC0_CLAIM 2097156UL #define METAL_RISCV_PLIC0_CONTEXT_BASE 2097152UL
#define METAL_RISCV_PLIC0_CONTEXT_PER_HART 4096UL
#define METAL_RISCV_PLIC0_CONTEXT_THRESHOLD 0UL
#define METAL_RISCV_PLIC0_CONTEXT_CLAIM 4UL
/* From aon@10000000 */ /* From aon@10000000 */
#define METAL_SIFIVE_AON0_10000000_BASE_ADDRESS 268435456UL #define METAL_SIFIVE_AON0_10000000_BASE_ADDRESS 268435456UL
@ -111,6 +117,10 @@
#define METAL_SIFIVE_FE310_G000_HFXOSC #define METAL_SIFIVE_FE310_G000_HFXOSC
/* From clock@7 */
#define METAL_SIFIVE_FE310_G000_LFROSC
/* From prci@10008000 */ /* From prci@10008000 */
#define METAL_SIFIVE_FE310_G000_PRCI_10008000_BASE_ADDRESS 268468224UL #define METAL_SIFIVE_FE310_G000_PRCI_10008000_BASE_ADDRESS 268468224UL
#define METAL_SIFIVE_FE310_G000_PRCI_0_BASE_ADDRESS 268468224UL #define METAL_SIFIVE_FE310_G000_PRCI_0_BASE_ADDRESS 268468224UL
@ -153,11 +163,11 @@
#define METAL_SIFIVE_GPIO0_IOF_SEL 60UL #define METAL_SIFIVE_GPIO0_IOF_SEL 60UL
#define METAL_SIFIVE_GPIO0_OUT_XOR 64UL #define METAL_SIFIVE_GPIO0_OUT_XOR 64UL
/* From led@0red */ /* From led@0 */
/* From led@0green */ /* From led@1 */
/* From led@0blue */ /* From led@2 */
#define METAL_SIFIVE_GPIO_LEDS #define METAL_SIFIVE_GPIO_LEDS
@ -176,16 +186,24 @@
#define METAL_SIFIVE_I2C0_COMMAND 16UL #define METAL_SIFIVE_I2C0_COMMAND 16UL
#define METAL_SIFIVE_I2C0_STATUS 16UL #define METAL_SIFIVE_I2C0_STATUS 16UL
/* From local_external_interrupts_0 */
#define METAL_SIFIVE_LOCAL_EXTERNAL_INTERRUPTS0
/* From pwm@10015000 */ /* From pwm@10015000 */
#define METAL_SIFIVE_PWM0_10015000_BASE_ADDRESS 268521472UL #define METAL_SIFIVE_PWM0_10015000_BASE_ADDRESS 268521472UL
#define METAL_SIFIVE_PWM0_0_BASE_ADDRESS 268521472UL #define METAL_SIFIVE_PWM0_0_BASE_ADDRESS 268521472UL
#define METAL_SIFIVE_PWM0_10015000_SIZE 4096UL #define METAL_SIFIVE_PWM0_10015000_SIZE 4096UL
#define METAL_SIFIVE_PWM0_0_SIZE 4096UL #define METAL_SIFIVE_PWM0_0_SIZE 4096UL
/* From pwm@10025000 */
#define METAL_SIFIVE_PWM0_10025000_BASE_ADDRESS 268587008UL
#define METAL_SIFIVE_PWM0_1_BASE_ADDRESS 268587008UL
#define METAL_SIFIVE_PWM0_10025000_SIZE 4096UL
#define METAL_SIFIVE_PWM0_1_SIZE 4096UL
/* From pwm@10035000 */
#define METAL_SIFIVE_PWM0_10035000_BASE_ADDRESS 268652544UL
#define METAL_SIFIVE_PWM0_2_BASE_ADDRESS 268652544UL
#define METAL_SIFIVE_PWM0_10035000_SIZE 4096UL
#define METAL_SIFIVE_PWM0_2_SIZE 4096UL
#define METAL_SIFIVE_PWM0 #define METAL_SIFIVE_PWM0
#define METAL_SIFIVE_PWM0_PWMCFG 0UL #define METAL_SIFIVE_PWM0_PWMCFG 0UL
#define METAL_SIFIVE_PWM0_PWMCOUNT 8UL #define METAL_SIFIVE_PWM0_PWMCOUNT 8UL
@ -195,12 +213,37 @@
#define METAL_SIFIVE_PWM0_PWMCMP2 40UL #define METAL_SIFIVE_PWM0_PWMCMP2 40UL
#define METAL_SIFIVE_PWM0_PWMCMP3 44UL #define METAL_SIFIVE_PWM0_PWMCMP3 44UL
/* From aon@10000000 */
#define METAL_SIFIVE_AON0_10000000_BASE_ADDRESS 268435456UL
#define METAL_SIFIVE_AON0_0_BASE_ADDRESS 268435456UL
#define METAL_SIFIVE_AON0_10000000_SIZE 32768UL
#define METAL_SIFIVE_AON0_0_SIZE 32768UL
#define METAL_SIFIVE_RTC0
#define METAL_SIFIVE_RTC0_RTCCFG 64UL
#define METAL_SIFIVE_RTC0_RTCCOUNTLO 72UL
#define METAL_SIFIVE_RTC0_RTCCOUNTHI 76UL
#define METAL_SIFIVE_RTC0_RTCS 80UL
#define METAL_SIFIVE_RTC0_RTCCMP0 96UL
/* From spi@10014000 */ /* From spi@10014000 */
#define METAL_SIFIVE_SPI0_10014000_BASE_ADDRESS 268517376UL #define METAL_SIFIVE_SPI0_10014000_BASE_ADDRESS 268517376UL
#define METAL_SIFIVE_SPI0_0_BASE_ADDRESS 268517376UL #define METAL_SIFIVE_SPI0_0_BASE_ADDRESS 268517376UL
#define METAL_SIFIVE_SPI0_10014000_SIZE 4096UL #define METAL_SIFIVE_SPI0_10014000_SIZE 4096UL
#define METAL_SIFIVE_SPI0_0_SIZE 4096UL #define METAL_SIFIVE_SPI0_0_SIZE 4096UL
/* From spi@10024000 */
#define METAL_SIFIVE_SPI0_10024000_BASE_ADDRESS 268582912UL
#define METAL_SIFIVE_SPI0_1_BASE_ADDRESS 268582912UL
#define METAL_SIFIVE_SPI0_10024000_SIZE 4096UL
#define METAL_SIFIVE_SPI0_1_SIZE 4096UL
/* From spi@10034000 */
#define METAL_SIFIVE_SPI0_10034000_BASE_ADDRESS 268648448UL
#define METAL_SIFIVE_SPI0_2_BASE_ADDRESS 268648448UL
#define METAL_SIFIVE_SPI0_10034000_SIZE 4096UL
#define METAL_SIFIVE_SPI0_2_SIZE 4096UL
#define METAL_SIFIVE_SPI0 #define METAL_SIFIVE_SPI0
#define METAL_SIFIVE_SPI0_SCKDIV 0UL #define METAL_SIFIVE_SPI0_SCKDIV 0UL
#define METAL_SIFIVE_SPI0_SCKMODE 4UL #define METAL_SIFIVE_SPI0_SCKMODE 4UL
@ -225,6 +268,12 @@
#define METAL_SIFIVE_UART0_10013000_SIZE 4096UL #define METAL_SIFIVE_UART0_10013000_SIZE 4096UL
#define METAL_SIFIVE_UART0_0_SIZE 4096UL #define METAL_SIFIVE_UART0_0_SIZE 4096UL
/* From serial@10023000 */
#define METAL_SIFIVE_UART0_10023000_BASE_ADDRESS 268578816UL
#define METAL_SIFIVE_UART0_1_BASE_ADDRESS 268578816UL
#define METAL_SIFIVE_UART0_10023000_SIZE 4096UL
#define METAL_SIFIVE_UART0_1_SIZE 4096UL
#define METAL_SIFIVE_UART0 #define METAL_SIFIVE_UART0
#define METAL_SIFIVE_UART0_TXDATA 0UL #define METAL_SIFIVE_UART0_TXDATA 0UL
#define METAL_SIFIVE_UART0_RXDATA 4UL #define METAL_SIFIVE_UART0_RXDATA 4UL
@ -234,4 +283,20 @@
#define METAL_SIFIVE_UART0_IP 20UL #define METAL_SIFIVE_UART0_IP 20UL
#define METAL_SIFIVE_UART0_DIV 24UL #define METAL_SIFIVE_UART0_DIV 24UL
#endif /* SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H*/ /* From aon@10000000 */
#define METAL_SIFIVE_AON0_10000000_BASE_ADDRESS 268435456UL
#define METAL_SIFIVE_AON0_0_BASE_ADDRESS 268435456UL
#define METAL_SIFIVE_AON0_10000000_SIZE 32768UL
#define METAL_SIFIVE_AON0_0_SIZE 32768UL
#define METAL_SIFIVE_WDOG0
#define METAL_SIFIVE_WDOG0_MAGIC_KEY 5370206UL
#define METAL_SIFIVE_WDOG0_MAGIC_FOOD 218755085UL
#define METAL_SIFIVE_WDOG0_WDOGCFG 0UL
#define METAL_SIFIVE_WDOG0_WDOGCOUNT 8UL
#define METAL_SIFIVE_WDOG0_WDOGS 16UL
#define METAL_SIFIVE_WDOG0_WDOGFEED 24UL
#define METAL_SIFIVE_WDOG0_WDOGKEY 28UL
#define METAL_SIFIVE_WDOG0_WDOGCMP 32UL
#endif /* METAL_PLATFORM_H*/

View file

@ -1,236 +1,302 @@
/* Copyright 2019 SiFive, Inc */ /* Copyright (c) 2020 SiFive Inc. */
/* SPDX-License-Identifier: Apache-2.0 */ /* SPDX-License-Identifier: Apache-2.0 */
/* ----------------------------------- */
/* ----------------------------------- */
OUTPUT_ARCH("riscv") OUTPUT_ARCH("riscv")
/* Default Linker Script
*
* This is the default linker script for all Freedom Metal applications.
*/
ENTRY(_enter) ENTRY(_enter)
MEMORY MEMORY
{ {
ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 0x4000 itim (airwx) : ORIGIN = 0x8000000, LENGTH = 0x2000
flash (rxai!w) : ORIGIN = 0x20010000, LENGTH = 0x6a120 ram (arw!xi) : ORIGIN = 0x80000000, LENGTH = 0x4000
rom (irx!wa) : ORIGIN = 0x20010000, LENGTH = 0x6a120
} }
PHDRS PHDRS
{ {
flash PT_LOAD; rom PT_LOAD;
ram_init PT_LOAD; ram_init PT_LOAD;
itim_init PT_LOAD; tls PT_TLS;
ram PT_NULL; ram PT_LOAD;
itim PT_NULL; itim_init PT_LOAD;
text PT_LOAD;
lim_init PT_LOAD;
} }
SECTIONS SECTIONS
{ {
__stack_size = DEFINED(__stack_size) ? __stack_size : 0x400; /* Each hart is allocated its own stack of size __stack_size. This value
PROVIDE(__stack_size = __stack_size); * can be overriden at build-time by adding the following to CFLAGS:
__heap_size = DEFINED(__heap_size) ? __heap_size : 0x4; *
PROVIDE(__metal_boot_hart = 0); * -Xlinker --defsym=__stack_size=0xf00
PROVIDE(__metal_chicken_bit = 0); *
* where 0xf00 can be replaced with a multiple of 16 of your choice.
*
* __stack_size is PROVIDE-ed as a symbol so that initialization code
* initializes the stack pointers for each hart at the right offset from
* the _sp symbol.
*/
__stack_size = DEFINED(__stack_size) ? __stack_size : 0x400;
PROVIDE(__stack_size = __stack_size);
/* The size of the heap can be overriden at build-time by adding the
* following to CFLAGS:
*
* -Xlinker --defsym=__heap_size=0xf00
*
* where 0xf00 can be replaced with the value of your choice.
*
* Altertatively, the heap can be grown to fill the entire remaining region
* of RAM by adding the following to CFLAGS:
*
* -Xlinker --defsym=__heap_max=1
*
* Note that depending on the memory layout, the bitness (32/64bit) of the
* target, and the code model in use, this might cause a relocation error.
*/
__heap_size = DEFINED(__heap_size) ? __heap_size : 0x800;
/* The boot hart sets which hart runs the pre-main initialization routines,
* including copying .data into RAM, zeroing the BSS region, running
* constructors, etc. After initialization, the boot hart is also the only
* hart which runs application code unless the application overrides the
* secondary_main() function to start execution on secondary harts.
*/
PROVIDE(__metal_boot_hart = 0);
/* The chicken bit is used by pre-main initialization to enable/disable
* certain core features */
PROVIDE(__metal_chicken_bit = 1);
/* The memory_ecc_scrub bit is used by _entry code to enable/disable
* memories scrubbing to zero */
PROVIDE(__metal_eccscrub_bit = 0);
/* The RAM memories map for ECC scrubbing */
PROVIDE( metal_dtim_0_memory_start = 0x80000000 );
PROVIDE( metal_dtim_0_memory_end = 0x80000000 + 0x4000 );
PROVIDE( metal_itim_0_memory_start = 0x8000000 );
PROVIDE( metal_itim_0_memory_end = 0x8000000 + 0x2000 );
/* ROM SECTION
*
* The following sections contain data which lives in read-only memory, if
* such memory is present in the design, for the entire duration of program
* execution.
*/
.init : {
/* The _enter symbol is placed in the .text.metal.init.enter section
* and must be placed at the beginning of the program */
KEEP (*(.text.metal.init.enter))
KEEP (*(.text.metal.init.*))
KEEP (*(SORT_NONE(.init)))
KEEP (*(.text.libgloss.start))
} >rom :rom
.fini : {
KEEP (*(SORT_NONE(.fini)))
} >rom :rom
.preinit_array : ALIGN(8) {
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >rom :rom
.init_array : ALIGN(8) {
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
PROVIDE_HIDDEN ( metal_constructors_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.metal.init_array.*)));
KEEP (*(.metal.init_array));
PROVIDE_HIDDEN ( metal_constructors_end = .);
} >rom :rom
.fini_array : ALIGN(8) {
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
PROVIDE_HIDDEN ( metal_destructors_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.metal.fini_array.*)));
KEEP (*(.metal.fini_array));
PROVIDE_HIDDEN ( metal_destructors_end = .);
} >rom :rom
.init :
{ .ctors : {
KEEP (*(.text.metal.init.enter)) KEEP (*crtbegin.o(.ctors))
KEEP (*(SORT_NONE(.init))) KEEP (*crtbegin?.o(.ctors))
KEEP (*(.text.libgloss.start)) KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
} >flash AT>flash :flash KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
KEEP (*(.metal.ctors .metal.ctors.*))
} >rom :rom
.dtors : {
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
KEEP (*(.metal.dtors .metal.dtors.*))
} >rom : rom
.rodata : {
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >rom :rom
/* ITIM SECTION
*
* The following sections contain data which is copied from read-only
* memory into an instruction tightly-integrated memory (ITIM), if one
* is present in the design, during pre-main program initialization.
*
* Generally, the data copied into the ITIM should be performance-critical
* functions which benefit from low instruction-fetch latency.
*/
.itim : ALIGN(8) {
*(.itim .itim.*)
} >itim AT>rom :itim_init
PROVIDE( metal_segment_itim_source_start = LOADADDR(.itim) );
PROVIDE( metal_segment_itim_target_start = ADDR(.itim) );
PROVIDE( metal_segment_itim_target_end = ADDR(.itim) + SIZEOF(.itim) );
/* LIM SECTION
*
* The following sections contain data which is copied from read-only
* memory into a loosely integrated memory (LIM), which is shared with L2
* cache, during pre-main program initialization.
*
* Generally, the data copied into the LIM should be performance-critical
* functions which benefit from low instruction-fetch latency.
*/
.lim : ALIGN(8) {
*(.lim .lim.*)
} >ram AT>rom :lim_init
PROVIDE( metal_segment_lim_source_start = LOADADDR(.lim) );
PROVIDE( metal_segment_lim_target_start = ADDR(.lim) );
PROVIDE( metal_segment_lim_target_end = ADDR(.lim) + SIZEOF(.lim) );
/* TEXT SECTION
*
* The following section contains the code of the program, excluding
* everything that's been allocated into the ITIM/LIM already
*/
.text : {
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
} >rom :text
/* RAM SECTION
*
* The following sections contain data which is copied from read-only
* memory into a read-write-capable memory such as data tightly-integrated
* memory (DTIM) or another main memory, as well as the BSS, stack, and
* heap.
*
* You might notice that .data, .tdata, .tbss, .tbss_space, and .bss all
* have an apparently unnecessary ALIGN at their top. This is because
* the implementation of _start in Freedom Metal libgloss depends on the
* ADDR and LOADADDR being 8-byte aligned.
*/
.data : ALIGN(8) {
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.* .sdata2.*)
*(.gnu.linkonce.s.*)
} >ram AT>rom :ram_init
.tdata : ALIGN(8) {
PROVIDE( __tls_base = . );
*(.tdata .tdata.* .gnu.linkonce.td.*)
} >ram AT>rom :tls :ram_init
PROVIDE( __tdata_source = LOADADDR(.tdata) );
PROVIDE( __tdata_size = SIZEOF(.tdata) );
PROVIDE( metal_segment_data_source_start = LOADADDR(.data) );
PROVIDE( metal_segment_data_target_start = ADDR(.data) );
PROVIDE( metal_segment_data_target_end = ADDR(.tdata) + SIZEOF(.tdata) );
.tbss : ALIGN(8) {
*(.tbss .tbss.* .gnu.linkonce.tb.*)
*(.tcommon .tcommon.*)
PROVIDE( __tls_end = . );
} >ram AT>ram :tls :ram
PROVIDE( __tbss_size = SIZEOF(.tbss) );
PROVIDE( __tls_size = __tls_end - __tls_base );
.tbss_space : ALIGN(8) {
. = . + __tbss_size;
} >ram :ram
.bss (NOLOAD): ALIGN(8) {
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
} >ram :ram
PROVIDE( metal_segment_bss_source_start = LOADADDR(.tbss) );
PROVIDE( metal_segment_bss_target_start = ADDR(.tbss) );
PROVIDE( metal_segment_bss_target_end = ADDR(.bss) + SIZEOF(.bss) );
.text :
{
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.itim .itim.*)
*(.gnu.linkonce.t.*)
} >flash AT>flash :flash
.stack (NOLOAD) : ALIGN(16) {
PROVIDE(metal_segment_stack_begin = .);
. += __stack_size; /* Hart 0 */
PROVIDE( _sp = . );
__freertos_irq_stack_top = .;
PROVIDE(metal_segment_stack_end = .);
} >ram :ram
.fini : .heap (NOLOAD) : ALIGN(8) {
{ PROVIDE( __end = . );
KEEP (*(SORT_NONE(.fini))) PROVIDE( __heap_start = . );
} >flash AT>flash :flash PROVIDE( metal_segment_heap_target_start = . );
/* If __heap_max is defined, grow the heap to use the rest of RAM,
* otherwise set the heap size to __heap_size */
PROVIDE (__etext = .); . = DEFINED(__heap_max) ? MIN( LENGTH(ram) - ( . - ORIGIN(ram)) , 0x10000000) : __heap_size;
PROVIDE (_etext = .); PROVIDE( metal_segment_heap_target_end = . );
PROVIDE (etext = .); PROVIDE( _heap_end = . );
PROVIDE( __heap_end = . );
} >ram :ram
.rodata :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >flash AT>flash :flash
. = ALIGN(4);
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >flash AT>flash :flash
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >flash AT>flash :flash
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >flash AT>flash :flash
.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))
} >flash AT>flash :flash
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >flash AT>flash :flash
.litimalign :
{
. = ALIGN(4);
PROVIDE( metal_segment_itim_source_start = . );
} >flash AT>flash :flash
.ditimalign :
{
. = ALIGN(4);
PROVIDE( metal_segment_itim_target_start = . );
} >ram AT>flash :ram_init
.itim :
{
*(.itim .itim.*)
} >flash AT>flash :flash
. = ALIGN(8);
PROVIDE( metal_segment_itim_target_end = . );
.lalign :
{
. = ALIGN(4);
PROVIDE( _data_lma = . );
PROVIDE( metal_segment_data_source_start = . );
} >flash AT>flash :flash
.dalign :
{
. = ALIGN(4);
PROVIDE( metal_segment_data_target_start = . );
} >ram AT>flash :ram_init
.data :
{
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.* .sdata2.*)
*(.gnu.linkonce.s.*)
} >ram AT>flash :ram_init
. = ALIGN(4);
PROVIDE( _edata = . );
PROVIDE( edata = . );
PROVIDE( metal_segment_data_target_end = . );
PROVIDE( _fbss = . );
PROVIDE( __bss_start = . );
PROVIDE( metal_segment_bss_target_start = . );
.bss :
{
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
} >ram AT>ram :ram
. = ALIGN(8);
PROVIDE( _end = . );
PROVIDE( end = . );
PROVIDE( metal_segment_bss_target_end = . );
.stack :
{
. = ALIGN(16);
metal_segment_stack_begin = .;
. += __stack_size;
. = ALIGN(16);
_sp = .;
PROVIDE(metal_segment_stack_end = .);
__freertos_irq_stack_top = .;
} >ram AT>ram :ram
.heap :
{
PROVIDE( metal_segment_heap_target_start = . );
. = __heap_size;
PROVIDE( metal_segment_heap_target_end = . );
PROVIDE( _heap_end = . );
} >ram AT>ram :ram
/* C++ exception handling information is
* not useful with our current runtime environment,
* and it consumes flash space. Discard it until
* we have something that can use it
*/
/DISCARD/ : {
*(.eh_frame .eh_frame.*)
}
} }

View file

@ -0,0 +1,327 @@
/* Copyright (c) 2020 SiFive Inc. */
/* SPDX-License-Identifier: Apache-2.0 */
OUTPUT_ARCH("riscv")
/* Privileged mode Linker Script
*
* This linker script is based on metal.default.lds. It introduce specific
* section to isolate (acessible only from machine mode) and others that can be
* used in every execution mode. This linker script it tailored for FreeRTOS
* applications.
*/
ENTRY(_enter)
MEMORY
{
itim (airwx) : ORIGIN = 0x8000000, LENGTH = 0x2000
ram (arw!xi) : ORIGIN = 0x80000000, LENGTH = 0x4000
rom (irx!wa) : ORIGIN = 0x20010000, LENGTH = 0x6a120
}
PHDRS
{
rom PT_LOAD;
ram_init PT_LOAD;
tls PT_TLS;
ram PT_LOAD;
itim_init PT_LOAD;
text PT_LOAD;
lim_init PT_LOAD;
}
SECTIONS
{
/* Each hart is allocated its own stack of size __stack_size. This value
* can be overriden at build-time by adding the following to CFLAGS:
*
* -Xlinker --defsym=__stack_size=0xf00
*
* where 0xf00 can be replaced with a multiple of 16 of your choice.
*
* __stack_size is PROVIDE-ed as a symbol so that initialization code
* initializes the stack pointers for each hart at the right offset from
* the _sp symbol.
*/
__stack_size = DEFINED(__stack_size) ? __stack_size : 0x400;
PROVIDE(__stack_size = __stack_size);
/* The size of the heap can be overriden at build-time by adding the
* following to CFLAGS:
*
* -Xlinker --defsym=__heap_size=0xf00
*
* where 0xf00 can be replaced with the value of your choice.
*
* Altertatively, the heap can be grown to fill the entire remaining region
* of RAM by adding the following to CFLAGS:
*
* -Xlinker --defsym=__heap_max=1
*
* Note that depending on the memory layout, the bitness (32/64bit) of the
* target, and the code model in use, this might cause a relocation error.
*/
__heap_size = DEFINED(__heap_size) ? __heap_size : 0x800;
/* The boot hart sets which hart runs the pre-main initialization routines,
* including copying .data into RAM, zeroing the BSS region, running
* constructors, etc. After initialization, the boot hart is also the only
* hart which runs application code unless the application overrides the
* secondary_main() function to start execution on secondary harts.
*/
PROVIDE(__metal_boot_hart = 0);
/* The chicken bit is used by pre-main initialization to enable/disable
* certain core features */
PROVIDE(__metal_chicken_bit = 1);
/* The memory_ecc_scrub bit is used by _entry code to enable/disable
* memories scrubbing to zero */
PROVIDE(__metal_eccscrub_bit = 0);
/* The RAM memories map for ECC scrubbing */
PROVIDE( metal_dtim_0_memory_start = 0x80000000 );
PROVIDE( metal_dtim_0_memory_end = 0x80000000 + 0x4000 );
PROVIDE( metal_itim_0_memory_start = 0x8000000 );
PROVIDE( metal_itim_0_memory_end = 0x8000000 + 0x2000 );
/* ROM SECTION
*
* The following sections contain data which lives in read-only memory, if
* such memory is present in the design, for the entire duration of program
* execution.
*/
.init : {
/* The _enter symbol is placed in the .text.metal.init.enter section
* and must be placed at the beginning of the program */
KEEP (*(.text.metal.init.enter))
KEEP (*(.text.metal.init.*))
KEEP (*(SORT_NONE(.init)))
KEEP (*(.text.libgloss.start))
} >rom :rom
.fini : {
KEEP (*(SORT_NONE(.fini)))
} >rom :rom
.preinit_array : ALIGN(8) {
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >rom :rom
.init_array : ALIGN(8) {
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
PROVIDE_HIDDEN ( metal_constructors_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.metal.init_array.*)));
KEEP (*(.metal.init_array));
PROVIDE_HIDDEN ( metal_constructors_end = .);
} >rom :rom
.fini_array : ALIGN(8) {
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
PROVIDE_HIDDEN ( metal_destructors_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.metal.fini_array.*)));
KEEP (*(.metal.fini_array));
PROVIDE_HIDDEN ( metal_destructors_end = .);
} >rom :rom
.privileged_functions : ALIGN (32) {
__privileged_functions_start__ = .;
KEEP(*(privileged_functions))
. = ALIGN(32);
__privileged_functions_end__ = .;
} >rom
.ctors : {
. = ALIGN(32);
__unprivileged_section_start__ = .;
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
KEEP (*(.metal.ctors .metal.ctors.*))
} >rom :rom
.dtors : {
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
KEEP (*(.metal.dtors .metal.dtors.*))
} >rom : rom
.rodata : {
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >rom :rom
/* ITIM SECTION
*
* The following sections contain data which is copied from read-only
* memory into an instruction tightly-integrated memory (ITIM), if one
* is present in the design, during pre-main program initialization.
*
* Generally, the data copied into the ITIM should be performance-critical
* functions which benefit from low instruction-fetch latency.
*/
.itim : ALIGN(8) {
*(.itim .itim.*)
} >itim AT>rom :itim_init
PROVIDE( metal_segment_itim_source_start = LOADADDR(.itim) );
PROVIDE( metal_segment_itim_target_start = ADDR(.itim) );
PROVIDE( metal_segment_itim_target_end = ADDR(.itim) + SIZEOF(.itim) );
/* LIM SECTION
*
* The following sections contain data which is copied from read-only
* memory into a loosely integrated memory (LIM), which is shared with L2
* cache, during pre-main program initialization.
*
* Generally, the data copied into the LIM should be performance-critical
* functions which benefit from low instruction-fetch latency.
*/
.lim : ALIGN(8) {
*(.lim .lim.*)
} >ram AT>rom :lim_init
PROVIDE( metal_segment_lim_source_start = LOADADDR(.lim) );
PROVIDE( metal_segment_lim_target_start = ADDR(.lim) );
PROVIDE( metal_segment_lim_target_end = ADDR(.lim) + SIZEOF(.lim) );
/* TEXT SECTION
*
* The following section contains the code of the program, excluding
* everything that's been allocated into the ITIM/LIM already
*/
.text : {
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
*(freertos_system_calls)
. = ALIGN(32);
__unprivileged_section_end__ = .;
} >rom :text
/* RAM SECTION
*
* The following sections contain data which is copied from read-only
* memory into a read-write-capable memory such as data tightly-integrated
* memory (DTIM) or another main memory, as well as the BSS, stack, and
* heap.
*
* You might notice that .data, .tdata, .tbss, .tbss_space, and .bss all
* have an apparently unnecessary ALIGN at their top. This is because
* the implementation of _start in Freedom Metal libgloss depends on the
* ADDR and LOADADDR being 8-byte aligned.
*/
.data : ALIGN(8) {
. = ALIGN(32);
__unprivileged_data_section_start__ = .;
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.* .sdata2.*)
*(.gnu.linkonce.s.*)
} >ram AT>rom :ram_init
.tdata : ALIGN(8) {
PROVIDE( __tls_base = . );
*(.tdata .tdata.* .gnu.linkonce.td.*)
} >ram AT>rom :tls :ram_init
PROVIDE( __tdata_source = LOADADDR(.tdata) );
PROVIDE( __tdata_size = SIZEOF(.tdata) );
PROVIDE( metal_segment_data_source_start = LOADADDR(.data) );
PROVIDE( metal_segment_data_target_start = ADDR(.data) );
PROVIDE( metal_segment_data_target_end = ADDR(.tdata) + SIZEOF(.tdata) );
.tbss : ALIGN(8) {
*(.tbss .tbss.* .gnu.linkonce.tb.*)
*(.tcommon .tcommon.*)
PROVIDE( __tls_end = . );
} >ram AT>ram :tls :ram
PROVIDE( __tbss_size = SIZEOF(.tbss) );
PROVIDE( __tls_size = __tls_end - __tls_base );
.tbss_space : ALIGN(8) {
. = . + __tbss_size;
} >ram :ram
.bss (NOLOAD): ALIGN(8) {
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(32);
__unprivileged_data_section_end__ = .;
} >ram :ram
PROVIDE( metal_segment_bss_source_start = LOADADDR(.tbss) );
PROVIDE( metal_segment_bss_target_start = ADDR(.tbss) );
PROVIDE( metal_segment_bss_target_end = ADDR(.bss) + SIZEOF(.bss) );
.privileged_data (NOLOAD) : ALIGN(32) {
__privileged_data_start__ = .;
*(privileged_data)
/* Non kernel data is kept out of the first _Privileged_Data_Region_Size
bytes of SRAM. */
. = ALIGN(32);
__privileged_data_end__ = .;
} >ram
.stack (NOLOAD) : ALIGN(16) {
PROVIDE(metal_segment_stack_begin = .);
. += __stack_size; /* Hart 0 */
PROVIDE( _sp = . );
PROVIDE(metal_segment_stack_end = .);
} >ram :ram
.heap (NOLOAD) : ALIGN(8) {
PROVIDE( __end = . );
PROVIDE( __heap_start = . );
PROVIDE( metal_segment_heap_target_start = . );
/* If __heap_max is defined, grow the heap to use the rest of RAM,
* otherwise set the heap size to __heap_size */
. = DEFINED(__heap_max) ? MIN( LENGTH(ram) - ( . - ORIGIN(ram)) , 0x10000000) : __heap_size;
PROVIDE( metal_segment_heap_target_end = . );
PROVIDE( _heap_end = . );
PROVIDE( __heap_end = . );
} >ram :ram
/* C++ exception handling information is
* not useful with our current runtime environment,
* and it consumes flash space. Discard it until
* we have something that can use it
*/
/DISCARD/ : {
*(.eh_frame .eh_frame.*)
}
}

View file

@ -0,0 +1,306 @@
/* Copyright (c) 2020 SiFive Inc. */
/* SPDX-License-Identifier: Apache-2.0 */
OUTPUT_ARCH("riscv")
/* RAM Read-Only Data Linker Script
*
* This linker script places application code and read-only data into writable
* memories in an attempt to improve performance, since writable memories
* are generally lower-latency. This linker script may cause your application
* to overflow RAM, since it dramatically increases the quantity of data vying
* for space there.
*/
ENTRY(_enter)
MEMORY
{
itim (airwx) : ORIGIN = 0x8000000, LENGTH = 0x2000
ram (arw!xi) : ORIGIN = 0x80000000, LENGTH = 0x4000
rom (irx!wa) : ORIGIN = 0x20010000, LENGTH = 0x6a120
}
PHDRS
{
rom PT_LOAD;
ram_init PT_LOAD;
tls PT_TLS;
ram PT_LOAD;
itim_init PT_LOAD;
text PT_LOAD;
lim_init PT_LOAD;
}
SECTIONS
{
/* Each hart is allocated its own stack of size __stack_size. This value
* can be overriden at build-time by adding the following to CFLAGS:
*
* -Xlinker --defsym=__stack_size=0xf00
*
* where 0xf00 can be replaced with a multiple of 16 of your choice.
*
* __stack_size is PROVIDE-ed as a symbol so that initialization code
* initializes the stack pointers for each hart at the right offset from
* the _sp symbol.
*/
__stack_size = DEFINED(__stack_size) ? __stack_size : 0x400;
PROVIDE(__stack_size = __stack_size);
/* The size of the heap can be overriden at build-time by adding the
* following to CFLAGS:
*
* -Xlinker --defsym=__heap_size=0xf00
*
* where 0xf00 can be replaced with the value of your choice.
*
* Altertatively, the heap can be grown to fill the entire remaining region
* of RAM by adding the following to CFLAGS:
*
* -Xlinker --defsym=__heap_max=1
*
* Note that depending on the memory layout, the bitness (32/64bit) of the
* target, and the code model in use, this might cause a relocation error.
*/
__heap_size = DEFINED(__heap_size) ? __heap_size : 0x800;
/* The boot hart sets which hart runs the pre-main initialization routines,
* including copying .data into RAM, zeroing the BSS region, running
* constructors, etc. After initialization, the boot hart is also the only
* hart which runs application code unless the application overrides the
* secondary_main() function to start execution on secondary harts.
*/
PROVIDE(__metal_boot_hart = 0);
/* The chicken bit is used by pre-main initialization to enable/disable
* certain core features */
PROVIDE(__metal_chicken_bit = 1);
/* The memory_ecc_scrub bit is used by _entry code to enable/disable
* memories scrubbing to zero */
PROVIDE(__metal_eccscrub_bit = 0);
/* The RAM memories map for ECC scrubbing */
PROVIDE( metal_dtim_0_memory_start = 0x80000000 );
PROVIDE( metal_dtim_0_memory_end = 0x80000000 + 0x4000 );
PROVIDE( metal_itim_0_memory_start = 0x8000000 );
PROVIDE( metal_itim_0_memory_end = 0x8000000 + 0x2000 );
/* ROM SECTION
*
* The following sections contain data which lives in read-only memory, if
* such memory is present in the design, for the entire duration of program
* execution.
*/
.init : {
/* The _enter symbol is placed in the .text.metal.init.enter section
* and must be placed at the beginning of the program */
KEEP (*(.text.metal.init.enter))
KEEP (*(.text.metal.init.*))
KEEP (*(SORT_NONE(.init)))
KEEP (*(.text.libgloss.start))
} >rom :rom
.fini : {
KEEP (*(SORT_NONE(.fini)))
} >rom :rom
.preinit_array : ALIGN(8) {
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >rom :rom
.init_array : ALIGN(8) {
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
PROVIDE_HIDDEN ( metal_constructors_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.metal.init_array.*)));
KEEP (*(.metal.init_array));
PROVIDE_HIDDEN ( metal_constructors_end = .);
} >rom :rom
.fini_array : ALIGN(8) {
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
PROVIDE_HIDDEN ( metal_destructors_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.metal.fini_array.*)));
KEEP (*(.metal.fini_array));
PROVIDE_HIDDEN ( metal_destructors_end = .);
} >rom :rom
.ctors : {
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
KEEP (*(.metal.ctors .metal.ctors.*))
} >rom :rom
.dtors : {
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
KEEP (*(.metal.dtors .metal.dtors.*))
} >rom : rom
/* ITIM SECTION
*
* The following sections contain data which is copied from read-only
* memory into an instruction tightly-integrated memory (ITIM), if one
* is present in the design, during pre-main program initialization.
*
* Generally, the data copied into the ITIM should be performance-critical
* functions which benefit from low instruction-fetch latency.
*/
.itim : ALIGN(8) {
*(.itim .itim.*)
} >itim AT>rom :itim_init
PROVIDE( metal_segment_itim_source_start = LOADADDR(.itim) );
PROVIDE( metal_segment_itim_target_start = ADDR(.itim) );
PROVIDE( metal_segment_itim_target_end = ADDR(.itim) + SIZEOF(.itim) );
/* LIM SECTION
*
* The following sections contain data which is copied from read-only
* memory into a loosely integrated memory (LIM), which is shared with L2
* cache, during pre-main program initialization.
*
* Generally, the data copied into the LIM should be performance-critical
* functions which benefit from low instruction-fetch latency.
*/
.lim : ALIGN(8) {
*(.lim .lim.*)
} >ram AT>rom :lim_init
PROVIDE( metal_segment_lim_source_start = LOADADDR(.lim) );
PROVIDE( metal_segment_lim_target_start = ADDR(.lim) );
PROVIDE( metal_segment_lim_target_end = ADDR(.lim) + SIZEOF(.lim) );
/* TEXT SECTION
*
* The following section contains the code of the program, excluding
* everything that's been allocated into the ITIM/LIM already
*/
.text : {
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
} >rom :text
/* RAM SECTION
*
* The following sections contain data which is copied from read-only
* memory into a read-write-capable memory such as data tightly-integrated
* memory (DTIM) or another main memory, as well as the BSS, stack, and
* heap.
*
* You might notice that .data, .tdata, .tbss, .tbss_space, and .bss all
* have an apparently unnecessary ALIGN at their top. This is because
* the implementation of _start in Freedom Metal libgloss depends on the
* ADDR and LOADADDR being 8-byte aligned.
*/
.data : ALIGN(8) {
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.* .sdata2.*)
*(.gnu.linkonce.s.*)
/* Read-only data is placed in RAM to improve performance, since
* read-only memory generally has higher latency than RAM */
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
. = ALIGN(8);
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
} >ram AT>rom :ram_init
.tdata : ALIGN(8) {
PROVIDE( __tls_base = . );
*(.tdata .tdata.* .gnu.linkonce.td.*)
} >ram AT>rom :tls :ram_init
PROVIDE( __tdata_source = LOADADDR(.tdata) );
PROVIDE( __tdata_size = SIZEOF(.tdata) );
PROVIDE( metal_segment_data_source_start = LOADADDR(.data) );
PROVIDE( metal_segment_data_target_start = ADDR(.data) );
PROVIDE( metal_segment_data_target_end = ADDR(.tdata) + SIZEOF(.tdata) );
.tbss : ALIGN(8) {
*(.tbss .tbss.* .gnu.linkonce.tb.*)
*(.tcommon .tcommon.*)
PROVIDE( __tls_end = . );
} >ram AT>ram :tls :ram
PROVIDE( __tbss_size = SIZEOF(.tbss) );
PROVIDE( __tls_size = __tls_end - __tls_base );
.tbss_space : ALIGN(8) {
. = . + __tbss_size;
} >ram :ram
.bss (NOLOAD): ALIGN(8) {
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
} >ram :ram
PROVIDE( metal_segment_bss_source_start = LOADADDR(.tbss) );
PROVIDE( metal_segment_bss_target_start = ADDR(.tbss) );
PROVIDE( metal_segment_bss_target_end = ADDR(.bss) + SIZEOF(.bss) );
.stack (NOLOAD) : ALIGN(16) {
PROVIDE(metal_segment_stack_begin = .);
. += __stack_size; /* Hart 0 */
PROVIDE( _sp = . );
PROVIDE(metal_segment_stack_end = .);
} >ram :ram
.heap (NOLOAD) : ALIGN(8) {
PROVIDE( __end = . );
PROVIDE( __heap_start = . );
PROVIDE( metal_segment_heap_target_start = . );
/* If __heap_max is defined, grow the heap to use the rest of RAM,
* otherwise set the heap size to __heap_size */
. = DEFINED(__heap_max) ? MIN( LENGTH(ram) - ( . - ORIGIN(ram)) , 0x10000000) : __heap_size;
PROVIDE( metal_segment_heap_target_end = . );
PROVIDE( _heap_end = . );
PROVIDE( __heap_end = . );
} >ram :ram
/* C++ exception handling information is
* not useful with our current runtime environment,
* and it consumes flash space. Discard it until
* we have something that can use it
*/
/DISCARD/ : {
*(.eh_frame .eh_frame.*)
}
}

View file

@ -0,0 +1,294 @@
/* Copyright (c) 2020 SiFive Inc. */
/* SPDX-License-Identifier: Apache-2.0 */
OUTPUT_ARCH("riscv")
/* Scratchpad Linker Script
*
* This linker script is for executing in "scratchpad" mode, where all
* application code and data is placed in writable memory.
*/
ENTRY(_enter)
MEMORY
{
itim (airwx) : ORIGIN = 0x8000000, LENGTH = 0x2000
ram (arw!xi) : ORIGIN = 0x80000000, LENGTH = 0x4000
rom (irx!wa) : ORIGIN = 0x20010000, LENGTH = 0x6a120
}
PHDRS
{
rom PT_LOAD;
ram_init PT_LOAD;
tls PT_TLS;
ram PT_LOAD;
itim_init PT_LOAD;
text PT_LOAD;
lim_init PT_LOAD;
}
SECTIONS
{
/* Each hart is allocated its own stack of size __stack_size. This value
* can be overriden at build-time by adding the following to CFLAGS:
*
* -Xlinker --defsym=__stack_size=0xf00
*
* where 0xf00 can be replaced with a multiple of 16 of your choice.
*
* __stack_size is PROVIDE-ed as a symbol so that initialization code
* initializes the stack pointers for each hart at the right offset from
* the _sp symbol.
*/
__stack_size = DEFINED(__stack_size) ? __stack_size : 0x400;
PROVIDE(__stack_size = __stack_size);
/* The size of the heap can be overriden at build-time by adding the
* following to CFLAGS:
*
* -Xlinker --defsym=__heap_size=0xf00
*
* where 0xf00 can be replaced with the value of your choice.
*
* Altertatively, the heap can be grown to fill the entire remaining region
* of RAM by adding the following to CFLAGS:
*
* -Xlinker --defsym=__heap_max=1
*
* Note that depending on the memory layout, the bitness (32/64bit) of the
* target, and the code model in use, this might cause a relocation error.
*/
__heap_size = DEFINED(__heap_size) ? __heap_size : 0x800;
/* The boot hart sets which hart runs the pre-main initialization routines,
* including copying .data into RAM, zeroing the BSS region, running
* constructors, etc. After initialization, the boot hart is also the only
* hart which runs application code unless the application overrides the
* secondary_main() function to start execution on secondary harts.
*/
PROVIDE(__metal_boot_hart = 0);
/* The chicken bit is used by pre-main initialization to enable/disable
* certain core features */
PROVIDE(__metal_chicken_bit = 1);
PROVIDE(__metal_eccscrub_bit = 0);
/* ROM SECTION
*
* The following sections contain data which lives in read-only memory, if
* such memory is present in the design, for the entire duration of program
* execution.
*/
.init : {
/* The _enter symbol is placed in the .text.metal.init.enter section
* and must be placed at the beginning of the program */
KEEP (*(.text.metal.init.enter))
KEEP (*(.text.metal.init.*))
KEEP (*(SORT_NONE(.init)))
KEEP (*(.text.libgloss.start))
} >ram :rom
.fini : {
KEEP (*(SORT_NONE(.fini)))
} >ram :rom
.preinit_array : ALIGN(8) {
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >ram :rom
.init_array : ALIGN(8) {
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
PROVIDE_HIDDEN ( metal_constructors_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.metal.init_array.*)));
KEEP (*(.metal.init_array));
PROVIDE_HIDDEN ( metal_constructors_end = .);
} >ram :rom
.fini_array : ALIGN(8) {
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
PROVIDE_HIDDEN ( metal_destructors_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.metal.fini_array.*)));
KEEP (*(.metal.fini_array));
PROVIDE_HIDDEN ( metal_destructors_end = .);
} >ram :rom
.ctors : {
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
KEEP (*(.metal.ctors .metal.ctors.*))
} >ram :rom
.dtors : {
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
KEEP (*(.metal.dtors .metal.dtors.*))
} >ram : rom
.rodata : {
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >ram :rom
/* ITIM SECTION
*
* The following sections contain data which is copied from read-only
* memory into an instruction tightly-integrated memory (ITIM), if one
* is present in the design, during pre-main program initialization.
*
* Generally, the data copied into the ITIM should be performance-critical
* functions which benefit from low instruction-fetch latency.
*/
.itim : ALIGN(8) {
*(.itim .itim.*)
} >itim AT>ram :itim_init
PROVIDE( metal_segment_itim_source_start = LOADADDR(.itim) );
PROVIDE( metal_segment_itim_target_start = ADDR(.itim) );
PROVIDE( metal_segment_itim_target_end = ADDR(.itim) + SIZEOF(.itim) );
/* LIM SECTION
*
* The following sections contain data which is copied from read-only
* memory into a loosely integrated memory (LIM), which is shared with L2
* cache, during pre-main program initialization.
*
* Generally, the data copied into the LIM should be performance-critical
* functions which benefit from low instruction-fetch latency.
*/
.lim : ALIGN(8) {
*(.lim .lim.*)
} >ram AT>ram :lim_init
PROVIDE( metal_segment_lim_source_start = LOADADDR(.lim) );
PROVIDE( metal_segment_lim_target_start = ADDR(.lim) );
PROVIDE( metal_segment_lim_target_end = ADDR(.lim) + SIZEOF(.lim) );
/* TEXT SECTION
*
* The following section contains the code of the program, excluding
* everything that's been allocated into the ITIM/LIM already
*/
.text : {
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
} >ram :text
/* RAM SECTION
*
* The following sections contain data which is copied from read-only
* memory into a read-write-capable memory such as data tightly-integrated
* memory (DTIM) or another main memory, as well as the BSS, stack, and
* heap.
*
* You might notice that .data, .tdata, .tbss, .tbss_space, and .bss all
* have an apparently unnecessary ALIGN at their top. This is because
* the implementation of _start in Freedom Metal libgloss depends on the
* ADDR and LOADADDR being 8-byte aligned.
*/
.data : ALIGN(8) {
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.* .sdata2.*)
*(.gnu.linkonce.s.*)
} >ram AT>ram :ram_init
.tdata : ALIGN(8) {
PROVIDE( __tls_base = . );
*(.tdata .tdata.* .gnu.linkonce.td.*)
} >ram AT>ram :tls :ram_init
PROVIDE( __tdata_source = LOADADDR(.tdata) );
PROVIDE( __tdata_size = SIZEOF(.tdata) );
PROVIDE( metal_segment_data_source_start = LOADADDR(.data) );
PROVIDE( metal_segment_data_target_start = ADDR(.data) );
PROVIDE( metal_segment_data_target_end = ADDR(.tdata) + SIZEOF(.tdata) );
.tbss : ALIGN(8) {
*(.tbss .tbss.* .gnu.linkonce.tb.*)
*(.tcommon .tcommon.*)
PROVIDE( __tls_end = . );
} >ram AT>ram :tls :ram
PROVIDE( __tbss_size = SIZEOF(.tbss) );
PROVIDE( __tls_size = __tls_end - __tls_base );
.tbss_space : ALIGN(8) {
. = . + __tbss_size;
} >ram :ram
.bss (NOLOAD): ALIGN(8) {
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
} >ram :ram
PROVIDE( metal_segment_bss_source_start = LOADADDR(.tbss) );
PROVIDE( metal_segment_bss_target_start = ADDR(.tbss) );
PROVIDE( metal_segment_bss_target_end = ADDR(.bss) + SIZEOF(.bss) );
.stack (NOLOAD) : ALIGN(16) {
PROVIDE(metal_segment_stack_begin = .);
. += __stack_size; /* Hart 0 */
PROVIDE( _sp = . );
PROVIDE(metal_segment_stack_end = .);
} >ram :ram
.heap (NOLOAD) : ALIGN(8) {
PROVIDE( __end = . );
PROVIDE( __heap_start = . );
PROVIDE( metal_segment_heap_target_start = . );
/* If __heap_max is defined, grow the heap to use the rest of RAM,
* otherwise set the heap size to __heap_size */
. = DEFINED(__heap_max) ? MIN( LENGTH(ram) - ( . - ORIGIN(ram)) , 0x10000000) : __heap_size;
PROVIDE( metal_segment_heap_target_end = . );
PROVIDE( _heap_end = . );
PROVIDE( __heap_end = . );
} >ram :ram
/* C++ exception handling information is
* not useful with our current runtime environment,
* and it consumes flash space. Discard it until
* we have something that can use it
*/
/DISCARD/ : {
*(.eh_frame .eh_frame.*)
}
}

View file

@ -0,0 +1,13 @@
# Copyright (C) 2020 SiFive Inc
# SPDX-License-Identifier: Apache-2.0
RISCV_ARCH = rv32imac
RISCV_ABI = ilp32
RISCV_CMODEL = medlow
RISCV_SERIES = sifive-3-series
TARGET_TAGS = board jlink
TARGET_DHRY_ITERS = 20000000
TARGET_CORE_ITERS = 5000
TARGET_FREERTOS_WAIT_MS = 1000
TARGET_INTR_WAIT_CYCLE = 0

View file

@ -0,0 +1,5 @@
BasedOnStyle: LLVM
Language: Cpp
IndentWidth: 4

View file

@ -0,0 +1,35 @@
sudo: required
# Travis doesn't provide a wide variety of host environments to run on, so we
# rely on Docker to provide these instead.
services:
- docker
# It is not really needed, other than for showing correct language tag in
# Travis CI build log.
language: c
# The matrix of targets that we're interested in.
env:
- HOST="ubuntu:16.04"
# Before running the install phase we need to set up docker container that runs
# the target machine.
before_install:
- docker run -d --name host -v $(pwd):/travis $HOST tail -f /dev/null
- docker ps
# Update the container and install dependencies
install:
- docker exec -t host bash -c "yes | apt-get update"
- docker exec -t host bash -c "yes | apt-get upgrade"
- docker exec -t host bash -c "yes | apt-get install git clang-format-6.0"
- sudo curl -L -o /tmp/wake.deb https://github.com/sifive/wake/releases/download/v0.19.0/ubuntu-16-04-wake_0.19.0-1_amd64.deb
- sudo apt install /tmp/wake.deb
# Here's where we actually run the test.
script:
# Check source code formatting
- docker exec -t host bash -c "cd /travis && ./scripts/check-format"
# Run dummy Wake program in order to run Wake type checker.
- wake --init . && wake -x Unit

View file

@ -0,0 +1,3 @@
This source repository is release under Apache2 and MIT licenses.
See LICENSE.Apache2 and LICENSE.MIT for details.

View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2019 SiFive, Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,238 @@
# Copyright 2018-2019 SiFive, Inc
# SPDX-License-Identifier: Apache-2.0
########################################################
# Sources passed in by configure
########################################################
metal/machine.h: @MACHINE_HEADER@
@mkdir -p $(dir $@)
cp $< $@
metal/machine/inline.h: @MACHINE_INLINE@
@mkdir -p $(dir $@)
cp $< $@
metal/machine/platform.h: @PLATFORM_HEADER@
@mkdir -p $(dir $@)
cp $< $@
nobase_include_HEADERS = \
metal/machine.h \
metal/machine/inline.h \
metal/machine/platform.h
# This will generate these sources before the compilation step
BUILT_SOURCES = \
metal/machine.h \
metal/machine/inline.h \
metal/machine/platform.h
########################################################
# Metal header files
########################################################
nobase_include_HEADERS += \
metal/drivers/fixed-clock.h \
metal/drivers/fixed-factor-clock.h \
metal/drivers/riscv_clint0.h \
metal/drivers/riscv_cpu.h \
metal/drivers/riscv_plic0.h \
metal/drivers/sifive_buserror0.h \
metal/drivers/sifive_ccache0.h \
metal/drivers/sifive_clic0.h \
metal/drivers/sifive_fe310-g000_hfrosc.h \
metal/drivers/sifive_fe310-g000_hfxosc.h \
metal/drivers/sifive_fe310-g000_lfrosc.h \
metal/drivers/sifive_fe310-g000_pll.h \
metal/drivers/sifive_fe310-g000_prci.h \
metal/drivers/sifive_global-external-interrupts0.h \
metal/drivers/sifive_gpio-buttons.h \
metal/drivers/sifive_gpio-leds.h \
metal/drivers/sifive_gpio-switches.h \
metal/drivers/sifive_gpio0.h \
metal/drivers/sifive_i2c0.h \
metal/drivers/sifive_l2pf0.h \
metal/drivers/sifive_local-external-interrupts0.h \
metal/drivers/sifive_pwm0.h \
metal/drivers/sifive_rtc0.h \
metal/drivers/sifive_spi0.h \
metal/drivers/sifive_test0.h \
metal/drivers/sifive_trace.h \
metal/drivers/sifive_uart0.h \
metal/drivers/sifive_simuart0.h \
metal/drivers/sifive_wdog0.h \
metal/drivers/ucb_htif0.h \
metal/atomic.h \
metal/button.h \
metal/cache.h \
metal/clock.h \
metal/compiler.h \
metal/cpu.h \
metal/csr.h \
metal/gpio.h \
metal/hpm.h \
metal/i2c.h \
metal/init.h \
metal/interrupt.h \
metal/io.h \
metal/itim.h \
metal/led.h \
metal/lim.h \
metal/lock.h \
metal/memory.h \
metal/pmp.h \
metal/privilege.h \
metal/pwm.h\
metal/rtc.h \
metal/shutdown.h \
metal/scrub.h \
metal/spi.h \
metal/switch.h \
metal/timer.h \
metal/time.h \
metal/tty.h \
metal/uart.h \
metal/watchdog.h
########################################################
# libmetal
########################################################
lib_LIBRARIES = libmetal.a
libmetal_a_SOURCES = \
src/drivers/fixed-clock.c \
src/drivers/fixed-factor-clock.c \
src/drivers/inline.c \
src/drivers/riscv_clint0.c \
src/drivers/riscv_cpu.c \
src/drivers/riscv_plic0.c \
src/drivers/sifive_buserror0.c \
src/drivers/sifive_ccache0.c \
src/drivers/sifive_clic0.c \
src/drivers/sifive_fe310-g000_hfrosc.c \
src/drivers/sifive_fe310-g000_hfxosc.c \
src/drivers/sifive_fe310-g000_lfrosc.c \
src/drivers/sifive_fe310-g000_pll.c \
src/drivers/sifive_fe310-g000_prci.c \
src/drivers/sifive_global-external-interrupts0.c \
src/drivers/sifive_gpio-buttons.c \
src/drivers/sifive_gpio-leds.c \
src/drivers/sifive_gpio-switches.c \
src/drivers/sifive_gpio0.c \
src/drivers/sifive_i2c0.c \
src/drivers/sifive_l2pf0.c \
src/drivers/sifive_local-external-interrupts0.c \
src/drivers/sifive_pwm0.c \
src/drivers/sifive_rtc0.c \
src/drivers/sifive_spi0.c \
src/drivers/sifive_test0.c \
src/drivers/sifive_trace.c \
src/drivers/sifive_uart0.c \
src/drivers/sifive_simuart0.c \
src/drivers/sifive_wdog0.c \
src/drivers/ucb_htif0.c \
src/atomic.c \
src/button.c \
src/cache.c \
src/clock.c \
src/cpu.c \
src/entry.S \
src/scrub.S \
src/trap.S \
src/gpio.c \
src/hpm.c \
src/i2c.c \
src/init.c \
src/interrupt.c \
src/led.c \
src/lock.c \
src/memory.c \
src/pmp.c \
src/privilege.c \
src/pwm.c\
src/rtc.c \
src/shutdown.c \
src/spi.c \
src/switch.c \
src/synchronize_harts.c \
src/timer.c \
src/time.c \
src/trap.S \
src/tty.c \
src/uart.c \
src/vector.S \
src/watchdog.c
########################################################
# libsegger
########################################################
# Provide segger hook with Freedom Metal that is built when
# --with-builtin-libmetal-segger is passed to configure
if WITH_BUILTIN_LIBMETAL_SEGGER
lib_LIBRARIES += libmetal-segger.a
libmetal_segger_a_SOURCES = \
gloss/crt0.S \
segger/SEGGER_target_metal.c
endif # WITH_BUILTIN_LIBMETAL_SEGGER
########################################################
# libgloss
########################################################
# Freedom Metal has its own libgloss implementation that is only built when
# --with-builtin-libgloss is passed to configure.
if WITH_BUILTIN_LIBGLOSS
lib_LIBRARIES += libmetal-gloss.a
libmetal_gloss_a_SOURCES = \
gloss/crt0.S \
gloss/nanosleep.c \
gloss/sys_access.c \
gloss/sys_chdir.c \
gloss/sys_chmod.c \
gloss/sys_chown.c \
gloss/sys_clock_gettime.c \
gloss/sys_close.c \
gloss/sys_execve.c \
gloss/sys_exit.c \
gloss/sys_faccessat.c \
gloss/sys_fork.c \
gloss/sys_fstat.c \
gloss/sys_fstatat.c \
gloss/sys_ftime.c \
gloss/sys_getcwd.c \
gloss/sys_getpid.c \
gloss/sys_gettimeofday.c \
gloss/sys_isatty.c \
gloss/sys_kill.c \
gloss/sys_link.c \
gloss/sys_lseek.c \
gloss/sys_lstat.c \
gloss/sys_open.c \
gloss/sys_openat.c \
gloss/sys_read.c \
gloss/sys_sbrk.c \
gloss/sys_stat.c \
gloss/sys_sysconf.c \
gloss/sys_times.c \
gloss/sys_unlink.c \
gloss/sys_utime.c \
gloss/sys_wait.c \
gloss/sys_write.c
endif
########################################################
# Clean
########################################################
clean-local:
-rm -rf metal/machine.h metal/machine/inline.h
-rm -rf metal/machine/platform.h

View file

@ -0,0 +1,4 @@
# Freedom Metal Machine Compatibility Library
Documentation for the Freedom Metal library [can be found here](https://sifive.github.io/freedom-metal-docs/).

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,270 @@
#! /bin/sh
# Wrapper for Microsoft lib.exe
me=ar-lib
scriptversion=2012-03-01.08; # UTC
# Copyright (C) 2010-2014 Free Software Foundation, Inc.
# Written by Peter Rosin <peda@lysator.liu.se>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
# func_error message
func_error ()
{
echo "$me: $1" 1>&2
exit 1
}
file_conv=
# func_file_conv build_file
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv in
mingw)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin)
file=`cygpath -m "$file" || echo "$file"`
;;
wine)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_at_file at_file operation archive
# Iterate over all members in AT_FILE performing OPERATION on ARCHIVE
# for each of them.
# When interpreting the content of the @FILE, do NOT use func_file_conv,
# since the user would need to supply preconverted file names to
# binutils ar, at least for MinGW.
func_at_file ()
{
operation=$2
archive=$3
at_file_contents=`cat "$1"`
eval set x "$at_file_contents"
shift
for member
do
$AR -NOLOGO $operation:"$member" "$archive" || exit $?
done
}
case $1 in
'')
func_error "no command. Try '$0 --help' for more information."
;;
-h | --h*)
cat <<EOF
Usage: $me [--help] [--version] PROGRAM ACTION ARCHIVE [MEMBER...]
Members may be specified in a file named with @FILE.
EOF
exit $?
;;
-v | --v*)
echo "$me, version $scriptversion"
exit $?
;;
esac
if test $# -lt 3; then
func_error "you must specify a program, an action and an archive"
fi
AR=$1
shift
while :
do
if test $# -lt 2; then
func_error "you must specify a program, an action and an archive"
fi
case $1 in
-lib | -LIB \
| -ltcg | -LTCG \
| -machine* | -MACHINE* \
| -subsystem* | -SUBSYSTEM* \
| -verbose | -VERBOSE \
| -wx* | -WX* )
AR="$AR $1"
shift
;;
*)
action=$1
shift
break
;;
esac
done
orig_archive=$1
shift
func_file_conv "$orig_archive"
archive=$file
# strip leading dash in $action
action=${action#-}
delete=
extract=
list=
quick=
replace=
index=
create=
while test -n "$action"
do
case $action in
d*) delete=yes ;;
x*) extract=yes ;;
t*) list=yes ;;
q*) quick=yes ;;
r*) replace=yes ;;
s*) index=yes ;;
S*) ;; # the index is always updated implicitly
c*) create=yes ;;
u*) ;; # TODO: don't ignore the update modifier
v*) ;; # TODO: don't ignore the verbose modifier
*)
func_error "unknown action specified"
;;
esac
action=${action#?}
done
case $delete$extract$list$quick$replace,$index in
yes,* | ,yes)
;;
yesyes*)
func_error "more than one action specified"
;;
*)
func_error "no action specified"
;;
esac
if test -n "$delete"; then
if test ! -f "$orig_archive"; then
func_error "archive not found"
fi
for member
do
case $1 in
@*)
func_at_file "${1#@}" -REMOVE "$archive"
;;
*)
func_file_conv "$1"
$AR -NOLOGO -REMOVE:"$file" "$archive" || exit $?
;;
esac
done
elif test -n "$extract"; then
if test ! -f "$orig_archive"; then
func_error "archive not found"
fi
if test $# -gt 0; then
for member
do
case $1 in
@*)
func_at_file "${1#@}" -EXTRACT "$archive"
;;
*)
func_file_conv "$1"
$AR -NOLOGO -EXTRACT:"$file" "$archive" || exit $?
;;
esac
done
else
$AR -NOLOGO -LIST "$archive" | sed -e 's/\\/\\\\/g' | while read member
do
$AR -NOLOGO -EXTRACT:"$member" "$archive" || exit $?
done
fi
elif test -n "$quick$replace"; then
if test ! -f "$orig_archive"; then
if test -z "$create"; then
echo "$me: creating $orig_archive"
fi
orig_archive=
else
orig_archive=$archive
fi
for member
do
case $1 in
@*)
func_file_conv "${1#@}"
set x "$@" "@$file"
;;
*)
func_file_conv "$1"
set x "$@" "$file"
;;
esac
shift
shift
done
if test -n "$orig_archive"; then
$AR -NOLOGO -OUT:"$archive" "$orig_archive" "$@" || exit $?
else
$AR -NOLOGO -OUT:"$archive" "$@" || exit $?
fi
elif test -n "$list"; then
if test ! -f "$orig_archive"; then
func_error "archive not found"
fi
$AR -NOLOGO -LIST "$archive" || exit $?
fi

View file

@ -0,0 +1,150 @@
tuple MachineExecutionEnvironment =
Job_: Job
IncludeDir_: String
LibDir_: String
LibMetal_: Path
LibMetalGloss_: Path
ConfigOptions: FreedomMetalConfigureOptions
AllOutputs_: List Path
global def getMachineExecutionEnvironmentJob = getMachineExecutionEnvironmentJob_
global def getMachineExecutionEnvironmentLibMetal = getMachineExecutionEnvironmentLibMetal_
global def getMachineExecutionEnvironmentLibMetalGloss = getMachineExecutionEnvironmentLibMetalGloss_
global def getMachineExecutionEnvironmentIncludeDir = getMachineExecutionEnvironmentIncludeDir_
global def getMachineExecutionEnvironmentLibDir = getMachineExecutionEnvironmentLibDir_
global def getMachineExecutionEnvironmentAllOutputs = getMachineExecutionEnvironmentAllOutputs_
global def getMachineExecutionEnvironmentRISCV_ARCH = _.getMachineExecutionEnvironmentConfigOptions.getFreedomMetalConfigureOptionsRISCV_ARCH
global def getMachineExecutionEnvironmentRISCV_ABI = _.getMachineExecutionEnvironmentConfigOptions.getFreedomMetalConfigureOptionsRISCV_ABI
global def getMachineExecutionEnvironmentRISCV_CMODEL = _.getMachineExecutionEnvironmentConfigOptions.getFreedomMetalConfigureOptionsRISCV_CMODEL
global def getMachineExecutionEnvironmentHost = _.getMachineExecutionEnvironmentConfigOptions.getFreedomMetalConfigureOptionsHost
global def getMachineExecutionEnvironmentPrefix = _.getMachineExecutionEnvironmentConfigOptions.getFreedomMetalConfigureOptionsOutputDir
global def getMachineExecutionEnvironmentName = _.getMachineExecutionEnvironmentConfigOptions.getFreedomMetalConfigureOptionsMachineName
global def getMachineExecutionEnvironmentHeader = _.getMachineExecutionEnvironmentConfigOptions.getFreedomMetalConfigureOptionsMachineHeader
global def getMachineExecutionEnvironmentLdScript = _.getMachineExecutionEnvironmentConfigOptions.getFreedomMetalConfigureOptionsMachineLdScript
tuple FreedomMetalConfigureOptions =
global Resources: List String
global RISCV_ARCH: String
global RISCV_ABI: String
global RISCV_CMODEL: String
global Host: String
global OutputDir: String
global MachineName: String
global MachineHeader: Path
global MachineInlineHeader: Path
global PlatformHeader: Path
global MachineLdScript: Path
global def defaultSiFiveRISCVResources = "riscv-tools/2019.05.0", Nil
global def makeFreedomMetalConfigureOptions arch abi cmodel host outputDir name header inlineHeader platformHeader ldScript =
def resources = defaultSiFiveRISCVResources
FreedomMetalConfigureOptions resources arch abi cmodel host outputDir name header inlineHeader platformHeader ldScript
global tuple MakeElfOptions =
global MEE: MachineExecutionEnvironment
global ProgramSrcs: List Path
global CFlags: List String
global LFlags: List String
global IncludeDirs: List String
global ElfFile: String
global def runFreedomMetalInstall options =
def outputDir = options.getFreedomMetalConfigureOptionsOutputDir
def metalHeader = options.getFreedomMetalConfigureOptionsMachineHeader
def metalInline = options.getFreedomMetalConfigureOptionsMachineInlineHeader
def platformHeader = options.getFreedomMetalConfigureOptionsPlatformHeader
def metalInstallDir = outputDir
def installedFreedomMetal =
def inputs =
sources "freedom-metal" `.*`
| filter (!matches `freedom-metal/doc/.*` _.getPathName)
def cmdline =
"rsync",
"-r",
"--exclude", "freedom-metal/doc",
"--exclude", "freedom-metal/.git",
"--exclude", "*.wake",
"freedom-metal",
outputDir,
Nil
def fnOutputs _ =
files "freedom-metal" `.*`
| filter (!matches `freedom-metal/(\.git|doc)/.*` _)
| filter (!matches `.*\.(in|am|m4|wake)` _) # exclude these because autoconf modfies them
| filter (!matches `(.*/)?(configure)` _)
| map ("{metalInstallDir}/{_}")
makePlan cmdline inputs
| setPlanFnOutputs fnOutputs
| setPlanLocalOnly True
| runJob
| getJobOutputs
def runDir = "{metalInstallDir}/freedom-metal"
def cmdline = "bash", "-c", "%
set -eo pipefail
machine_header=$(pwd)/%{metalHeader.getPathName}
machine_inline=$(pwd)/%{metalInline.getPathName}
platform_header=$(pwd)/%{platformHeader.getPathName}
install_dir=$(pwd)/%{outputDir}
export RISCV_PATH=$RISCV
cd %{runDir}
./configure \
--host=%{options.getFreedomMetalConfigureOptionsHost} \
--with-builtin-libgloss \
--with-machine-header=$machine_header \
--with-machine-inline=$machine_inline \
--with-platform-header=$platform_header \
--prefix=
make \
RANLIB="riscv64-unknown-elf-ranlib -D" \
ARFLAGS=Dcr
make \
RANLIB="riscv64-unknown-elf-ranlib -D" \
ARFLAGS=Dcr \
DESTDIR=$install_dir \
install
%", Nil
def inputs = mkdir outputDir, metalHeader, installedFreedomMetal
def foutputs _ =
files "{outputDir}/include" `.*`
++ files "{outputDir}/lib" `.*`
def withCFlags =
def march = options.getFreedomMetalConfigureOptionsRISCV_ARCH
def mabi = options.getFreedomMetalConfigureOptionsRISCV_ABI
def cmodel = options.getFreedomMetalConfigureOptionsRISCV_CMODEL
"CFLAGS=-march={march} -mabi={mabi} -g -mcmodel={cmodel}", _
def job =
makePlan cmdline inputs
| setPlanLocalOnly True
| setPlanFnOutputs foutputs
| setPlanResources options.getFreedomMetalConfigureOptionsResources
| editPlanEnvironment withCFlags
| runJob
def makeOutputs = job.getJobOutputs
def getFile f msg = match (makeOutputs | map getPathResult | findFail)
Fail e = makeBadPath e
Pass _ =
filter (simplify f ==~ _.getPathName) makeOutputs
| head
| getOrElse msg.makeError.makeBadPath
def libmetal =
def fileName = "{outputDir}/lib/libmetal.a"
getFile fileName "Failed to compile libmetal: {fileName}"
def libmetalGloss =
def fileName = "{outputDir}/lib/libmetal-gloss.a"
getFile fileName "Failed to compile libgloss: {fileName}"
def includeDir = "{outputDir}/include"
def libDir = "{outputDir}/lib"
MachineExecutionEnvironment job includeDir libDir libmetal libmetalGloss options makeOutputs

View file

@ -0,0 +1,347 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2012-10-14.11; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
func_file_conv "$1"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
}
# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
lib=$1
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
lib=$dir/$lib.dll.lib
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
lib=$dir/$lib.lib
break
fi
if test -f "$dir/lib$lib.a"; then
found=yes
lib=$dir/lib$lib.a
break
fi
done
IFS=$save_IFS
if test "$found" != yes; then
lib=$lib.lib
fi
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I)
eat=1
func_file_conv "$2" mingw
set x "$@" -I"$file"
shift
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l)
eat=1
func_cl_dashl "$2"
set x "$@" "$lib"
shift
;;
-l*)
func_cl_dashl "${1#-l}"
set x "$@" "$lib"
shift
;;
-L)
eat=1
func_cl_dashL "$2"
;;
-L*)
func_cl_dashL "${1#-L}"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,97 @@
# The name, version, and maintainer of this package
AC_INIT([freedom-metal], [m4_esyscmd_s([./scripts/git-version])], [https://github.com/sifive/freedom-metal/issues], [freedom-metal], [https://github.com/sifive/freedom-metal])
# Initializes automake, enabling maintainer mode by default (which should be
# disabled by the archive generated by "make dist").
AM_INIT_AUTOMAKE([foreign subdir-objects])
AM_MAINTAINER_MODE([disable])
AC_CONFIG_MACRO_DIRS([m4])
AC_CANONICAL_HOST
# Probe for tools that we need in order to build.
AC_PROG_CC
AC_PROG_RANLIB
AM_PROG_AR
AM_PROG_AS
# autoconf tries very hard to avoid failing, so it'll even go ahead and try to
# build the project using "gcc" if it can't find a suitable C compiler prefixed
# by the host system. This doesn't work when cross compiling, but it's a
# common error for users so we explicitly check for this right here to quickly
# provide an error message.
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[
#ifndef __riscv
# error "A RISC-V compiler is required to build Freedom Metal"
#endif
])], [], [AC_MSG_FAILURE([The C compiler doesn't define __riscv, which means it's probably not a RISC-V compiler. You should specify something like --host=riscv64-sifive-elf when building this, as it will only work on RISC-V systems.])])
########################################################
# Options
########################################################
AC_ARG_WITH([builtin-libgloss],
[AS_HELP_STRING([--with-bultin-libgloss], [Build libgloss along with Metal])],
[with_builtin_libgloss="yes"],
[with_builtin_libgloss="no"]
)
AC_ARG_WITH([builtin-libmetal-pico],
[AS_HELP_STRING([--with-bultin-libmetal-pico], [Build libmetal-pico along with Metal])],
[with_builtin_libmetal_pico="yes"],
[with_builtin_libmetal_pico="no"]
)
AC_ARG_WITH([builtin-libmetal-segger],
[AS_HELP_STRING([--with-bultin-libmetal-segger], [Build libmetal-segger along with Metal])],
[with_builtin_libmetal_segger="yes"],
[with_builtin_libmetal_segger="no"]
)
AC_ARG_WITH([machine-header],
[AS_HELP_STRING([--with-machine-header=PATH], [Path to the machine header file])],
[],
[with_machine_header="no"]
)
AC_ARG_WITH([machine-inline],
[AS_HELP_STRING([--with-machine-inline=PATH], [Path to the machine inline file])],
[],
[with_machine_inline="no"]
)
AC_ARG_WITH([platform-header],
[AS_HELP_STRING([--with-platform-header=PATH], [Path to the platform header file])],
[],
[with_platform_header="no"]
)
########################################################
# Process Options
########################################################
AM_CONDITIONAL([WITH_BUILTIN_LIBGLOSS], [test "x$with_builtin_libgloss" = "xyes"])
AM_CONDITIONAL([WITH_BUILTIN_LIBMETAL_PICO], [test "x$with_builtin_libmetal_pico" = "xyes"])
AM_CONDITIONAL([WITH_BUILTIN_LIBMETAL_SEGGER], [test "x$with_builtin_libmetal_segger" = "xyes"])
# Configure the build system to pass in the preconfigured machine support files
AS_IF([test "x$with_machine_header" != "xno"],
[AC_SUBST([MACHINE_HEADER], "$with_machine_header")],
[AC_MSG_FAILURE([--with-machine-header is required])]
)
AS_IF([test "x$with_machine_inline" != "xno"],
[AC_SUBST([MACHINE_INLINE], "$with_machine_inline")],
[AC_MSG_FAILURE([--with-machine-inline is required])]
)
AS_IF([test "x$with_platform_header" != "xno"],
[AC_SUBST([PLATFORM_HEADER], "$with_platform_header")],
[AC_MSG_FAILURE([--with-platform-header is required])]
)
# Generates the remainder of the build system.
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

View file

@ -0,0 +1,791 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2013-05-30.07; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
# Get the directory component of the given path, and save it in the
# global variables '$dir'. Note that this directory component will
# be either empty or ending with a '/' character. This is deliberate.
set_dir_from ()
{
case $1 in
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
*) dir=;;
esac
}
# Get the suffix-stripped basename of the given path, and save it the
# global variable '$base'.
set_base_from ()
{
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
}
# If no dependency file was actually created by the compiler invocation,
# we still have to create a dummy depfile, to avoid errors with the
# Makefile "include basename.Plo" scheme.
make_dummy_depfile ()
{
echo "#dummy" > "$depfile"
}
# Factor out some common post-processing of the generated depfile.
# Requires the auxiliary global variable '$tmpdepfile' to be set.
aix_post_process_depfile ()
{
# If the compiler actually managed to produce a dependency file,
# post-process it.
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependency.h'.
# Do two passes, one to just change these to
# $object: dependency.h
# and one to simply output
# dependency.h:
# which is needed to avoid the deleted-header problem.
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
} > "$depfile"
rm -f "$tmpdepfile"
else
make_dummy_depfile
fi
}
# A tabulation character.
tab=' '
# A newline character.
nl='
'
# Character ranges might be problematic outside the C locale.
# These definitions help.
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower=abcdefghijklmnopqrstuvwxyz
digits=0123456789
alpha=${upper}${lower}
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Avoid interferences from the environment.
gccflag= dashmflag=
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
## (see the conditional assignment to $gccflag above).
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say). Also, it might not be
## supported by the other compilers which use the 'gcc' depmode.
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The second -e expression handles DOS-style file names with drive
# letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
| tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
aix_post_process_depfile
;;
tcc)
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
# FIXME: That version still under development at the moment of writing.
# Make that this statement remains true also for stable, released
# versions.
# It will wrap lines (doesn't matter whether long or short) with a
# trailing '\', as in:
#
# foo.o : \
# foo.c \
# foo.h \
#
# It will put a trailing '\' even on the last line, and will use leading
# spaces rather than leading tabs (at least since its commit 0394caf7
# "Emit spaces for -MD").
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
# We have to change lines of the first kind to '$object: \'.
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
# And for each line of the second kind, we have to emit a 'dep.h:'
# dummy dependency, to avoid the deleted-header problem.
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
## The order of this option in the case statement is important, since the
## shell code in configure will try each of these formats in the order
## listed in this file. A plain '-MD' option would be understood by many
## compilers, so we must ensure this comes after the gcc and icc options.
pgcc)
# Portland's C compiler understands '-MD'.
# Will always output deps to 'file.d' where file is the root name of the
# source file under compilation, even if file resides in a subdirectory.
# The object file name does not affect the name of the '.d' file.
# pgcc 10.2 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\' :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
set_dir_from "$object"
# Use the source, not the object, to determine the base name, since
# that's sadly what pgcc will do too.
set_base_from "$source"
tmpdepfile=$base.d
# For projects that build the same source file twice into different object
# files, the pgcc approach of using the *source* file root name can cause
# problems in parallel builds. Use a locking strategy to avoid stomping on
# the same $tmpdepfile.
lockdir=$base.d-lock
trap "
echo '$0: caught signal, cleaning up...' >&2
rmdir '$lockdir'
exit 1
" 1 2 13 15
numtries=100
i=$numtries
while test $i -gt 0; do
# mkdir is a portable test-and-set.
if mkdir "$lockdir" 2>/dev/null; then
# This process acquired the lock.
"$@" -MD
stat=$?
# Release the lock.
rmdir "$lockdir"
break
else
# If the lock is being held by a different process, wait
# until the winning process is done or we timeout.
while test -d "$lockdir" && test $i -gt 0; do
sleep 1
i=`expr $i - 1`
done
fi
i=`expr $i - 1`
done
trap - 1 2 13 15
if test $i -le 0; then
echo "$0: failed to acquire lock after $numtries attempts" >&2
echo "$0: check lockdir '$lockdir'" >&2
exit 1
fi
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
# Libtool generates 2 separate objects for the 2 libraries. These
# two compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir$base.o.d # libtool 1.5
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
# Same post-processing that is required for AIX mode.
aix_post_process_depfile
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this sed invocation
# correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process the last invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed '1,2d' "$tmpdepfile" \
| tr ' ' "$nl" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E \
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
| sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View file

@ -1,5 +0,0 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,11
[InternetShortcut]
IDList=
URL=https://github.com/sifive/freedom-metal-docs

View file

@ -44,22 +44,7 @@ _start:
la gp, __global_pointer$ la gp, __global_pointer$
.option pop .option pop
/* The METAL is designed for a bare-metal environment and therefor is expected /* Stack pointer is expected to be initialized before _start */
* to define its own stack pointer. We also align the stack pointer here
* because the only RISC-V ABI that's currently defined mandates 16-byte
* stack alignment. */
la sp, _sp
/* Increment by hartid number of stack sizes */
li t0, 0
la t1, __stack_size
1:
beq t0, a0, 1f
add sp, sp, t1
addi t0, t0, 1
j 1b
1:
andi sp, sp, -16
/* If we're not hart 0, skip the initialization work */ /* If we're not hart 0, skip the initialization work */
la t0, __metal_boot_hart la t0, __metal_boot_hart
@ -123,6 +108,36 @@ _start:
complete */ complete */
fence.i fence.i
2:
/* Copy the LIM section */
la t0, metal_segment_lim_source_start
la t1, metal_segment_lim_target_start
la t2, metal_segment_lim_target_end
beq t0, t1, 2f
bge t1, t2, 2f
1:
#if __riscv_xlen == 32
lw a0, 0(t0)
addi t0, t0, 4
sw a0, 0(t1)
addi t1, t1, 4
blt t1, t2, 1b
#else
ld a0, 0(t0)
addi t0, t0, 8
sd a0, 0(t1)
addi t1, t1, 8
blt t1, t2, 1b
#endif
2:
/* Fence all subsequent instruction fetches until after the LIM writes
complete */
fence.i
/* Zero the BSS segment. */ /* Zero the BSS segment. */
la t1, metal_segment_bss_target_start la t1, metal_segment_bss_target_start
la t2, metal_segment_bss_target_end la t2, metal_segment_bss_target_end
@ -141,6 +156,10 @@ _start:
#endif #endif
2: 2:
/* Set TLS pointer */
.weak __tls_base
la tp, __tls_base
/* At this point we're in an environment that can execute C code. The first /* At this point we're in an environment that can execute C code. The first
* thing to do is to make the callback to the parent environment if it's been * thing to do is to make the callback to the parent environment if it's been
* requested to do so. */ * requested to do so. */
@ -153,14 +172,41 @@ _start:
call atexit call atexit
call __libc_init_array call __libc_init_array
/* Register metal_fini_run as a destructor and call metal_init_run to
* run and setup Metal constructors */
la a0, metal_fini_run
call atexit
call metal_init_run
_skip_init: _skip_init:
/* Synchronize harts so that secondary harts wait until hart 0 finishes /* Synchronize harts so that secondary harts wait until hart 0 finishes
initializing */ initializing */
call __metal_synchronize_harts call __metal_synchronize_harts
/* Check RISC-V isa and enable FS bits if Floating Point architecture. */ /* Disable and clear all interrupt sources */
li a3, -1
csrc mie, a3
csrc mip, a3
/* The delegation CSRs exist if user mode interrupts (N extension) or
* supervisor mode (S extension) are supported */
csrr a5, misa csrr a5, misa
lui a4, 0x42
and a4, a4, a5
beqz a4, 1f
csrc mideleg, a3
csrc medeleg, a3
1:
/* The satp CSR exists if supervisor mode (S extension) is supported */
lui a4, 0x40
and a4, a4, a5
beqz a4, 1f
csrc satp, a3
1:
/* Check RISC-V isa and enable FS bits if Floating Point architecture. */
li a4, 0x10028 li a4, 0x10028
and a5, a5, a4 and a5, a5, a4
beqz a5, 1f beqz a5, 1f
@ -171,6 +217,16 @@ _skip_init:
csrwi fcsr, 0 csrwi fcsr, 0
1: 1:
/* Check for vector extension support and enable it if found */
csrr a5, misa
li a4, 0x200000
and a5, a5, a4
beqz a5, 1f
csrr a5, mstatus
ori a5, a5, 0x200
csrw mstatus, a5
1:
/* This is a C runtime, so main() is defined to have some arguments. Since /* This is a C runtime, so main() is defined to have some arguments. Since
* there's nothing sane the METAL can pass we don't bother with that but * there's nothing sane the METAL can pass we don't bother with that but
* instead just setup as close to a NOP as we can. */ * instead just setup as close to a NOP as we can. */

View file

@ -1,9 +1,7 @@
#include <errno.h> #include <errno.h>
#include <sys/time.h> #include <sys/time.h>
int int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) {
nanosleep(const struct timespec *rqtp, struct timespec *rmtp) errno = ENOSYS;
{ return -1;
errno = ENOSYS;
return -1;
} }

View file

@ -1,59 +0,0 @@
/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */
#include <metal/machine.h>
#include <metal/machine/platform.h>
#include <metal/io.h>
#include <metal/cpu.h>
#define METAL_REG(base, offset) (((unsigned long)(base) + (offset)))
#define METAL_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)METAL_REG((base), (offset))))
#define METAL_MSIP(base, hart) (METAL_REGW((base),4*(hart)))
/*
* _synchronize_harts() is called by crt0.S to cause harts > 0 to wait for
* hart 0 to finish copying the datat section, zeroing the BSS, and running
* the libc contstructors.
*/
void _synchronize_harts() {
#if __METAL_DT_MAX_HARTS > 1
int hart = metal_cpu_get_current_hartid();
uintptr_t msip_base = 0;
/* Get the base address of the MSIP registers */
#ifdef __METAL_DT_RISCV_CLINT0_HANDLE
msip_base = __metal_driver_sifive_clint0_control_base(__METAL_DT_RISCV_CLINT0_HANDLE);
msip_base += METAL_RISCV_CLINT0_MSIP_BASE;
#elif __METAL_DT_RISCV_CLIC0_HANDLE
msip_base = __metal_driver_sifive_clic0_control_base(__METAL_DT_RISCV_CLIC0_HANDLE);
msip_base += METAL_RISCV_CLIC0_MSIP_BASE;
#else
#warning No handle for CLINT or CLIC found, harts may be unsynchronized after init!
#endif
/* Disable machine interrupts as a precaution */
__asm__ volatile("csrc mstatus, %0" :: "r" (METAL_MSTATUS_MIE));
if (hart == 0) {
/* Hart 0 waits for all harts to set their MSIP bit */
for (int i = 1 ; i < __METAL_DT_MAX_HARTS; i++) {
while (METAL_MSIP(msip_base, i) == 0) ;
}
/* Hart 0 clears everyone's MSIP bit */
for (int i = 1 ; i < __METAL_DT_MAX_HARTS; i++) {
METAL_MSIP(msip_base, i) = 0;
}
} else {
/* Other harts set their MSIP bit to indicate they're ready */
METAL_MSIP(msip_base, hart) = 1;
__asm__ volatile ("fence w,rw");
/* Wait for hart 0 to clear the MSIP bit */
while (METAL_MSIP(msip_base, hart) == 1) ;
}
#endif /* __METAL_DT_MAX_HARTS > 1 */
}

View file

@ -1,8 +1,6 @@
#include <errno.h> #include <errno.h>
int int _access(const char *file, int mode) {
_access(const char *file, int mode) errno = ENOSYS;
{ return -1;
errno = ENOSYS;
return -1;
} }

Some files were not shown because too many files have changed in this diff Show more