--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>\r
+<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">\r
+ \r
+ <storageModule moduleId="org.eclipse.cdt.core.settings">\r
+ \r
+ <cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480">\r
+ \r
+ <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">\r
+ \r
+ <externalSettings/>\r
+ \r
+ <extensions>\r
+ \r
+ <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>\r
+ \r
+ <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>\r
+ \r
+ <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>\r
+ \r
+ <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>\r
+ \r
+ <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>\r
+ \r
+ <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>\r
+ \r
+ </extensions>\r
+ \r
+ </storageModule>\r
+ \r
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">\r
+ \r
+ <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">\r
+ \r
+ <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480." name="/" resourcePath="">\r
+ \r
+ <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.debug.1023181676" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.debug">\r
+ \r
+ <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"/>\r
+ \r
+ <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"/>\r
+ \r
+ <tool command="riscv64-unknown-elf-gcc.exe" id="cdt.managedbuild.tool.gnu.cross.c.compiler.1469975065" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler">\r
+ \r
+ <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"/>\r
+ \r
+ <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"/>\r
+ \r
+ <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"/>\r
+ \r
+ <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">\r
+ \r
+ <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/include}""/>\r
+ \r
+ <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/full_demo/Common_Demo_Tasks/include}""/>\r
+ \r
+ <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}}""/>\r
+ \r
+ <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/portable/GCC/RISC-V}""/>\r
+ \r
+ <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/include}""/>\r
+ \r
+ <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/freedom-metal}""/>\r
+ \r
+ <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/bsp/install/include}""/>\r
+ \r
+ </option>\r
+ \r
+ <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"/>\r
+ \r
+ <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"/>\r
+ \r
+ <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1079251302" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>\r
+ \r
+ </tool>\r
+ \r
+ <tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.420742449" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler">\r
+ \r
+ <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"/>\r
+ \r
+ <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"/>\r
+ \r
+ </tool>\r
+ \r
+ <tool command="riscv64-unknown-elf-gcc.exe" id="cdt.managedbuild.tool.gnu.cross.c.linker.558060359" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker">\r
+ \r
+ <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"/>\r
+ \r
+ <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"/>\r
+ \r
+ <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"/>\r
+ \r
+ <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"/>\r
+ \r
+ <inputType id="cdt.managedbuild.tool.gnu.c.linker.input.549526426" superClass="cdt.managedbuild.tool.gnu.c.linker.input">\r
+ \r
+ <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>\r
+ \r
+ <additionalInput kind="additionalinput" paths="$(LIBS)"/>\r
+ \r
+ </inputType>\r
+ \r
+ </tool>\r
+ \r
+ <tool id="cdt.managedbuild.tool.gnu.cross.cpp.linker.2105463183" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker"/>\r
+ \r
+ <tool id="cdt.managedbuild.tool.gnu.cross.archiver.424513814" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>\r
+ \r
+ <tool command="riscv64-unknown-elf-gcc.exe" id="cdt.managedbuild.tool.gnu.cross.assembler.825438707" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler">\r
+ \r
+ <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"/>\r
+ \r
+ <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">\r
+ \r
+ <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/portable/GCC/RISC-V/chip_specific_extensions/RV32I_CLINT_no_extensions}""/>\r
+ \r
+ </option>\r
+ \r
+ <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1723023894" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>\r
+ \r
+ </tool>\r
+ \r
+ </toolChain>\r
+ \r
+ </folderInfo>\r
+ \r
+ <sourceEntries>\r
+ \r
+ <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>\r
+ \r
+ </sourceEntries>\r
+ \r
+ </configuration>\r
+ \r
+ </storageModule>\r
+ \r
+ <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>\r
+ \r
+ </cconfiguration>\r
+ \r
+ </storageModule>\r
+ \r
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">\r
+ \r
+ <project id="RTOSDemo.cdt.managedbuild.target.gnu.cross.exe.1669036252" name="Executable" projectType="cdt.managedbuild.target.gnu.cross.exe"/>\r
+ \r
+ </storageModule>\r
+ \r
+ <storageModule moduleId="scannerConfiguration">\r
+ \r
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>\r
+ \r
+ <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">\r
+ \r
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>\r
+ \r
+ </scannerConfigBuildInfo>\r
+ \r
+ </storageModule>\r
+ \r
+ <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>\r
+ \r
+ <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>\r
+ \r
+ <storageModule moduleId="refreshScope" versionNumber="2">\r
+ \r
+ <configuration configurationName="Debug">\r
+ \r
+ <resource resourceType="PROJECT" workspacePath="/RTOSDemo"/>\r
+ \r
+ </configuration>\r
+ \r
+ </storageModule>\r
+ \r
+</cproject>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+ <name>RTOSDemo</name>\r
+ <comment></comment>\r
+ <projects>\r
+ </projects>\r
+ <buildSpec>\r
+ <buildCommand>\r
+ <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>\r
+ <triggers>clean,full,incremental,</triggers>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ <buildCommand>\r
+ <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>\r
+ <triggers>full,incremental,</triggers>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ </buildSpec>\r
+ <natures>\r
+ <nature>org.eclipse.cdt.core.cnature</nature>\r
+ <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>\r
+ <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>\r
+ </natures>\r
+ <linkedResources>\r
+ <link>\r
+ <name>FreeRTOS_Source</name>\r
+ <type>2</type>\r
+ <locationURI>FREERTOS_ROOT/FreeRTOS/Source</locationURI>\r
+ </link>\r
+ <link>\r
+ <name>full_demo/Common_Demo_Tasks</name>\r
+ <type>2</type>\r
+ <locationURI>FREERTOS_ROOT/FreeRTOS/Demo/Common/Minimal</locationURI>\r
+ </link>\r
+ <link>\r
+ <name>full_demo/Common_Demo_Tasks/include</name>\r
+ <type>2</type>\r
+ <locationURI>FREERTOS_ROOT/FreeRTOS/Demo/Common/include</locationURI>\r
+ </link>\r
+ </linkedResources>\r
+ <filteredResources>\r
+ <filter>\r
+ <id>1570727806810</id>\r
+ <name>FreeRTOS_Source</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-event_groups.c</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727806825</id>\r
+ <name>FreeRTOS_Source</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-list.c</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727806841</id>\r
+ <name>FreeRTOS_Source</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-queue.c</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727806841</id>\r
+ <name>FreeRTOS_Source</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-stream_buffer.c</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727806841</id>\r
+ <name>FreeRTOS_Source</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-timers.c</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727806856</id>\r
+ <name>FreeRTOS_Source</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-tasks.c</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727892841</id>\r
+ <name>FreeRTOS_Source/include</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-event_groups.h</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727892856</id>\r
+ <name>FreeRTOS_Source/include</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-FreeRTOS.h</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727892856</id>\r
+ <name>FreeRTOS_Source/include</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-message_buffer.h</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727892856</id>\r
+ <name>FreeRTOS_Source/include</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-queue.h</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727892872</id>\r
+ <name>FreeRTOS_Source/include</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-semphr.h</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727892872</id>\r
+ <name>FreeRTOS_Source/include</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-stream_buffer.h</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727892888</id>\r
+ <name>FreeRTOS_Source/include</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-task.h</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727892888</id>\r
+ <name>FreeRTOS_Source/include</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-timers.h</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727962643</id>\r
+ <name>FreeRTOS_Source/portable</name>\r
+ <type>9</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-MemMang</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727962643</id>\r
+ <name>FreeRTOS_Source/portable</name>\r
+ <type>9</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-GCC</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1571005814144</id>\r
+ <name>full_demo/Common_Demo_Tasks</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-TimerDemo.c</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1571005814150</id>\r
+ <name>full_demo/Common_Demo_Tasks</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-blocktim.c</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1571005814159</id>\r
+ <name>full_demo/Common_Demo_Tasks</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-dynamic.c</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1571005814167</id>\r
+ <name>full_demo/Common_Demo_Tasks</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-TaskNotify.c</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727992991</id>\r
+ <name>FreeRTOS_Source/portable/GCC</name>\r
+ <type>9</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-RISC-V</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570727979500</id>\r
+ <name>FreeRTOS_Source/portable/MemMang</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-heap_4.c</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1571005832815</id>\r
+ <name>full_demo/Common_Demo_Tasks/include</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-TimerDemo.h</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1571005832820</id>\r
+ <name>full_demo/Common_Demo_Tasks/include</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-blocktim.h</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1571005832824</id>\r
+ <name>full_demo/Common_Demo_Tasks/include</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-dynamic.h</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1571005832829</id>\r
+ <name>full_demo/Common_Demo_Tasks/include</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-MessageBufferDemo.h</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1571005832835</id>\r
+ <name>full_demo/Common_Demo_Tasks/include</name>\r
+ <type>5</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-TaskNotify.h</arguments>\r
+ </matcher>\r
+ </filter>\r
+ <filter>\r
+ <id>1570728021983</id>\r
+ <name>FreeRTOS_Source/portable/GCC/RISC-V/chip_specific_extensions</name>\r
+ <type>9</type>\r
+ <matcher>\r
+ <id>org.eclipse.ui.ide.multiFilter</id>\r
+ <arguments>1.0-name-matches-false-false-RV32I_CLINT_no_extensions</arguments>\r
+ </matcher>\r
+ </filter>\r
+ </filteredResources>\r
+ <variableList>\r
+ <variable>\r
+ <name>FREERTOS_ROOT</name>\r
+ <value>$%7BPARENT-3-PROJECT_LOC%7D</value>\r
+ </variable>\r
+ </variableList>\r
+</projectDescription>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>\r
+<project>\r
+ \r
+ <configuration id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" name="Debug">\r
+ \r
+ <extension point="org.eclipse.cdt.core.LanguageSettingsProvider">\r
+ \r
+ <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>\r
+ \r
+ <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>\r
+ \r
+ <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>\r
+ \r
+ <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-316647897902857" 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 "${INPUTS}"" prefer-non-shared="true">\r
+ \r
+ <language-scope id="org.eclipse.cdt.core.gcc"/>\r
+ \r
+ <language-scope id="org.eclipse.cdt.core.g++"/>\r
+ \r
+ </provider>\r
+ \r
+ </extension>\r
+ \r
+ </configuration>\r
+ \r
+</project>\r
--- /dev/null
+/*\r
+ * FreeRTOS Kernel V10.2.1\r
+ * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * http://www.FreeRTOS.org\r
+ * http://aws.amazon.com/freertos\r
+ *\r
+ * 1 tab == 4 spaces!\r
+ */\r
+\r
+#ifndef FREERTOS_CONFIG_H\r
+#define FREERTOS_CONFIG_H\r
+\r
+/*-----------------------------------------------------------\r
+ * Application specific definitions.\r
+ *\r
+ * These definitions should be adjusted for your particular hardware and\r
+ * application requirements.\r
+ *\r
+ * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE\r
+ * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.\r
+ *\r
+ * See http://www.freertos.org/a00110.html.\r
+ *----------------------------------------------------------*/\r
+#define CLINT_CTRL_ADDR ( 0x02000000UL )\r
+#define configCLINT_BASE_ADDRESS CLINT_CTRL_ADDR\r
+#define configUSE_PREEMPTION 1\r
+#define configUSE_IDLE_HOOK 0\r
+#define configUSE_TICK_HOOK 1\r
+#define configCPU_CLOCK_HZ ( 32768 )\r
+#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )\r
+#define configMAX_PRIORITIES ( 7 )\r
+#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 120 ) /* Only needs to be this high as some demo tasks also use this constant. In production only the idle task would use this. */\r
+#define configTOTAL_HEAP_SIZE ( ( size_t ) 10900 )\r
+#define configMAX_TASK_NAME_LEN ( 16 )\r
+#define configUSE_TRACE_FACILITY 0\r
+#define configUSE_16_BIT_TICKS 0\r
+#define configIDLE_SHOULD_YIELD 0\r
+#define configUSE_MUTEXES 1\r
+#define configQUEUE_REGISTRY_SIZE 8\r
+#define configCHECK_FOR_STACK_OVERFLOW 2\r
+#define configUSE_RECURSIVE_MUTEXES 1\r
+#define configUSE_MALLOC_FAILED_HOOK 1\r
+#define configUSE_APPLICATION_TASK_TAG 0\r
+#define configUSE_COUNTING_SEMAPHORES 1\r
+#define configGENERATE_RUN_TIME_STATS 0\r
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1\r
+\r
+/* Co-routine definitions. */\r
+#define configUSE_CO_ROUTINES 0\r
+#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )\r
+\r
+/* Software timer definitions. */\r
+#define configUSE_TIMERS 1\r
+#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )\r
+#define configTIMER_QUEUE_LENGTH 8\r
+#define configTIMER_TASK_STACK_DEPTH ( 160 )\r
+\r
+/* Task priorities. Allow these to be overridden. */\r
+#ifndef uartPRIMARY_PRIORITY\r
+ #define uartPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )\r
+#endif\r
+\r
+/* Set the following definitions to 1 to include the API function, or zero\r
+to exclude the API function. */\r
+#define INCLUDE_vTaskPrioritySet 1\r
+#define INCLUDE_uxTaskPriorityGet 1\r
+#define INCLUDE_vTaskDelete 1\r
+#define INCLUDE_vTaskCleanUpResources 1\r
+#define INCLUDE_vTaskSuspend 1\r
+#define INCLUDE_vTaskDelayUntil 1\r
+#define INCLUDE_vTaskDelay 1\r
+#define INCLUDE_eTaskGetState 1\r
+#define INCLUDE_xTimerPendFunctionCall 1\r
+#define INCLUDE_xTaskAbortDelay 1\r
+#define INCLUDE_xTaskGetHandle 1\r
+#define INCLUDE_xSemaphoreGetMutexHolder 1\r
+\r
+/* Normal assert() semantics without relying on the provision of an assert.h\r
+header file. */\r
+void vAssertCalled( void );\r
+#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled()\r
+\r
+#endif /* FREERTOS_CONFIG_H */\r
--- /dev/null
+/*\r
+ * FreeRTOS Kernel V10.2.1\r
+ * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * http://www.FreeRTOS.org\r
+ * http://aws.amazon.com/freertos\r
+ *\r
+ * 1 tab == 4 spaces!\r
+ */\r
+\r
+/******************************************************************************\r
+ * NOTE 1: This project provides two demo applications. A simple blinky\r
+ * style project, and a more comprehensive test and demo application. The\r
+ * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting in main.c is used to select\r
+ * between the two. See the notes on using mainCREATE_SIMPLE_BLINKY_DEMO_ONLY\r
+ * in main.c. This file implements the simply blinky style version.\r
+ *\r
+ * NOTE 2: This file only contains the source code that is specific to the\r
+ * blinky demo. Generic functions, such FreeRTOS hook functions, and functions\r
+ * required to configure the hardware are defined in main.c.\r
+ ******************************************************************************\r
+ *\r
+ * main_blinky() creates one queue, and two tasks. It then starts the\r
+ * scheduler.\r
+ *\r
+ * The Queue Send Task:\r
+ * The queue send task is implemented by the prvQueueSendTask() function in\r
+ * this file. prvQueueSendTask() sits in a loop that causes it to repeatedly\r
+ * block for 1000 milliseconds, before sending the value 100 to the queue that\r
+ * was created within main_blinky(). Once the value is sent, the task loops\r
+ * back around to block for another 1000 milliseconds...and so on.\r
+ *\r
+ * The Queue Receive Task:\r
+ * The queue receive task is implemented by the prvQueueReceiveTask() function\r
+ * in this file. prvQueueReceiveTask() sits in a loop where it repeatedly\r
+ * blocks on attempts to read data from the queue that was created within\r
+ * main_blinky(). When data is received, the task checks the value of the\r
+ * data, and if the value equals the expected 100, toggles an LED. The 'block\r
+ * time' parameter passed to the queue receive function specifies that the task\r
+ * should be held in the Blocked state indefinitely to wait for data to be\r
+ * available on the queue. The queue receive task will only leave the Blocked\r
+ * state when the queue send task writes to the queue. As the queue send task\r
+ * writes to the queue every 1000 milliseconds, the queue receive task leaves\r
+ * the Blocked state every 1000 milliseconds, and therefore toggles the LED\r
+ * every 200 milliseconds.\r
+ */\r
+\r
+/* Standard includes. */\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <unistd.h>\r
+\r
+/* Kernel includes. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+#include "queue.h"\r
+\r
+/* Priorities used by the tasks. */\r
+#define mainQUEUE_RECEIVE_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
+#define mainQUEUE_SEND_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
+\r
+/* The rate at which data is sent to the queue. The 200ms value is converted\r
+to ticks using the pdMS_TO_TICKS() macro. */\r
+#define mainQUEUE_SEND_FREQUENCY_MS pdMS_TO_TICKS( 1000 )\r
+\r
+/* The maximum number items the queue can hold. The priority of the receiving\r
+task is above the priority of the sending task, so the receiving task will\r
+preempt the sending task and remove the queue items each time the sending task\r
+writes to the queue. Therefore the queue will never have more than one item in\r
+it at any time, and even with a queue length of 1, the sending task will never\r
+find the queue full. */\r
+#define mainQUEUE_LENGTH ( 1 )\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/*\r
+ * Called by main when mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set to 1 in\r
+ * main.c.\r
+ */\r
+void main_blinky( void );\r
+\r
+/*\r
+ * The tasks as described in the comments at the top of this file.\r
+ */\r
+static void prvQueueReceiveTask( void *pvParameters );\r
+static void prvQueueSendTask( void *pvParameters );\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/* The queue used by both tasks. */\r
+static QueueHandle_t xQueue = NULL;\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+void main_blinky( void )\r
+{\r
+ /* Create the queue. */\r
+ xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( uint32_t ) );\r
+\r
+ if( xQueue != NULL )\r
+ {\r
+ /* Start the two tasks as described in the comments at the top of this\r
+ file. */\r
+ xTaskCreate( prvQueueReceiveTask, /* The function that implements the task. */\r
+ "Rx", /* The text name assigned to the task - for debug only as it is not used by the kernel. */\r
+ configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */\r
+ NULL, /* The parameter passed to the task - not used in this case. */\r
+ mainQUEUE_RECEIVE_TASK_PRIORITY, /* The priority assigned to the task. */\r
+ NULL ); /* The task handle is not required, so NULL is passed. */\r
+\r
+ xTaskCreate( prvQueueSendTask, "TX", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL );\r
+\r
+ /* Start the tasks and timer running. */\r
+ vTaskStartScheduler();\r
+ }\r
+\r
+ /* If all is well, the scheduler will now be running, and the following\r
+ line will never be reached. If the following line does execute, then\r
+ there was insufficient FreeRTOS heap memory available for the Idle and/or\r
+ timer tasks to be created. See the memory management section on the\r
+ FreeRTOS web site for more details on the FreeRTOS heap\r
+ http://www.freertos.org/a00111.html. */\r
+ for( ;; );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvQueueSendTask( void *pvParameters )\r
+{\r
+TickType_t xNextWakeTime;\r
+const unsigned long ulValueToSend = 100UL;\r
+BaseType_t xReturned;\r
+\r
+ /* Remove compiler warning about unused parameter. */\r
+ ( void ) pvParameters;\r
+\r
+ /* Initialise xNextWakeTime - this only needs to be done once. */\r
+ xNextWakeTime = xTaskGetTickCount();\r
+\r
+ for( ;; )\r
+ {\r
+ /* Place this task in the blocked state until it is time to run again. */\r
+ vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS );\r
+\r
+ /* Send to the queue - causing the queue receive task to unblock and\r
+ toggle the LED. 0 is used as the block time so the sending operation\r
+ will not block - it shouldn't need to block as the queue should always\r
+ be empty at this point in the code. */\r
+ xReturned = xQueueSend( xQueue, &ulValueToSend, 0U );\r
+ configASSERT( xReturned == pdPASS );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvQueueReceiveTask( void *pvParameters )\r
+{\r
+unsigned long ulReceivedValue;\r
+const unsigned long ulExpectedValue = 100UL;\r
+extern void vToggleLED( void );\r
+\r
+ /* Remove compiler warning about unused parameter. */\r
+ ( void ) pvParameters;\r
+\r
+ for( ;; )\r
+ {\r
+ /* Wait until something arrives in the queue - this task will block\r
+ indefinitely provided INCLUDE_vTaskSuspend is set to 1 in\r
+ FreeRTOSConfig.h. */\r
+ xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY );\r
+\r
+ /* To get here something must have been received from the queue, but\r
+ is it the expected value? If it is, toggle the LED. */\r
+ if( ulReceivedValue == ulExpectedValue )\r
+ {\r
+ vToggleLED();\r
+ ulReceivedValue = 0U;\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
--- /dev/null
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "sifive,hifive1-revb";
+ model = "sifive,hifive1-revb";
+
+ chosen {
+ 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";
+ };
+ };
+};
--- /dev/null
+zero
+ra
+sp
+gp
+tp
+t0
+t1
+t2
+fp
+s1
+a0
+a1
+a2
+a3
+a4
+a5
+a6
+a7
+s2
+s3
+s4
+s5
+s6
+s7
+s8
+s9
+s10
+s11
+t3
+t4
+t5
+t6
+pc
+mstatus
+misa
+mie
+mtvec
+mscratch
+mepc
+mcause
+mtval
+mip
+mvendorid
+marchid
+mimpid
+mhartid
+tselect
+tdata1
+tdata2
+tdata3
+dcsr
+dpc
+dscratch
+priv
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__BUTTON_H
+#define METAL__BUTTON_H
+
+/*!
+ * @file button.h
+ * API for interfacing with physical buttons
+ */
+
+#include <metal/interrupt.h>
+
+struct metal_button;
+
+struct metal_button_vtable {
+ int (*button_exist)(struct metal_button *button, char *label);
+ struct metal_interrupt* (*interrupt_controller)(struct metal_button *button);
+ int (*get_interrupt_id)(struct metal_button *button);
+};
+
+/*!
+ * @brief A button device handle
+ *
+ * A `struct metal_button` is an implementation-defined object which represents
+ * a button on a development board.
+ */
+struct metal_button {
+ const struct metal_button_vtable *vtable;
+};
+
+/*!
+ * @brief Get a reference to a button
+ *
+ * @param label The DeviceTree label for the button
+ * @return A handle for the button
+ */
+struct metal_button* metal_button_get(char *label);
+
+
+/*!
+ * @brief Get the interrupt controller for a button
+ *
+ * @param button The handle for the button
+ * @return A pointer to the interrupt controller responsible for handling
+ * button interrupts.
+ */
+inline struct metal_interrupt*
+ metal_button_interrupt_controller(struct metal_button *button) { return button->vtable->interrupt_controller(button); }
+
+/*!
+ * @brief Get the interrupt id for a button
+ *
+ * @param button The handle for the 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); }
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__CACHE_H
+#define METAL__CACHE_H
+
+/*!
+ * @file cache.h
+ *
+ * @brief API for configuring caches
+ */
+
+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
+ */
+struct metal_cache {
+ const struct __metal_cache_vtable *vtable;
+};
+
+/*!
+ * @brief Initialize a cache
+ * @param cache The handle for the cache to initialize
+ * @param ways The number of ways to enable
+ *
+ * Initializes a cache with the requested number of ways enabled.
+ */
+inline void metal_cache_init(struct metal_cache *cache, int ways) {
+ return cache->vtable->init(cache, ways);
+}
+
+/*!
+ * @brief Get the current number of enabled cache ways
+ * @param cache The handle for the cache
+ * @return The current number of enabled cache ways
+ */
+inline int metal_cache_get_enabled_ways(struct metal_cache *cache) {
+ return cache->vtable->get_enabled_ways(cache);
+}
+
+/*!
+ * @brief Enable the requested number of cache ways
+ * @param cache The handle for the cache
+ * @param ways The number of ways to enabled
+ * @return 0 if the ways are successfully enabled
+ */
+inline int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways) {
+ return cache->vtable->set_enabled_ways(cache, ways);
+}
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__CLOCK_H
+#define METAL__CLOCK_H
+
+/*!
+ * @file clock.h
+ * @brief API for manipulating clock sources
+ *
+ * The clock interface allows for controlling the rate of various clocks in the system.
+ */
+
+struct metal_clock;
+
+#include <stddef.h>
+
+/* The generic interface to all clocks. */
+struct __metal_clock_vtable {
+ long (*get_rate_hz)(const struct metal_clock *clk);
+ long (*set_rate_hz)(struct metal_clock *clk, long hz);
+};
+
+/*!
+ * @brief Function signature of clock pre-rate change callbacks
+ */
+typedef void (*metal_clock_pre_rate_change_callback)(void *priv);
+
+/*!
+ * @brief Function signature of clock post-rate change callbacks
+ */
+typedef void (*metal_clock_post_rate_change_callback)(void *priv);
+
+/*!
+ * @struct metal_clock
+ * @brief The handle for a clock
+ *
+ * Clocks are defined as a pointer to a `struct metal_clock`, the contents of which
+ * are implementation defined. Users of the clock interface must call 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
+ * defined, making it impossible to call any of these functions without invoking
+ * implementation-defined behavior.
+ */
+struct metal_clock {
+ const struct __metal_clock_vtable *vtable;
+
+ /* Pre-rate change callback */
+ metal_clock_pre_rate_change_callback _pre_rate_change_callback;
+ void *_pre_rate_change_callback_priv;
+
+ /* Post-rate change callback */
+ metal_clock_post_rate_change_callback _post_rate_change_callback;
+ void *_post_rate_change_callback_priv;
+};
+
+/*!
+ * @brief Returns the current rate of the given clock
+ *
+ * @param clk The handle for the clock
+ * @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); }
+
+/*!
+ * @brief Set the current rate of a clock
+ *
+ * @param clk The handle for the clock
+ * @param hz The desired rate in Hz
+ * @return The new rate of the clock in Hz.
+ *
+ * Attempts to set the current rate of the given clock to as close as possible
+ * to the given rate in Hz. Returns the actual value that's been selected, which
+ * could be anything!
+ *
+ * Prior to and after the rate change of the clock, this will call the registered
+ * pre- and post-rate change callbacks.
+ */
+inline long metal_clock_set_rate_hz(struct metal_clock *clk, long hz)
+{
+ 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);
+
+ if (clk->_post_rate_change_callback != NULL)
+ clk->_post_rate_change_callback(clk->_post_rate_change_callback_priv);
+
+ return out;
+}
+
+/*!
+ * @brief Register a callback that must be called before a rate change
+ *
+ * @param clk The handle for the clock
+ * @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)
+{
+ clk->_pre_rate_change_callback = cb;
+ clk->_pre_rate_change_callback_priv = priv;
+}
+
+/*!
+ * @brief Registers a callback that must be called after a rate change
+ *
+ * @param clk The handle for the clock
+ * @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)
+{
+ clk->_post_rate_change_callback = cb;
+ clk->_post_rate_change_callback_priv = priv;
+}
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__COMPILER_H
+#define METAL__COMPILER_H
+
+#define __METAL_DECLARE_VTABLE(type) \
+ extern const struct type type;
+
+#define __METAL_DEFINE_VTABLE(type) \
+ const struct type type
+
+#define __METAL_GET_FIELD(reg, mask) \
+ (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
+
+/* Set field with mask for a given value */
+#define __METAL_SET_FIELD(reg, mask, val) \
+ (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
+
+void _metal_trap(int ecode);
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+
+/* SPDX-License-Identifier: Apache-2.0 */
+
+/*! @file cpu.h
+ * @brief API for accessing CPU capabilities.
+ */
+
+#ifndef METAL__CPU_H
+#define METAL__CPU_H
+
+#include <stdint.h>
+#include <metal/interrupt.h>
+
+struct metal_cpu;
+
+/*!
+ * @brief Function signature for exception handlers
+ */
+typedef void (*metal_exception_handler_t) (struct metal_cpu *cpu, int ecode);
+
+struct metal_cpu_vtable {
+ unsigned long long (*timer_get)(struct metal_cpu *cpu);
+ unsigned long long (*timebase_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);
+ struct metal_interrupt* (*tmr_controller_interrupt)(struct metal_cpu *cpu);
+ int (*get_tmr_interrupt_id)(struct metal_cpu *cpu);
+ struct metal_interrupt* (*sw_controller_interrupt)(struct metal_cpu *cpu);
+ int (*get_sw_interrupt_id)(struct metal_cpu *cpu);
+ int (*set_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);
+ struct metal_interrupt* (*controller_interrupt)(struct metal_cpu *cpu);
+ int (*exception_register)(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler);
+ int (*get_ilen)(struct metal_cpu *cpu, uintptr_t epc);
+ uintptr_t (*get_epc)(struct metal_cpu *cpu);
+ int (*set_epc)(struct metal_cpu *cpu, uintptr_t epc);
+};
+
+/*! @brief A device handle for a CPU hart
+ */
+struct metal_cpu {
+ const struct metal_cpu_vtable *vtable;
+};
+
+/*! @brief Get a reference to a CPU hart
+ *
+ * @param hartid The ID of the desired CPU hart
+ * @return A pointer to the CPU device handle
+ */
+struct metal_cpu* metal_cpu_get(int hartid);
+
+/*! @brief Get the hartid of the CPU hart executing this function
+ *
+ * @return The hartid of the current CPU hart */
+int metal_cpu_get_current_hartid();
+
+/*! @brief Get the number of CPU harts
+ *
+ * @return The number of CPU harts */
+int metal_cpu_get_num_harts();
+
+/*! @brief Get the CPU cycle count timer value
+ *
+ * Get the value of the cycle count timer for a given CPU
+ *
+ * @param cpu The CPU device handle
+ * @return The value of the CPU cycle count timer
+ */
+inline unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu)
+{ return cpu->vtable->timer_get(cpu); }
+
+/*! @brief Get the timebase of the CPU
+ *
+ * Get the value of the timebase of the cycle count timer
+ *
+ * @param cpu The CPU device handle
+ * @return The value of the cycle count timer timebase
+ */
+inline unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu)
+{ return cpu->vtable->timebase_get(cpu); }
+
+/*! @brief Get the value of the mtime RTC
+ *
+ * Get the value of the mtime real-time clock. The CPU interrupt controller
+ * must be initialized before this function is called or the return value
+ * will be 0.
+ *
+ * @param cpu The CPU device handle
+ * @return The value of mtime, or 0 if failure
+ */
+inline unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu)
+{ return cpu->vtable->mtime_get(cpu); }
+
+/*! @brief Set the value of the RTC mtimecmp RTC
+ *
+ * Set the value of the mtime real-time clock compare register. The CPU
+ * interrupt controller must be initialized before this function is called
+ * or the return value will be -1;
+ *
+ * @param cpu The CPU device handle
+ * @param time The value to set the compare register to
+ * @return The value of mtimecmp or -1 if error
+ */
+inline int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time)
+{ return cpu->vtable->mtimecmp_set(cpu, time); }
+
+/*! @brief Get a reference to RTC timer interrupt controller
+ *
+ * Get a reference to the interrupt controller for the real-time clock interrupt.
+ * The controller returned by this function must be initialized before any interrupts
+ * are registered or enabled with it.
+ *
+ * @param cpu The CPU device handle
+ * @return A pointer to the timer interrupt handle
+ */
+inline struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu)
+{ return cpu->vtable->tmr_controller_interrupt(cpu); }
+
+/*! @brief Get the RTC timer interrupt id
+ *
+ * Get the interrupt ID of the real-time clock interrupt
+ *
+ * @param cpu The CPU device handle
+ * @return The timer interrupt ID
+ */
+inline int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu)
+{ return cpu->vtable->get_tmr_interrupt_id(cpu); }
+
+/*! @brief Get a reference to the software interrupt controller
+ *
+ * Get a reference to the interrupt controller for the software/inter-process
+ * interrupt. The controller returned by this function must be initialized before
+ * any interrupts are registered or enabled with it.
+ *
+ * @param cpu The CPU device handle
+ * @return A pointer to the software interrupt handle
+ */
+inline struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu)
+{ return cpu->vtable->sw_controller_interrupt(cpu); }
+
+/*! @brief Get the software interrupt id
+ *
+ * Get the interrupt ID for the software/inter-process interrupt
+ *
+ * @param cpu The CPU device handle
+ * @return the software interrupt ID
+ */
+inline int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu)
+{ return cpu->vtable->get_sw_interrupt_id(cpu); }
+
+/*!
+ * @brief Set the inter-process interrupt for a hart
+ *
+ * Trigger a software/inter-process interrupt for a hart. The CPU interrupt
+ * controller for the CPU handle passed to this function must be initialized
+ * before this function is called.
+ *
+ * @param cpu The CPU device handle
+ * @param hartid The CPU hart ID to be interrupted
+ * @return 0 upon success
+ */
+inline int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid)
+{ return cpu->vtable->set_sw_ipi(cpu, hartid); }
+
+/*!
+ * @brief Clear the inter-process interrupt for a hart
+ *
+ * Clear the software/inter-process interrupt for a hart. The CPU interrupt
+ * controller for the CPU handle passed to this function must be initialized
+ * before this function is called.
+ *
+ * @param cpu The CPU device handle
+ * @param hartid The CPU hart ID to clear
+ * @return 0 upon success
+ */
+inline int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid)
+{ return cpu->vtable->clear_sw_ipi(cpu, hartid); }
+
+/*!
+ * @brief Get the value of MSIP for the given hart
+ *
+ * Get the value of the machine software interrupt pending bit for
+ * the given hart. The CPU interrupt controller for the CPU handle passed
+ * as argument to this function must be initialized before this function
+ * is called.
+ *
+ * @param cpu the CPU device handle
+ * @param hartid The CPU hart to read
+ * @return 0 upon success
+ */
+inline int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid)
+{ return cpu->vtable->get_msip(cpu, hartid); }
+
+/*!
+ * @brief Get the interrupt controller for the CPU
+ *
+ * Get the CPU interrupt controller. The controller returned by this
+ * function must be initialized before any interrupts are registered
+ * or enabled and before any exception handlers are registered with
+ * this CPU.
+ *
+ * @param cpu The CPU device handle
+ * @return The handle for the CPU interrupt controller
+ */
+inline struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu)
+{ return cpu->vtable->controller_interrupt(cpu); }
+
+/*!
+ * @brief Register an exception handler
+ *
+ * Register an exception handler for the CPU. The CPU interrupt controller must be initialized
+ * before this function is called.
+ *
+ * @param cpu The CPU device handle
+ * @param ecode The exception code to register a handler for
+ * @param handler Callback function for the exception handler
+ * @return 0 upon success
+ */
+inline int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler)
+{ return cpu->vtable->exception_register(cpu, ecode, handler); }
+
+/*!
+ * @brief Get the length of an instruction in bytes
+ *
+ * Get the length of an instruction in bytes.
+ *
+ * On RISC-V platforms, this is useful for detecting whether an instruction is
+ * compressed (2 bytes long) or uncompressed (4 bytes long).
+ *
+ * This function is useful in conjuction with `metal_cpu_get_exception_pc()`
+ * and `metal_cpu_set_exception_pc()` in order to cause the exception handler to
+ * return execution after the faulting instruction.
+ *
+ * @param cpu The CPU device handle
+ * @param epc The address of the instruction to measure
+ * @return the length of the instruction in bytes
+ */
+inline int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
+{ return cpu->vtable->get_ilen(cpu, epc); }
+
+/*!
+ * @brief Get the program counter of the current exception.
+ *
+ * This function must be called within an exception handler. The behavior is
+ * undefined outside of an exception handler.
+ *
+ * @param cpu The CPU device handle
+ * @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)
+{ return cpu->vtable->get_epc(cpu); }
+
+/*!
+ * @brief Set the exception program counter
+ *
+ * This function must be called within an exception handler. The behavior
+ * is undefined outside of an exception handler.
+ *
+ * This function can be used to cause an exception handler to return execution
+ * to an address other than the one that caused the exception.
+ *
+ * @param cpu the CPU device handle
+ * @param epc The address to set the exception program counter to
+ * @return 0 upon success
+ */
+inline int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc)
+{ return cpu->vtable->set_epc(cpu, epc); }
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__FIXED_CLOCK_H
+#define METAL__DRIVERS__FIXED_CLOCK_H
+
+struct __metal_driver_fixed_clock;
+
+#include <metal/compiler.h>
+#include <metal/clock.h>
+
+struct __metal_driver_vtable_fixed_clock {
+ struct __metal_clock_vtable clock;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_fixed_clock)
+
+struct __metal_driver_fixed_clock {
+ struct metal_clock clock;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__FIXED_FACTOR_CLOCK_H
+#define METAL__DRIVERS__FIXED_FACTOR_CLOCK_H
+
+struct __metal_driver_fixed_factor_clock;
+
+#include <metal/compiler.h>
+#include <metal/clock.h>
+
+struct __metal_driver_vtable_fixed_factor_clock {
+ struct __metal_clock_vtable clock;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_fixed_factor_clock)
+
+struct __metal_driver_fixed_factor_clock {
+ struct metal_clock clock;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__RISCV_CLINT0_H
+#define METAL__DRIVERS__RISCV_CLINT0_H
+
+#include <metal/compiler.h>
+#include <metal/drivers/riscv_cpu.h>
+
+struct __metal_driver_vtable_riscv_clint0 {
+ struct metal_interrupt_vtable clint_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_clint0)
+
+#define __METAL_MACHINE_MACROS
+#include <metal/machine.h>
+struct __metal_driver_riscv_clint0 {
+ struct metal_interrupt controller;
+ int init_done;
+};
+#undef __METAL_MACHINE_MACROS
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__RISCV_CPU_H
+#define METAL__DRIVERS__RISCV_CPU_H
+
+#include <stdint.h>
+#include <metal/cpu.h>
+#include <metal/compiler.h>
+
+#define METAL_MAX_CORES 8
+#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_DEFAULT_RTC_FREQ 32768
+
+#define METAL_DISABLE 0
+#define METAL_ENABLE 1
+
+#define METAL_ISA_A_EXTENSIONS 0x0001
+#define METAL_ISA_C_EXTENSIONS 0x0004
+#define METAL_ISA_D_EXTENSIONS 0x0008
+#define METAL_ISA_E_EXTENSIONS 0x0010
+#define METAL_ISA_F_EXTENSIONS 0x0020
+#define METAL_ISA_G_EXTENSIONS 0x0040
+#define METAL_ISA_I_EXTENSIONS 0x0100
+#define METAL_ISA_M_EXTENSIONS 0x1000
+#define METAL_ISA_N_EXTENSIONS 0x2000
+#define METAL_ISA_Q_EXTENSIONS 0x10000
+#define METAL_ISA_S_EXTENSIONS 0x40000
+#define METAL_ISA_U_EXTENSIONS 0x100000
+#define METAL_ISA_V_EXTENSIONS 0x200000
+#define METAL_ISA_XL32_EXTENSIONS 0x40000000UL
+#define METAL_ISA_XL64_EXTENSIONS 0x8000000000000000UL
+#define METAL_ISA_XL128_EXTENSIONS 0xC000000000000000UL
+
+#define METAL_MTVEC_DIRECT 0x00
+#define METAL_MTVEC_VECTORED 0x01
+#define METAL_MTVEC_CLIC 0x02
+#define METAL_MTVEC_CLIC_VECTORED 0x03
+#define METAL_MTVEC_CLIC_RESERVED 0x3C
+#define METAL_MTVEC_MASK 0x3F
+#if __riscv_xlen == 32
+#define METAL_MCAUSE_INTR 0x80000000UL
+#define METAL_MCAUSE_CAUSE 0x000003FFUL
+#else
+#define METAL_MCAUSE_INTR 0x8000000000000000UL
+#define METAL_MCAUSE_CAUSE 0x00000000000003FFUL
+#endif
+#define METAL_MCAUSE_MINHV 0x40000000UL
+#define METAL_MCAUSE_MPP 0x30000000UL
+#define METAL_MCAUSE_MPIE 0x08000000UL
+#define METAL_MCAUSE_MPIL 0x00FF0000UL
+#define METAL_MSTATUS_MIE 0x00000008UL
+#define METAL_MSTATUS_MPIE 0x00000080UL
+#define METAL_MSTATUS_MPP 0x00001800UL
+#define METAL_MSTATUS_FS_INIT 0x00002000UL
+#define METAL_MSTATUS_FS_CLEAN 0x00004000UL
+#define METAL_MSTATUS_FS_DIRTY 0x00006000UL
+#define METAL_MSTATUS_MPRV 0x00020000UL
+#define METAL_MSTATUS_MXR 0x00080000UL
+#define METAL_MINTSTATUS_MIL 0xFF000000UL
+#define METAL_MINTSTATUS_SIL 0x0000FF00UL
+#define METAL_MINTSTATUS_UIL 0x000000FFUL
+
+#define METAL_LOCAL_INTR(X) (16 + X)
+#define METAL_MCAUSE_EVAL(cause) (cause & METAL_MCAUSE_INTR)
+#define METAL_INTERRUPT(cause) (METAL_MCAUSE_EVAL(cause) ? 1 : 0)
+#define METAL_EXCEPTION(cause) (METAL_MCAUSE_EVAL(cause) ? 0 : 1)
+#define METAL_SW_INTR_EXCEPTION (METAL_MCAUSE_INTR + 3)
+#define METAL_TMR_INTR_EXCEPTION (METAL_MCAUSE_INTR + 7)
+#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_RESERVE0 1
+#define METAL_LOCAL_INTR_RESERVE1 2
+#define METAL_LOCAL_INTR_RESERVE2 4
+#define METAL_LOCAL_INTERRUPT_SW 8 /* Bit3 0x008 */
+#define METAL_LOCAL_INTR_RESERVE4 16
+#define METAL_LOCAL_INTR_RESERVE5 32
+#define METAL_LOCAL_INTR_RESERVE6 64
+#define METAL_LOCAL_INTERRUPT_TMR 128 /* Bit7 0x080 */
+#define METAL_LOCAL_INTR_RESERVE8 256
+#define METAL_LOCAL_INTR_RESERVE9 512
+#define METAL_LOCAL_INTR_RESERVE10 1024
+#define METAL_LOCAL_INTERRUPT_EXT 2048 /* Bit11 0x800 */
+/* Bit12 to Bit15 are Reserved */
+#define METAL_LOCAL_INTERRUPT(X) (0x10000 << X) /* Bit16+ Start of Custom Local Interrupt */
+#define METAL_MIE_INTERRUPT METAL_MSTATUS_MIE
+
+typedef enum {
+ METAL_MACHINE_PRIVILEGE_MODE,
+ METAL_SUPERVISOR_PRIVILEGE_MODE,
+ METAL_USER_PRIVILEGE_MODE,
+} metal_privilege_mode_e;
+
+typedef enum {
+ METAL_INTERRUPT_ID_BASE,
+ METAL_INTERRUPT_ID_SW = (METAL_INTERRUPT_ID_BASE + 3),
+ METAL_INTERRUPT_ID_TMR = (METAL_INTERRUPT_ID_BASE + 7),
+ METAL_INTERRUPT_ID_EXT = (METAL_INTERRUPT_ID_BASE + 11),
+ METAL_INTERRUPT_ID_LC0 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(0)),
+ METAL_INTERRUPT_ID_LC1 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(1)),
+ METAL_INTERRUPT_ID_LC2 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(2)),
+ METAL_INTERRUPT_ID_LC3 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(3)),
+ METAL_INTERRUPT_ID_LC4 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(4)),
+ METAL_INTERRUPT_ID_LC5 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(5)),
+ METAL_INTERRUPT_ID_LC6 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(6)),
+ METAL_INTERRUPT_ID_LC7 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(7)),
+ METAL_INTERRUPT_ID_LC8 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(8)),
+ METAL_INTERRUPT_ID_LC9 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(9)),
+ METAL_INTERRUPT_ID_LC10 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(10)),
+ METAL_INTERRUPT_ID_LC11 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(11)),
+ METAL_INTERRUPT_ID_LC12 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(12)),
+ METAL_INTERRUPT_ID_LC13 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(13)),
+ METAL_INTERRUPT_ID_LC14 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(14)),
+ METAL_INTERRUPT_ID_LC15 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(15)),
+ METAL_INTERRUPT_ID_LCMX,
+ METAL_INTERRUPT_ID_GL0 = METAL_INTERRUPT_ID_LCMX,
+ METAL_INTERRUPT_ID_GLMX = (METAL_MCAUSE_CAUSE + 1),
+} metal_interrupt_id_e;
+
+typedef enum {
+ METAL_IAM_EXCEPTION_CODE, /* Instruction address misaligned */
+ METAL_IAF_EXCEPTION_CODE, /* Instruction access faultd */
+ METAL_II_EXCEPTION_CODE, /* Illegal instruction */
+ METAL_BREAK_EXCEPTION_CODE, /* Breakpoint */
+ METAL_LAM_EXCEPTION_CODE, /* Load address misaligned */
+ METAL_LAF_EXCEPTION_CODE, /* Load access fault */
+ METAL_SAMOAM_EXCEPTION_CODE, /* Store/AMO address misaligned */
+ METAL_SAMOAF_EXCEPTION_CODE, /* Store/AMO access fault */
+ METAL_ECALL_U_EXCEPTION_CODE, /* Environment call from U-mode */
+ METAL_R9_EXCEPTION_CODE, /* Reserved */
+ METAL_R10_EXCEPTION_CODE, /* Reserved */
+ METAL_ECALL_M_EXCEPTION_CODE, /* Environment call from M-mode */
+ METAL_MAX_EXCEPTION_CODE,
+} metal_exception_code_e;
+
+typedef enum {
+ METAL_TIMER_MTIME_GET = 1,
+ METAL_SOFTWARE_IPI_CLEAR,
+ METAL_SOFTWARE_IPI_SET,
+ METAL_SOFTWARE_MSIP_GET,
+ METAL_MAX_INTERRUPT_GET,
+ METAL_INDEX_INTERRUPT_GET,
+} metal_interrup_cmd_e;
+
+typedef struct __metal_interrupt_data {
+ long long pad : 64;
+ metal_interrupt_handler_t handler;
+ void *sub_int;
+ void *exint_data;
+} __metal_interrupt_data;
+
+/* CPU interrupt controller */
+
+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_interrupt_vtable controller_vtable;
+};
+
+
+void __metal_interrupt_global_enable(void);
+void __metal_interrupt_global_disable(void);
+void __metal_controller_interrupt_vector(metal_vector_mode mode, void *vec_table);
+inline int __metal_controller_interrupt_is_selective_vectored (void)
+{
+ 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)
+
+struct __metal_driver_riscv_cpu_intc {
+ struct metal_interrupt controller;
+ int init_done;
+ uintptr_t metal_mtvec_table[METAL_MAX_MI];
+ __metal_interrupt_data metal_int_table[METAL_MAX_MI];
+ metal_exception_handler_t metal_exception_table[METAL_MAX_ME];
+};
+
+/* CPU driver*/
+struct __metal_driver_vtable_cpu {
+ struct metal_cpu_vtable cpu_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_cpu)
+
+struct __metal_driver_cpu {
+ struct metal_cpu cpu;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__RISCV_PLIC0_H
+#define METAL__DRIVERS__RISCV_PLIC0_H
+
+#include <metal/compiler.h>
+#include <metal/drivers/riscv_cpu.h>
+
+#define METAL_PLIC_SOURCE_MASK 0x1F
+#define METAL_PLIC_SOURCE_SHIFT 5
+#define METAL_PLIC_SOURCE_PRIORITY_SHIFT 2
+#define METAL_PLIC_SOURCE_PENDING_SHIFT 0
+
+struct __metal_driver_vtable_riscv_plic0 {
+ struct metal_interrupt_vtable plic_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_plic0)
+
+#define __METAL_MACHINE_MACROS
+#include <metal/machine.h>
+struct __metal_driver_riscv_plic0 {
+ struct metal_interrupt controller;
+ int init_done;
+ metal_interrupt_handler_t metal_exint_table[__METAL_PLIC_SUBINTERRUPTS];
+ __metal_interrupt_data metal_exdata_table[__METAL_PLIC_SUBINTERRUPTS];
+};
+#undef __METAL_MACHINE_MACROS
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_CLIC0_H
+#define METAL__DRIVERS__SIFIVE_CLIC0_H
+
+#include <metal/compiler.h>
+#include <metal/drivers/riscv_cpu.h>
+
+#define METAL_CLIC_MAX_NMBITS 2
+#define METAL_CLIC_MAX_NLBITS 8
+#define METAL_CLIC_MAX_NVBITS 1
+
+#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MMODE 0x00
+#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE1 0x20
+#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE2 0x40
+#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MASK 0x60
+#define METAL_SIFIVE_CLIC0_CLICCFG_NLBITS_MASK 0x1E
+#define METAL_SIFIVE_CLIC0_CLICCFG_NVBIT_MASK 0x01
+
+#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_MAX_INTERRUPT_LEVEL ((1 << METAL_CLIC_MAX_NLBITS) - 1)
+
+struct __metal_driver_vtable_sifive_clic0 {
+ struct metal_interrupt_vtable clic_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_clic0)
+
+#define __METAL_MACHINE_MACROS
+#include <metal/machine.h>
+struct __metal_driver_sifive_clic0 {
+ struct metal_interrupt controller;
+ int init_done;
+ metal_interrupt_handler_t metal_mtvt_table[__METAL_CLIC_SUBINTERRUPTS];
+ __metal_interrupt_data metal_exint_table[__METAL_CLIC_SUBINTERRUPTS];
+};
+#undef __METAL_MACHINE_MACROS
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef 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/io.h>
+
+struct __metal_driver_vtable_sifive_fe310_g000_hfrosc {
+ struct __metal_clock_vtable clock;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfrosc)
+
+struct __metal_driver_sifive_fe310_g000_hfrosc {
+ struct metal_clock clock;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_HFXOSC_H
+#define METAL__DRIVERS__SIFIVE_FE310_G000_HFXOSC_H
+
+#include <metal/clock.h>
+#include <metal/drivers/sifive_fe310-g000_prci.h>
+
+struct __metal_driver_vtable_sifive_fe310_g000_hfxosc {
+ struct __metal_clock_vtable clock;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfxosc)
+
+struct __metal_driver_sifive_fe310_g000_hfxosc {
+ struct metal_clock clock;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_PLL_H
+#define METAL__DRIVERS__SIFIVE_FE310_G000_PLL_H
+
+struct __metal_driver_sifive_fe310_g000_pll;
+
+#include <metal/clock.h>
+#include <metal/drivers/sifive_fe310-g000_prci.h>
+#include <metal/machine.h>
+
+struct __metal_driver_vtable_sifive_fe310_g000_pll {
+ void (*init)(struct __metal_driver_sifive_fe310_g000_pll *pll);
+ struct __metal_clock_vtable clock;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_pll)
+
+struct __metal_driver_sifive_fe310_g000_pll {
+ struct metal_clock clock;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_PRCI_H
+#define METAL__DRIVERS__SIFIVE_FE310_G000_PRCI_H
+
+#include <metal/compiler.h>
+#include <metal/io.h>
+
+struct __metal_driver_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 (*set_reg)(const struct __metal_driver_sifive_fe310_g000_prci *, long offset, long value);
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci)
+
+struct __metal_driver_sifive_fe310_g000_prci {
+};
+
+#endif
+
--- /dev/null
+/* 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
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0_H
+#define METAL__DRIVERS__SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0_H
+
+#include <metal/compiler.h>
+#include <metal/drivers/riscv_cpu.h>
+
+struct __metal_driver_vtable_sifive_global_external_interrupts0 {
+ struct metal_interrupt_vtable global0_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_global_external_interrupts0)
+
+struct __metal_driver_sifive_global_external_interrupts0 {
+ struct metal_interrupt irc;
+ int init_done;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H
+#define METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H
+
+#include <string.h>
+#include <metal/button.h>
+#include <metal/compiler.h>
+
+struct __metal_driver_vtable_sifive_button {
+ struct metal_button_vtable button_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_button)
+
+struct __metal_driver_sifive_gpio_button {
+ struct metal_button button;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_GPIO_LEDS_H
+#define METAL__DRIVERS__SIFIVE_GPIO_LEDS_H
+
+#include <metal/drivers/sifive_gpio0.h>
+#include <metal/led.h>
+#include <metal/compiler.h>
+
+struct __metal_driver_vtable_sifive_led {
+ struct metal_led_vtable led_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_led)
+
+struct __metal_driver_sifive_gpio_led {
+ struct metal_led led;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H
+#define METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H
+
+#include <metal/drivers/sifive_gpio0.h>
+#include <metal/switch.h>
+#include <metal/compiler.h>
+
+struct __metal_driver_vtable_sifive_switch {
+ struct metal_switch_vtable switch_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_switch)
+
+struct __metal_driver_sifive_gpio_switch {
+ struct metal_switch flip;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_GPIO0_H
+#define METAL__DRIVERS__SIFIVE_GPIO0_H
+
+#include <metal/compiler.h>
+#include <metal/gpio.h>
+
+struct __metal_driver_vtable_sifive_gpio0 {
+ const struct __metal_gpio_vtable gpio;
+};
+
+//struct __metal_driver_sifive_gpio0;
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_gpio0)
+
+struct __metal_driver_sifive_gpio0 {
+ struct metal_gpio gpio;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_EXTERNAL_INTERRUPTS0_H
+#define METAL__DRIVERS__SIFIVE_EXTERNAL_INTERRUPTS0_H
+
+#include <metal/compiler.h>
+#include <metal/drivers/riscv_cpu.h>
+
+struct __metal_driver_vtable_sifive_local_external_interrupts0 {
+ struct metal_interrupt_vtable local0_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_local_external_interrupts0)
+
+struct __metal_driver_sifive_local_external_interrupts0 {
+ struct metal_interrupt irc;
+ int init_done;
+};
+
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_SPI0_H
+#define METAL__DRIVERS__SIFIVE_SPI0_H
+
+#include <metal/drivers/sifive_gpio0.h>
+#include <metal/clock.h>
+#include <metal/compiler.h>
+#include <metal/io.h>
+#include <metal/spi.h>
+
+struct __metal_driver_vtable_sifive_spi0 {
+ const struct metal_spi_vtable spi;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_spi0)
+
+struct __metal_driver_sifive_spi0 {
+ struct metal_spi spi;
+ unsigned long baud_rate;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_TEST0_H
+#define METAL__DRIVERS__SIFIVE_TEST0_H
+
+#include <metal/compiler.h>
+#include <metal/shutdown.h>
+
+struct __metal_driver_vtable_sifive_test0 {
+ const struct __metal_shutdown_vtable shutdown;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_test0)
+
+struct __metal_driver_sifive_test0 {
+ struct __metal_shutdown shutdown;
+};
+
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef 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/io.h>
+#include <metal/uart.h>
+#include <metal/compiler.h>
+
+struct __metal_driver_vtable_sifive_uart0 {
+ const struct metal_uart_vtable uart;
+};
+
+struct __metal_driver_sifive_uart0;
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_uart0)
+
+struct __metal_driver_sifive_uart0 {
+ struct metal_uart uart;
+ unsigned long baud_rate;
+};
+
+
+#endif
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__GPIO_H
+#define METAL__GPIO_H
+
+#include <metal/compiler.h>
+
+/*!
+ * @file gpio.h
+ * @brief API for manipulating general-purpose input/output
+ */
+
+struct metal_gpio;
+
+struct __metal_gpio_vtable {
+ int (*disable_input)(struct metal_gpio *, long pins);
+ long (*output)(struct metal_gpio *);
+ int (*enable_output)(struct metal_gpio *, long pins);
+ int (*output_set)(struct metal_gpio *, long value);
+ int (*output_clear)(struct metal_gpio *, long value);
+ int (*output_toggle)(struct metal_gpio *, long value);
+ int (*enable_io)(struct metal_gpio *, long pins, long dest);
+};
+
+/*!
+ * @struct metal_gpio
+ * @brief The handle for a GPIO interface
+ */
+struct metal_gpio {
+ const struct __metal_gpio_vtable *vtable;
+};
+
+/*!
+ * @brief Get a GPIO device handle
+ * @param device_num The GPIO device 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);
+
+/*!
+ * @brief Disable 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 disabled
+ */
+inline int metal_gpio_disable_input(struct metal_gpio *gpio, int pin) {
+ if(!gpio) {
+ return 1;
+ }
+
+ return gpio->vtable->disable_input(gpio, (1 << pin));
+}
+
+/*!
+ * @brief Enable 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 enabled
+ */
+inline int metal_gpio_enable_output(struct metal_gpio *gpio, int pin) {
+ if(!gpio) {
+ return 1;
+ }
+
+ return gpio->vtable->enable_output(gpio, (1 << pin));
+}
+
+/*!
+ * @brief Set the output value of a GPIO pin
+ * @param gpio The handle for the GPIO interface
+ * @param pin The pin number indexed from 0
+ * @param value The value to set the pin to
+ * @return 0 if the output is successfully set
+ */
+inline int metal_gpio_set_pin(struct metal_gpio *gpio, int pin, int value) {
+ if(!gpio) {
+ return 1;
+ }
+
+ if(value == 0) {
+ return gpio->vtable->output_clear(gpio, (1 << pin));
+ } else {
+ return gpio->vtable->output_set(gpio, (1 << pin));
+ }
+}
+
+/*!
+ * @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_pin(struct metal_gpio *gpio, int pin) {
+ if(!gpio) {
+ return 0;
+ }
+
+ long value = gpio->vtable->output(gpio);
+
+ if(value & (1 << pin)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ * @brief Clears the value of the GPIO pin
+ * @param gpio The handle for the GPIO interface
+ * @param pin The pin number indexed from 0
+ * @return 0 if the pin is successfully cleared
+ */
+inline int metal_gpio_clear_pin(struct metal_gpio *gpio, int pin) {
+ if(!gpio) {
+ return 1;
+ }
+
+ return gpio->vtable->output_clear(gpio, (1 << pin));
+}
+
+/*!
+ * @brief Toggles the value of the GPIO pin
+ * @param gpio The handle for the GPIO interface
+ * @param pin The pin number indexed from 0
+ * @return 0 if the pin is successfully toggled
+ */
+inline int metal_gpio_toggle_pin(struct metal_gpio *gpio, int pin) {
+ if(!gpio) {
+ return 1;
+ }
+
+ return gpio->vtable->output_toggle(gpio, (1 << pin));
+}
+
+/*!
+ * @brief Enables and sets the pinmux for a GPIO pin
+ * @param gpio The handle for the GPIO interface
+ * @param pin The bitmask for the pin to enable pinmux on
+ * @param io_function The IO function to set
+ * @return 0 if the pinmux is successfully set
+ */
+inline int metal_gpio_enable_pinmux(struct metal_gpio *gpio, int pin, int io_function) {
+ if(!gpio) {
+ return 1;
+ }
+
+ return gpio->vtable->enable_io(gpio, (1 << pin), (io_function << pin));
+}
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__INTERRUPT_H
+#define METAL__INTERRUPT_H
+
+/*! @file interrupt.h
+ * @brief API for registering and manipulating interrupts
+ */
+
+#include <stddef.h>
+
+/*!
+ * @brief Possible mode of interrupts to operate
+ */
+typedef enum metal_vector_mode_ {
+ METAL_DIRECT_MODE = 0,
+ METAL_VECTOR_MODE = 1,
+ METAL_SELECTIVE_VECTOR_MODE = 2,
+ METAL_HARDWARE_VECTOR_MODE = 3
+} metal_vector_mode;
+
+/*!
+ * @brief Function signature for interrupt callback handlers
+ */
+typedef void (*metal_interrupt_handler_t) (int, void *);
+
+struct metal_interrupt;
+
+struct metal_interrupt_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 (*interrupt_vector_enable)(struct metal_interrupt *controller,
+ int id, metal_vector_mode mode);
+ int (*interrupt_vector_disable)(struct metal_interrupt *controller, int id);
+ int (*command_request)(struct metal_interrupt *controller, int cmd, void *data);
+ int (*mtimecmp_set)(struct metal_interrupt *controller, int hartid, unsigned long long time);
+};
+
+/*!
+ * @brief A handle for an interrupt
+ */
+struct metal_interrupt {
+ const struct metal_interrupt_vtable *vtable;
+};
+
+/*!
+ * @brief Initialize a given interrupt controller
+ *
+ * Initialize a given interrupt controller. This function must be called
+ * before any interrupts are registered or enabled with the handler. It
+ * is invalid to initialize an interrupt controller more than once.
+ *
+ * @param controller The handle for the interrupt controller
+ */
+inline void metal_interrupt_init(struct metal_interrupt *controller)
+{
+ return controller->vtable->interrupt_init(controller);
+}
+
+
+/*!
+ * @brief Register an interrupt handler
+ * @param controller The handle for the interrupt controller
+ * @param id The interrupt ID to register
+ * @param handler The interrupt handler callback
+ * @param priv_data Private data for the interrupt handler
+ * @return 0 upon success
+ */
+inline int metal_interrupt_register_handler(struct metal_interrupt *controller,
+ int id,
+ metal_interrupt_handler_t handler,
+ void *priv_data)
+{
+ return controller->vtable->interrupt_register(controller, id, handler, priv_data);
+}
+
+/*!
+ * @brief Enable an interrupt
+ * @param controller The handle for the interrupt controller
+ * @param id The interrupt ID to enable
+ * @return 0 upon success
+ */
+inline int metal_interrupt_enable(struct metal_interrupt *controller, int id)
+{
+ return controller->vtable->interrupt_enable(controller, id);
+}
+
+/*!
+ * @brief Disable an interrupt
+ * @param controller The handle for the interrupt controller
+ * @param id The interrupt ID to disable
+ * @return 0 upon success
+ */
+inline int metal_interrupt_disable(struct metal_interrupt *controller, int id)
+{
+ return controller->vtable->interrupt_disable(controller, id);
+}
+
+/*!
+ * @brief Enable an interrupt vector
+ * @param controller The handle for the interrupt controller
+ * @param id The interrupt ID to enable
+ * @param mode The interrupt mode type to enable
+ * @return 0 upon success
+ */
+inline int metal_interrupt_vector_enable(struct metal_interrupt *controller,
+ int id, metal_vector_mode mode)
+{
+ return controller->vtable->interrupt_vector_enable(controller, id, mode);
+}
+
+/*!
+ * @brief Disable an interrupt vector
+ * @param controller The handle for the interrupt controller
+ * @param id The interrupt ID to disable
+ * @return 0 upon success
+ */
+inline int metal_interrupt_vector_disable(struct metal_interrupt *controller, int 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,
+ int cmd, void *data)
+{
+ return controller->vtable->command_request(controller, cmd, data);
+}
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__IO_H
+#define METAL__IO_H
+
+/* This macro enforces that the compiler will not elide the given access. */
+#define __METAL_ACCESS_ONCE(x) (*(typeof(*x) volatile *)(x))
+
+/* Allows users to specify arbitrary fences. */
+#define __METAL_IO_FENCE(pred, succ) __asm__ volatile ("fence " #pred "," #succ ::: "memory");
+
+/* Types that explicitly describe an address as being used for memory-mapped
+ * IO. These should only be accessed via __METAL_ACCESS_ONCE. */
+typedef unsigned char __metal_io_u8;
+typedef unsigned short __metal_io_u16;
+typedef unsigned int __metal_io_u32;
+#if __riscv_xlen >= 64
+typedef unsigned long __metal_io_u64;
+#endif
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__ITIM_H
+#define METAL__ITIM_H
+
+/*! @file itim.h
+ *
+ * API for manipulating ITIM allocation
+ */
+
+
+/*! @def METAL_PLACE_IN_ITIM
+ * @brief Link a function into the ITIM
+ *
+ * Link a function into the ITIM (Instruction Tightly Integrated
+ * Memory) if the ITIM is present on the target device.
+ */
+#define METAL_PLACE_IN_ITIM __attribute__((section(".itim")))
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__LED_H
+#define METAL__LED_H
+
+/*!
+ * @file led.h
+ * @brief API for manipulating LEDs
+ */
+
+struct metal_led;
+
+struct metal_led_vtable {
+ int (*led_exist)(struct metal_led *led, char *label);
+ void (*led_enable)(struct metal_led *led);
+ void (*led_on)(struct metal_led *led);
+ void (*led_off)(struct metal_led *led);
+ void (*led_toggle)(struct metal_led *led);
+};
+
+/*!
+ * @brief A handle for an LED
+ */
+struct metal_led {
+ const struct metal_led_vtable *vtable;
+};
+
+/*!
+ * @brief Get a handle for an 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
+ */
+struct metal_led* metal_led_get(char *label);
+
+/*!
+ * @brief Get a handle for a channel of an RGB LED
+ * @param label The DeviceTree label for the desired LED
+ * @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
+ */
+struct metal_led* metal_led_get_rgb(char *label, char *color);
+
+/*!
+ * @brief Enable an LED
+ * @param led The handle for the LED
+ */
+inline void metal_led_enable(struct metal_led *led) { led->vtable->led_enable(led); }
+
+/*!
+ * @brief Turn an LED on
+ * @param led The handle for the LED
+ */
+inline void metal_led_on(struct metal_led *led) { led->vtable->led_on(led); }
+
+/*!
+ * @brief Turn an LED off
+ * @param led The handle for the LED
+ */
+inline void metal_led_off(struct metal_led *led) { led->vtable->led_off(led); }
+
+/*!
+ * @brief Toggle the on/off state of an LED
+ * @param led The handle for the LED
+ */
+inline void metal_led_toggle(struct metal_led *led) { led->vtable->led_toggle(led); }
+
+#endif
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__LOCK_H
+#define METAL__LOCK_H
+
+#include <metal/memory.h>
+#include <metal/compiler.h>
+
+/*!
+ * @file lock.h
+ * @brief An API for creating and using a software lock/mutex
+ */
+
+/* TODO: How can we make the exception code platform-independant? */
+#define _METAL_STORE_AMO_ACCESS_FAULT 7
+
+/*!
+ * @def METAL_LOCK_DECLARE
+ * @brief Declare a 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.
+ */
+#define METAL_LOCK_DECLARE(name) \
+ __attribute__((section(".data.locks"))) \
+ struct metal_lock name
+
+/*!
+ * @brief A handle for a lock
+ */
+struct metal_lock {
+ int _state;
+};
+
+/*!
+ * @brief Initialize a lock
+ * @param lock The handle for a lock
+ * @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
+ * will result in a Store/AMO access fault.
+ */
+inline int metal_lock_init(struct metal_lock *lock) {
+#ifdef __riscv_atomic
+ /* 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));
+ if(!lock_mem) {
+ return 1;
+ }
+
+ /* If the memory doesn't support atomics, report an error */
+ if(!metal_memory_supports_atomics(lock_mem)) {
+ return 2;
+ }
+
+ lock->_state = 0;
+
+ return 0;
+#else
+ return 3;
+#endif
+}
+
+/*!
+ * @brief Take a lock
+ * @param lock The handle for a lock
+ * @return 0 if the lock is successfully taken
+ *
+ * If the lock initialization failed, attempts to take a lock will result in
+ * a Store/AMO access fault.
+ */
+inline int metal_lock_take(struct metal_lock *lock) {
+#ifdef __riscv_atomic
+ int old = 1;
+ int new = 1;
+
+ while(old != 0) {
+ __asm__ volatile("amoswap.w.aq %[old], %[new], (%[state])"
+ : [old] "=r" (old)
+ : [new] "r" (new), [state] "r" (&(lock->_state))
+ : "memory");
+ }
+
+ return 0;
+#else
+ /* Store the memory address in mtval like a normal store/amo access fault */
+ __asm__ ("csrw mtval, %[state]"
+ :: [state] "r" (&(lock->_state)));
+
+ /* Trigger a Store/AMO access fault */
+ _metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);
+
+ /* If execution returns, indicate failure */
+ return 1;
+#endif
+}
+
+/*!
+ * @brief Give back a held lock
+ * @param lock The handle for a lock
+ * @return 0 if the lock is successfully given
+ *
+ * If the lock initialization failed, attempts to give a lock will result in
+ * a Store/AMO access fault.
+ */
+inline int metal_lock_give(struct metal_lock *lock) {
+#ifdef __riscv_atomic
+ __asm__ volatile("amoswap.w.rl x0, x0, (%[state])"
+ :: [state] "r" (&(lock->_state))
+ : "memory");
+
+ return 0;
+#else
+ /* Store the memory address in mtval like a normal store/amo access fault */
+ __asm__ ("csrw mtval, %[state]"
+ :: [state] "r" (&(lock->_state)));
+
+ /* Trigger a Store/AMO access fault */
+ _metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);
+
+ /* If execution returns, indicate failure */
+ return 1;
+#endif
+}
+
+#endif /* METAL__LOCK_H */
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+/* ----------------------------------- */
+/* ----------------------------------- */
+
+#ifndef ASSEMBLY
+
+#include <metal/machine/platform.h>
+
+#ifdef __METAL_MACHINE_MACROS
+
+#ifndef MACROS_IF_SIFIVE_HIFIVE1_REVB____METAL_H
+#define MACROS_IF_SIFIVE_HIFIVE1_REVB____METAL_H
+
+#define __METAL_CLINT_NUM_PARENTS 2
+
+#ifndef __METAL_CLINT_NUM_PARENTS
+#define __METAL_CLINT_NUM_PARENTS 0
+#endif
+#define __METAL_PLIC_SUBINTERRUPTS 27
+
+#define __METAL_PLIC_NUM_PARENTS 1
+
+#ifndef __METAL_PLIC_SUBINTERRUPTS
+#define __METAL_PLIC_SUBINTERRUPTS 0
+#endif
+#ifndef __METAL_PLIC_NUM_PARENTS
+#define __METAL_PLIC_NUM_PARENTS 0
+#endif
+#ifndef __METAL_CLIC_SUBINTERRUPTS
+#define __METAL_CLIC_SUBINTERRUPTS 0
+#endif
+
+#endif /* MACROS_IF_SIFIVE_HIFIVE1_REVB____METAL_H*/
+
+#else /* ! __METAL_MACHINE_MACROS */
+
+#ifndef MACROS_ELSE_SIFIVE_HIFIVE1_REVB____METAL_H
+#define MACROS_ELSE_SIFIVE_HIFIVE1_REVB____METAL_H
+
+#define __METAL_CLINT_2000000_INTERRUPTS 2
+
+#define METAL_MAX_CLINT_INTERRUPTS 2
+
+#define __METAL_CLINT_NUM_PARENTS 2
+
+#define __METAL_INTERRUPT_CONTROLLER_C000000_INTERRUPTS 1
+
+#define __METAL_PLIC_SUBINTERRUPTS 27
+
+#define METAL_MAX_PLIC_INTERRUPTS 1
+
+#define __METAL_PLIC_NUM_PARENTS 1
+
+#define __METAL_CLIC_SUBINTERRUPTS 0
+#define METAL_MAX_CLIC_INTERRUPTS 0
+
+#define __METAL_LOCAL_EXTERNAL_INTERRUPTS_0_INTERRUPTS 16
+
+#define METAL_MAX_LOCAL_EXT_INTERRUPTS 16
+
+#define METAL_MAX_GLOBAL_EXT_INTERRUPTS 0
+
+#define __METAL_GPIO_10012000_INTERRUPTS 16
+
+#define METAL_MAX_GPIO_INTERRUPTS 16
+
+#define __METAL_SERIAL_10013000_INTERRUPTS 1
+
+#define METAL_MAX_UART_INTERRUPTS 1
+
+
+#include <metal/drivers/fixed-clock.h>
+#include <metal/memory.h>
+#include <metal/drivers/riscv_clint0.h>
+#include <metal/drivers/riscv_cpu.h>
+#include <metal/drivers/riscv_plic0.h>
+#include <metal/pmp.h>
+#include <metal/drivers/sifive_local-external-interrupts0.h>
+#include <metal/drivers/sifive_gpio0.h>
+#include <metal/drivers/sifive_gpio-leds.h>
+#include <metal/drivers/sifive_spi0.h>
+#include <metal/drivers/sifive_uart0.h>
+#include <metal/drivers/sifive_fe310-g000_hfrosc.h>
+#include <metal/drivers/sifive_fe310-g000_hfxosc.h>
+#include <metal/drivers/sifive_fe310-g000_pll.h>
+#include <metal/drivers/sifive_fe310-g000_prci.h>
+
+/* From clock@0 */
+struct __metal_driver_fixed_clock __metal_dt_clock_0;
+
+/* From clock@2 */
+struct __metal_driver_fixed_clock __metal_dt_clock_2;
+
+/* From clock@5 */
+struct __metal_driver_fixed_clock __metal_dt_clock_5;
+
+struct metal_memory __metal_dt_mem_dtim_80000000;
+
+struct metal_memory __metal_dt_mem_spi_10014000;
+
+/* From clint@2000000 */
+struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000;
+
+/* From cpu@0 */
+struct __metal_driver_cpu __metal_dt_cpu_0;
+
+struct __metal_driver_riscv_cpu_intc __metal_dt_cpu_0_interrupt_controller;
+
+/* From interrupt_controller@c000000 */
+struct __metal_driver_riscv_plic0 __metal_dt_interrupt_controller_c000000;
+
+struct metal_pmp __metal_dt_pmp;
+
+/* From local_external_interrupts_0 */
+struct __metal_driver_sifive_local_external_interrupts0 __metal_dt_local_external_interrupts_0;
+
+/* From gpio@10012000 */
+struct __metal_driver_sifive_gpio0 __metal_dt_gpio_10012000;
+
+/* From led@0red */
+struct __metal_driver_sifive_gpio_led __metal_dt_led_0red;
+
+/* From led@0green */
+struct __metal_driver_sifive_gpio_led __metal_dt_led_0green;
+
+/* From led@0blue */
+struct __metal_driver_sifive_gpio_led __metal_dt_led_0blue;
+
+/* From spi@10014000 */
+struct __metal_driver_sifive_spi0 __metal_dt_spi_10014000;
+
+/* From serial@10013000 */
+struct __metal_driver_sifive_uart0 __metal_dt_serial_10013000;
+
+/* From clock@3 */
+struct __metal_driver_sifive_fe310_g000_hfrosc __metal_dt_clock_3;
+
+/* From clock@1 */
+struct __metal_driver_sifive_fe310_g000_hfxosc __metal_dt_clock_1;
+
+/* From clock@4 */
+struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4;
+
+/* From prci@10008000 */
+struct __metal_driver_sifive_fe310_g000_prci __metal_dt_prci_10008000;
+
+
+
+/* --------------------- fixed_clock ------------ */
+static inline unsigned long __metal_driver_fixed_clock_rate(const struct metal_clock *clock)
+{
+ if ((uintptr_t)clock == (uintptr_t)&__metal_dt_clock_0) {
+ return METAL_FIXED_CLOCK_0_CLOCK_FREQUENCY;
+ }
+ else if ((uintptr_t)clock == (uintptr_t)&__metal_dt_clock_2) {
+ return METAL_FIXED_CLOCK_2_CLOCK_FREQUENCY;
+ }
+ else if ((uintptr_t)clock == (uintptr_t)&__metal_dt_clock_5) {
+ return METAL_FIXED_CLOCK_5_CLOCK_FREQUENCY;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+
+/* --------------------- fixed_factor_clock ------------ */
+
+
+/* --------------------- sifive_clint0 ------------ */
+static inline unsigned long __metal_driver_sifive_clint0_control_base(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_clint_2000000) {
+ return METAL_RISCV_CLINT0_2000000_BASE_ADDRESS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline unsigned long __metal_driver_sifive_clint0_control_size(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_clint_2000000) {
+ return METAL_RISCV_CLINT0_2000000_SIZE;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_clint0_num_interrupts(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_clint_2000000) {
+ return METAL_MAX_CLINT_INTERRUPTS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline struct metal_interrupt * __metal_driver_sifive_clint0_interrupt_parents(struct metal_interrupt *controller, int idx)
+{
+ if (idx == 0) {
+ return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
+ }
+ else if (idx == 1) {
+ return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static inline int __metal_driver_sifive_clint0_interrupt_lines(struct metal_interrupt *controller, int idx)
+{
+ if (idx == 0) {
+ return 3;
+ }
+ else if (idx == 1) {
+ return 7;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+
+/* --------------------- cpu ------------ */
+static inline int __metal_driver_cpu_hartid(struct metal_cpu *cpu)
+{
+ if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
+ return 0;
+ }
+ else {
+ return -1;
+ }
+}
+
+static inline int __metal_driver_cpu_timebase(struct metal_cpu *cpu)
+{
+ if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
+ return 1000000;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline struct metal_interrupt * __metal_driver_cpu_interrupt_controller(struct metal_cpu *cpu)
+{
+ if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
+ return &__metal_dt_cpu_0_interrupt_controller.controller;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static inline int __metal_driver_cpu_num_pmp_regions(struct metal_cpu *cpu)
+{
+ if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
+ return 8;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+
+/* --------------------- sifive_plic0 ------------ */
+static inline unsigned long __metal_driver_sifive_plic0_control_base(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
+ return METAL_RISCV_PLIC0_C000000_BASE_ADDRESS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline unsigned long __metal_driver_sifive_plic0_control_size(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
+ return METAL_RISCV_PLIC0_C000000_SIZE;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_plic0_num_interrupts(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
+ return METAL_RISCV_PLIC0_C000000_RISCV_NDEV;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_plic0_max_priority(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
+ return METAL_RISCV_PLIC0_C000000_RISCV_MAX_PRIORITY;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline struct metal_interrupt * __metal_driver_sifive_plic0_interrupt_parents(struct metal_interrupt *controller, int idx)
+{
+ if (idx == 0) {
+ return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
+ }
+ else if (idx == 0) {
+ return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static inline int __metal_driver_sifive_plic0_interrupt_lines(struct metal_interrupt *controller, int idx)
+{
+ if (idx == 0) {
+ return 11;
+ }
+ else if (idx == 0) {
+ return 11;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+
+/* --------------------- sifive_clic0 ------------ */
+
+
+/* --------------------- sifive_local_external_interrupts0 ------------ */
+static inline struct metal_interrupt * __metal_driver_sifive_local_external_interrupts0_interrupt_parent(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_local_external_interrupts_0) {
+ return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static inline int __metal_driver_sifive_local_external_interrupts0_num_interrupts(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_local_external_interrupts_0) {
+ return METAL_MAX_LOCAL_EXT_INTERRUPTS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_local_external_interrupts0_interrupt_lines(struct metal_interrupt *controller, int idx)
+{
+ if (idx == 0) {
+ return 16;
+ }
+ else if (idx == 1) {
+ return 17;
+ }
+ else if (idx == 2) {
+ return 18;
+ }
+ else if (idx == 3) {
+ return 19;
+ }
+ else if (idx == 4) {
+ return 20;
+ }
+ else if (idx == 5) {
+ return 21;
+ }
+ else if (idx == 6) {
+ return 22;
+ }
+ else if (idx == 7) {
+ return 23;
+ }
+ else if (idx == 8) {
+ return 24;
+ }
+ else if (idx == 9) {
+ return 25;
+ }
+ else if (idx == 10) {
+ return 26;
+ }
+ else if (idx == 11) {
+ return 27;
+ }
+ else if (idx == 12) {
+ return 28;
+ }
+ else if (idx == 13) {
+ return 29;
+ }
+ else if (idx == 14) {
+ return 30;
+ }
+ else if (idx == 15) {
+ return 31;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+
+/* --------------------- sifive_global_external_interrupts0 ------------ */
+
+
+/* --------------------- sifive_gpio0 ------------ */
+static inline unsigned long __metal_driver_sifive_gpio0_base(struct metal_gpio *gpio)
+{
+ if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
+ return METAL_SIFIVE_GPIO0_10012000_BASE_ADDRESS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline unsigned long __metal_driver_sifive_gpio0_size(struct metal_gpio *gpio)
+{
+ if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
+ return METAL_SIFIVE_GPIO0_10012000_SIZE;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_gpio0_num_interrupts(struct metal_gpio *gpio)
+{
+ if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
+ return METAL_MAX_GPIO_INTERRUPTS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline struct metal_interrupt * __metal_driver_sifive_gpio0_interrupt_parent(struct metal_gpio *gpio)
+{
+ if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
+ return (struct metal_interrupt *)&__metal_dt_interrupt_controller_c000000.controller;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_gpio0_interrupt_lines(struct metal_gpio *gpio, int idx)
+{
+ if (((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 0)) {
+ return 7;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 1))) {
+ return 8;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 2))) {
+ return 9;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 3))) {
+ return 10;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 4))) {
+ return 11;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 5))) {
+ return 12;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 6))) {
+ return 13;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 7))) {
+ return 14;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 8))) {
+ return 15;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 9))) {
+ return 16;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 10))) {
+ return 17;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 11))) {
+ return 18;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 12))) {
+ return 19;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 13))) {
+ return 20;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 14))) {
+ return 21;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 15))) {
+ return 22;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+
+/* --------------------- sifive_gpio_button ------------ */
+
+
+/* --------------------- sifive_gpio_led ------------ */
+static inline struct metal_gpio * __metal_driver_sifive_gpio_led_gpio(struct metal_led *led)
+{
+ if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0red) {
+ return (struct metal_gpio *)&__metal_dt_gpio_10012000;
+ }
+ else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0green) {
+ return (struct metal_gpio *)&__metal_dt_gpio_10012000;
+ }
+ else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0blue) {
+ return (struct metal_gpio *)&__metal_dt_gpio_10012000;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static inline int __metal_driver_sifive_gpio_led_pin(struct metal_led *led)
+{
+ if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0red) {
+ return 22;
+ }
+ else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0green) {
+ return 19;
+ }
+ else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0blue) {
+ return 21;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline char * __metal_driver_sifive_gpio_led_label(struct metal_led *led)
+{
+ if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0red) {
+ return "LD0red";
+ }
+ else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0green) {
+ return "LD0green";
+ }
+ else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0blue) {
+ return "LD0blue";
+ }
+ else {
+ return "";
+ }
+}
+
+
+
+/* --------------------- sifive_gpio_switch ------------ */
+
+
+/* --------------------- sifive_spi0 ------------ */
+static inline unsigned long __metal_driver_sifive_spi0_control_base(struct metal_spi *spi)
+{
+ if ((uintptr_t)spi == (uintptr_t)&__metal_dt_spi_10014000) {
+ return METAL_SIFIVE_SPI0_10014000_BASE_ADDRESS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline unsigned long __metal_driver_sifive_spi0_control_size(struct metal_spi *spi)
+{
+ if ((uintptr_t)spi == (uintptr_t)&__metal_dt_spi_10014000) {
+ return METAL_SIFIVE_SPI0_10014000_SIZE;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline struct metal_clock * __metal_driver_sifive_spi0_clock(struct metal_spi *spi)
+{
+ return (struct metal_clock *)&__metal_dt_clock_4.clock;
+}
+
+static inline struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_spi0_pinmux(struct metal_spi *spi)
+{
+ return (struct __metal_driver_sifive_gpio0 *)&__metal_dt_gpio_10012000;
+}
+
+static inline unsigned long __metal_driver_sifive_spi0_pinmux_output_selector(struct metal_spi *spi)
+{
+ return 60;
+}
+
+static inline unsigned long __metal_driver_sifive_spi0_pinmux_source_selector(struct metal_spi *spi)
+{
+ return 60;
+}
+
+
+
+/* --------------------- sifive_test0 ------------ */
+
+
+/* --------------------- sifive_uart0 ------------ */
+static inline unsigned long __metal_driver_sifive_uart0_control_base(struct metal_uart *uart)
+{
+ if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
+ return METAL_SIFIVE_UART0_10013000_BASE_ADDRESS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline unsigned long __metal_driver_sifive_uart0_control_size(struct metal_uart *uart)
+{
+ if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
+ return METAL_SIFIVE_UART0_10013000_SIZE;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_uart0_num_interrupts(struct metal_uart *uart)
+{
+ if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
+ return METAL_MAX_UART_INTERRUPTS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline struct metal_interrupt * __metal_driver_sifive_uart0_interrupt_parent(struct metal_uart *uart)
+{
+ if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
+ return (struct metal_interrupt *)&__metal_dt_interrupt_controller_c000000.controller;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static inline int __metal_driver_sifive_uart0_interrupt_line(struct metal_uart *uart)
+{
+ return 5;
+}
+
+static inline struct metal_clock * __metal_driver_sifive_uart0_clock(struct metal_uart *uart)
+{
+ return (struct metal_clock *)&__metal_dt_clock_4.clock;
+}
+
+static inline struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_uart0_pinmux(struct metal_uart *uart)
+{
+ return (struct __metal_driver_sifive_gpio0 *)&__metal_dt_gpio_10012000;
+}
+
+static inline unsigned long __metal_driver_sifive_uart0_pinmux_output_selector(struct metal_uart *uart)
+{
+ return 196608;
+}
+
+static inline unsigned long __metal_driver_sifive_uart0_pinmux_source_selector(struct metal_uart *uart)
+{
+ return 196608;
+}
+
+
+
+/* --------------------- sifive_fe310_g000_hfrosc ------------ */
+static inline struct metal_clock * __metal_driver_sifive_fe310_g000_hfrosc_ref(const struct metal_clock *clock)
+{
+ return (struct metal_clock *)&__metal_dt_clock_2.clock;
+}
+
+static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_base(const struct metal_clock *clock)
+{
+ return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
+}
+
+static inline const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_vtable(struct metal_clock *clock)
+{
+ return &__metal_driver_vtable_sifive_fe310_g000_prci;
+}
+
+static inline long __metal_driver_sifive_fe310_g000_hfrosc_config_offset(const struct metal_clock *clock)
+{
+ return METAL_SIFIVE_FE310_G000_PRCI_HFROSCCFG;
+}
+
+
+
+/* --------------------- sifive_fe310_g000_hfxosc ------------ */
+static inline struct metal_clock * __metal_driver_sifive_fe310_g000_hfxosc_ref(const struct metal_clock *clock)
+{
+ return (struct metal_clock *)&__metal_dt_clock_0.clock;
+}
+
+static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfxosc_config_base(const struct metal_clock *clock)
+{
+ return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
+}
+
+static inline long __metal_driver_sifive_fe310_g000_hfxosc_config_offset(const struct metal_clock *clock)
+{
+ return METAL_SIFIVE_FE310_G000_PRCI_HFXOSCCFG;
+}
+
+
+
+/* --------------------- sifive_fe310_g000_pll ------------ */
+static inline struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllsel0(const struct metal_clock *clock)
+{
+ return (struct metal_clock *)&__metal_dt_clock_3.clock;
+}
+
+static inline struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllref(const struct metal_clock *clock)
+{
+ return (struct metal_clock *)&__metal_dt_clock_1.clock;
+}
+
+static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_divider_base(const struct metal_clock *clock)
+{
+ return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
+}
+
+static inline long __metal_driver_sifive_fe310_g000_pll_divider_offset(const struct metal_clock *clock)
+{
+ return METAL_SIFIVE_FE310_G000_PRCI_PLLOUTDIV;
+}
+
+static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_config_base( )
+{
+ return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
+}
+
+static inline long __metal_driver_sifive_fe310_g000_pll_config_offset( )
+{
+ return METAL_SIFIVE_FE310_G000_PRCI_PLLCFG;
+}
+
+static inline long __metal_driver_sifive_fe310_g000_pll_init_rate( )
+{
+ return 16000000;
+}
+
+
+
+/* --------------------- sifive_fe310_g000_prci ------------ */
+static inline long __metal_driver_sifive_fe310_g000_prci_base( )
+{
+ return METAL_SIFIVE_FE310_G000_PRCI_10008000_BASE_ADDRESS;
+}
+
+static inline long __metal_driver_sifive_fe310_g000_prci_size( )
+{
+ return METAL_SIFIVE_FE310_G000_PRCI_10008000_SIZE;
+}
+
+static inline const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_prci_vtable( )
+{
+ return &__metal_driver_vtable_sifive_fe310_g000_prci;
+}
+
+
+
+/* --------------------- sifive_fu540_c000_l2 ------------ */
+
+
+#define __METAL_DT_MAX_MEMORIES 2
+
+asm (".weak __metal_memory_table");
+struct metal_memory *__metal_memory_table[] = {
+ &__metal_dt_mem_dtim_80000000,
+ &__metal_dt_mem_spi_10014000};
+
+/* From serial@10013000 */
+#define __METAL_DT_STDOUT_UART_HANDLE (&__metal_dt_serial_10013000.uart)
+
+#define __METAL_DT_SERIAL_10013000_HANDLE (&__metal_dt_serial_10013000.uart)
+
+#define __METAL_DT_STDOUT_UART_BAUD 115200
+
+/* From clint@2000000 */
+#define __METAL_DT_RISCV_CLINT0_HANDLE (&__metal_dt_clint_2000000.controller)
+
+#define __METAL_DT_CLINT_2000000_HANDLE (&__metal_dt_clint_2000000.controller)
+
+#define __METAL_DT_MAX_HARTS 1
+
+asm (".weak __metal_cpu_table");
+struct __metal_driver_cpu *__metal_cpu_table[] = {
+ &__metal_dt_cpu_0};
+
+/* From interrupt_controller@c000000 */
+#define __METAL_DT_RISCV_PLIC0_HANDLE (&__metal_dt_interrupt_controller_c000000.controller)
+
+#define __METAL_DT_INTERRUPT_CONTROLLER_C000000_HANDLE (&__metal_dt_interrupt_controller_c000000.controller)
+
+#define __METAL_DT_PMP_HANDLE (&__metal_dt_pmp)
+
+/* From local_external_interrupts_0 */
+#define __METAL_DT_SIFIVE_LOCAL_EXINTR0_HANDLE (&__metal_dt_local_external_interrupts_0.irc)
+
+#define __METAL_DT_LOCAL_EXTERNAL_INTERRUPTS_0_HANDLE (&__metal_dt_local_external_interrupts_0.irc)
+
+#define __MEE_DT_MAX_GPIOS 1
+
+asm (".weak __metal_gpio_table");
+struct __metal_driver_sifive_gpio0 *__metal_gpio_table[] = {
+ &__metal_dt_gpio_10012000};
+
+#define __METAL_DT_MAX_BUTTONS 0
+
+asm (".weak __metal_button_table");
+struct __metal_driver_sifive_gpio_button *__metal_button_table[] = {
+ NULL };
+#define __METAL_DT_MAX_LEDS 3
+
+asm (".weak __metal_led_table");
+struct __metal_driver_sifive_gpio_led *__metal_led_table[] = {
+ &__metal_dt_led_0red,
+ &__metal_dt_led_0green,
+ &__metal_dt_led_0blue};
+
+#define __METAL_DT_MAX_SWITCHES 0
+
+asm (".weak __metal_switch_table");
+struct __metal_driver_sifive_gpio_switch *__metal_switch_table[] = {
+ NULL };
+#define __METAL_DT_MAX_SPIS 1
+
+asm (".weak __metal_spi_table");
+struct __metal_driver_sifive_spi0 *__metal_spi_table[] = {
+ &__metal_dt_spi_10014000};
+
+/* From clock@4 */
+#define __METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE (&__metal_dt_clock_4)
+
+#define __METAL_DT_CLOCK_4_HANDLE (&__metal_dt_clock_4)
+
+#endif /* MACROS_ELSE_SIFIVE_HIFIVE1_REVB____METAL_H*/
+
+#endif /* ! __METAL_MACHINE_MACROS */
+
+#endif /* ! ASSEMBLY */
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+/* ----------------------------------- */
+/* ----------------------------------- */
+
+#ifndef ASSEMBLY
+
+#ifndef SIFIVE_HIFIVE1_REVB____METAL_INLINE_H
+#define SIFIVE_HIFIVE1_REVB____METAL_INLINE_H
+
+#include <metal/machine.h>
+
+
+/* --------------------- fixed_clock ------------ */
+extern inline unsigned long __metal_driver_fixed_clock_rate(const struct metal_clock *clock);
+
+
+/* --------------------- fixed_factor_clock ------------ */
+
+
+/* --------------------- 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_size(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 int __metal_driver_sifive_clint0_interrupt_lines(struct metal_interrupt *controller, int idx);
+
+
+/* --------------------- 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 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);
+
+
+/* --------------------- 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_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_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 int __metal_driver_sifive_plic0_interrupt_lines(struct metal_interrupt *controller, int idx);
+
+
+/* --------------------- sifive_clic0 ------------ */
+
+
+/* --------------------- 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_gpio0 ------------ */
+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 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 int __metal_driver_sifive_gpio0_interrupt_lines(struct metal_gpio *gpio, int idx);
+
+
+/* --------------------- sifive_gpio_button ------------ */
+
+
+/* --------------------- sifive_gpio_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 char * __metal_driver_sifive_gpio_led_label(struct metal_led *led);
+
+
+/* --------------------- sifive_gpio_switch ------------ */
+
+
+/* --------------------- 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_size(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_source_selector(struct metal_spi *spi);
+
+
+/* --------------------- sifive_test0 ------------ */
+
+
+/* --------------------- 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_size(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 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_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_source_selector(struct metal_uart *uart);
+
+
+/* --------------------- 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_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 long __metal_driver_sifive_fe310_g000_hfrosc_config_offset(const struct metal_clock *clock);
+
+
+/* --------------------- 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_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);
+
+
+/* --------------------- 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_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 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 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( );
+
+
+/* --------------------- fe310_g000_prci ------------ */
+extern inline long __metal_driver_sifive_fe310_g000_prci_base( );
+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( );
+
+
+/* --------------------- sifive_fu540_c000_l2 ------------ */
+
+
+/* From clock@0 */
+struct __metal_driver_fixed_clock __metal_dt_clock_0 = {
+ .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
+};
+
+/* From clock@2 */
+struct __metal_driver_fixed_clock __metal_dt_clock_2 = {
+ .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
+};
+
+/* From clock@5 */
+struct __metal_driver_fixed_clock __metal_dt_clock_5 = {
+ .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
+};
+
+struct metal_memory __metal_dt_mem_dtim_80000000 = {
+ ._base_address = 2147483648UL,
+ ._size = 16384UL,
+ ._attrs = {
+ .R = 1,
+ .W = 1,
+ .X = 1,
+ .C = 1,
+ .A = 1},
+};
+
+struct metal_memory __metal_dt_mem_spi_10014000 = {
+ ._base_address = 536870912UL,
+ ._size = 500000UL,
+ ._attrs = {
+ .R = 1,
+ .W = 1,
+ .X = 1,
+ .C = 1,
+ .A = 1},
+};
+
+/* From clint@2000000 */
+struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000 = {
+ .controller.vtable = &__metal_driver_vtable_riscv_clint0.clint_vtable,
+ .init_done = 0,
+};
+
+/* From cpu@0 */
+struct __metal_driver_cpu __metal_dt_cpu_0 = {
+ .cpu.vtable = &__metal_driver_vtable_cpu.cpu_vtable,
+};
+
+/* From interrupt_controller */
+struct __metal_driver_riscv_cpu_intc __metal_dt_cpu_0_interrupt_controller = {
+ .controller.vtable = &__metal_driver_vtable_riscv_cpu_intc.controller_vtable,
+ .init_done = 0,
+};
+
+/* From interrupt_controller@c000000 */
+struct __metal_driver_riscv_plic0 __metal_dt_interrupt_controller_c000000 = {
+ .controller.vtable = &__metal_driver_vtable_riscv_plic0.plic_vtable,
+ .init_done = 0,
+};
+
+/* From local_external_interrupts_0 */
+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 */
+struct __metal_driver_sifive_gpio0 __metal_dt_gpio_10012000 = {
+ .gpio.vtable = &__metal_driver_vtable_sifive_gpio0.gpio,
+};
+
+/* From led@0red */
+struct __metal_driver_sifive_gpio_led __metal_dt_led_0red = {
+ .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
+};
+
+/* From led@0green */
+struct __metal_driver_sifive_gpio_led __metal_dt_led_0green = {
+ .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
+};
+
+/* From led@0blue */
+struct __metal_driver_sifive_gpio_led __metal_dt_led_0blue = {
+ .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
+};
+
+/* From spi@10014000 */
+struct __metal_driver_sifive_spi0 __metal_dt_spi_10014000 = {
+ .spi.vtable = &__metal_driver_vtable_sifive_spi0.spi,
+};
+
+/* From serial@10013000 */
+struct __metal_driver_sifive_uart0 __metal_dt_serial_10013000 = {
+ .uart.vtable = &__metal_driver_vtable_sifive_uart0.uart,
+};
+
+/* From clock@3 */
+struct __metal_driver_sifive_fe310_g000_hfrosc __metal_dt_clock_3 = {
+ .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfrosc.clock,
+};
+
+/* From clock@1 */
+struct __metal_driver_sifive_fe310_g000_hfxosc __metal_dt_clock_1 = {
+ .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfxosc.clock,
+};
+
+/* From clock@4 */
+struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4 = {
+ .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_pll.clock,
+};
+
+/* From prci@10008000 */
+struct __metal_driver_sifive_fe310_g000_prci __metal_dt_prci_10008000 = {
+};
+
+
+#endif /* SIFIVE_HIFIVE1_REVB____METAL_INLINE_H*/
+#endif /* ! ASSEMBLY */
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+/* ----------------------------------- */
+/* ----------------------------------- */
+
+#ifndef SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H
+#define SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H
+
+/* From clock@0 */
+#define METAL_FIXED_CLOCK_0_CLOCK_FREQUENCY 16000000UL
+
+/* From clock@2 */
+#define METAL_FIXED_CLOCK_2_CLOCK_FREQUENCY 72000000UL
+
+/* From clock@5 */
+#define METAL_FIXED_CLOCK_5_CLOCK_FREQUENCY 32000000UL
+
+#define METAL_FIXED_CLOCK
+
+/* From clint@2000000 */
+#define METAL_RISCV_CLINT0_2000000_BASE_ADDRESS 33554432UL
+#define METAL_RISCV_CLINT0_0_BASE_ADDRESS 33554432UL
+#define METAL_RISCV_CLINT0_2000000_SIZE 65536UL
+#define METAL_RISCV_CLINT0_0_SIZE 65536UL
+
+#define METAL_RISCV_CLINT0
+#define METAL_RISCV_CLINT0_MSIP_BASE 0UL
+#define METAL_RISCV_CLINT0_MTIMECMP_BASE 16384UL
+#define METAL_RISCV_CLINT0_MTIME 49144UL
+
+/* From interrupt_controller@c000000 */
+#define METAL_RISCV_PLIC0_C000000_BASE_ADDRESS 201326592UL
+#define METAL_RISCV_PLIC0_0_BASE_ADDRESS 201326592UL
+#define METAL_RISCV_PLIC0_C000000_SIZE 67108864UL
+#define METAL_RISCV_PLIC0_0_SIZE 67108864UL
+#define METAL_RISCV_PLIC0_C000000_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_0_RISCV_NDEV 27UL
+
+#define METAL_RISCV_PLIC0
+#define METAL_RISCV_PLIC0_PRIORITY_BASE 0UL
+#define METAL_RISCV_PLIC0_PENDING_BASE 4096UL
+#define METAL_RISCV_PLIC0_ENABLE_BASE 8192UL
+#define METAL_RISCV_PLIC0_THRESHOLD 2097152UL
+#define METAL_RISCV_PLIC0_CLAIM 2097156UL
+
+/* 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_AON0
+#define METAL_SIFIVE_AON0_WDOGCFG 0UL
+#define METAL_SIFIVE_AON0_WDOGCOUNT 8UL
+#define METAL_SIFIVE_AON0_WDOGS 16UL
+#define METAL_SIFIVE_AON0_WDOGFEED 24UL
+#define METAL_SIFIVE_AON0_WDOGKEY 28UL
+#define METAL_SIFIVE_AON0_WDOGCMP 32UL
+#define METAL_SIFIVE_AON0_RTCCFG 64UL
+#define METAL_SIFIVE_AON0_RTCLO 72UL
+#define METAL_SIFIVE_AON0_RTCHI 72UL
+#define METAL_SIFIVE_AON0_RTCS 80UL
+#define METAL_SIFIVE_AON0_RTCCMP 96UL
+#define METAL_SIFIVE_AON0_LFROSCCFG 112UL
+#define METAL_SIFIVE_AON0_BACKUP0 128UL
+#define METAL_SIFIVE_AON0_BACKUP1 132UL
+#define METAL_SIFIVE_AON0_BACKUP2 136UL
+#define METAL_SIFIVE_AON0_BACKUP3 140UL
+#define METAL_SIFIVE_AON0_BACKUP4 144UL
+#define METAL_SIFIVE_AON0_BACKUP5 148UL
+#define METAL_SIFIVE_AON0_BACKUP6 152UL
+#define METAL_SIFIVE_AON0_BACKUP7 152UL
+#define METAL_SIFIVE_AON0_BACKUP8 160UL
+#define METAL_SIFIVE_AON0_BACKUP9 164UL
+#define METAL_SIFIVE_AON0_BACKUP10 168UL
+#define METAL_SIFIVE_AON0_BACKUP11 172UL
+#define METAL_SIFIVE_AON0_BACKUP12 176UL
+#define METAL_SIFIVE_AON0_BACKUP13 180UL
+#define METAL_SIFIVE_AON0_BACKUP14 184UL
+#define METAL_SIFIVE_AON0_BACKUP15 188UL
+#define METAL_SIFIVE_AON0_BACKUP16 192UL
+#define METAL_SIFIVE_AON0_BACKUP17 196UL
+#define METAL_SIFIVE_AON0_BACKUP18 200UL
+#define METAL_SIFIVE_AON0_BACKUP19 204UL
+#define METAL_SIFIVE_AON0_BACKUP20 208UL
+#define METAL_SIFIVE_AON0_BACKUP21 212UL
+#define METAL_SIFIVE_AON0_BACKUP22 216UL
+#define METAL_SIFIVE_AON0_BACKUP23 220UL
+#define METAL_SIFIVE_AON0_BACKUP24 224UL
+#define METAL_SIFIVE_AON0_BACKUP25 228UL
+#define METAL_SIFIVE_AON0_BACKUP26 232UL
+#define METAL_SIFIVE_AON0_BACKUP27 236UL
+#define METAL_SIFIVE_AON0_BACKUP28 240UL
+#define METAL_SIFIVE_AON0_BACKUP29 244UL
+#define METAL_SIFIVE_AON0_BACKUP30 248UL
+#define METAL_SIFIVE_AON0_BACKUP31 252UL
+#define METAL_SIFIVE_AON0_PMU_WAKEUP_BASE 256UL
+#define METAL_SIFIVE_AON0_PWM_SLEEP_BASE 288UL
+#define METAL_SIFIVE_AON0_PMUIE 320UL
+#define METAL_SIFIVE_AON0_PMUCAUSE 324UL
+#define METAL_SIFIVE_AON0_PMUSLEEP 328UL
+#define METAL_SIFIVE_AON0_PMUKEY 332UL
+
+/* From clock@3 */
+
+#define METAL_SIFIVE_FE310_G000_HFROSC
+
+/* From clock@1 */
+
+#define METAL_SIFIVE_FE310_G000_HFXOSC
+
+/* From prci@10008000 */
+#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_10008000_SIZE 32768UL
+#define METAL_SIFIVE_FE310_G000_PRCI_0_SIZE 32768UL
+
+#define METAL_SIFIVE_FE310_G000_PRCI
+#define METAL_SIFIVE_FE310_G000_PRCI_HFROSCCFG 0UL
+#define METAL_SIFIVE_FE310_G000_PRCI_HFXOSCCFG 4UL
+#define METAL_SIFIVE_FE310_G000_PRCI_PLLCFG 8UL
+#define METAL_SIFIVE_FE310_G000_PRCI_PLLOUTDIV 12UL
+
+/* From clock@4 */
+#define METAL_SIFIVE_FE310_G000_PLL_4_CLOCK_FREQUENCY 16000000UL
+
+#define METAL_SIFIVE_FE310_G000_PLL
+
+/* From gpio@10012000 */
+#define METAL_SIFIVE_GPIO0_10012000_BASE_ADDRESS 268509184UL
+#define METAL_SIFIVE_GPIO0_0_BASE_ADDRESS 268509184UL
+#define METAL_SIFIVE_GPIO0_10012000_SIZE 4096UL
+#define METAL_SIFIVE_GPIO0_0_SIZE 4096UL
+
+#define METAL_SIFIVE_GPIO0
+#define METAL_SIFIVE_GPIO0_VALUE 0UL
+#define METAL_SIFIVE_GPIO0_INPUT_EN 4UL
+#define METAL_SIFIVE_GPIO0_OUTPUT_EN 8UL
+#define METAL_SIFIVE_GPIO0_PORT 12UL
+#define METAL_SIFIVE_GPIO0_PUE 16UL
+#define METAL_SIFIVE_GPIO0_DS 20UL
+#define METAL_SIFIVE_GPIO0_RISE_IE 24UL
+#define METAL_SIFIVE_GPIO0_RISE_IP 28UL
+#define METAL_SIFIVE_GPIO0_FALL_IE 32UL
+#define METAL_SIFIVE_GPIO0_FALL_IP 36UL
+#define METAL_SIFIVE_GPIO0_HIGH_IE 40UL
+#define METAL_SIFIVE_GPIO0_HIGH_IP 44UL
+#define METAL_SIFIVE_GPIO0_LOW_IE 48UL
+#define METAL_SIFIVE_GPIO0_LOW_IP 52UL
+#define METAL_SIFIVE_GPIO0_IOF_EN 56UL
+#define METAL_SIFIVE_GPIO0_IOF_SEL 60UL
+#define METAL_SIFIVE_GPIO0_OUT_XOR 64UL
+
+/* From led@0red */
+
+/* From led@0green */
+
+/* From led@0blue */
+
+#define METAL_SIFIVE_GPIO_LEDS
+
+/* From i2c@10016000 */
+#define METAL_SIFIVE_I2C0_10016000_BASE_ADDRESS 268525568UL
+#define METAL_SIFIVE_I2C0_0_BASE_ADDRESS 268525568UL
+#define METAL_SIFIVE_I2C0_10016000_SIZE 4096UL
+#define METAL_SIFIVE_I2C0_0_SIZE 4096UL
+
+#define METAL_SIFIVE_I2C0
+#define METAL_SIFIVE_I2C0_PRESCALE_LOW 0UL
+#define METAL_SIFIVE_I2C0_PRESCALE_HIGH 4UL
+#define METAL_SIFIVE_I2C0_CONTROL 8UL
+#define METAL_SIFIVE_I2C0_TRANSMIT 12UL
+#define METAL_SIFIVE_I2C0_RECEIVE 12UL
+#define METAL_SIFIVE_I2C0_COMMAND 16UL
+#define METAL_SIFIVE_I2C0_STATUS 16UL
+
+/* From local_external_interrupts_0 */
+
+#define METAL_SIFIVE_LOCAL_EXTERNAL_INTERRUPTS0
+
+/* From pwm@10015000 */
+#define METAL_SIFIVE_PWM0_10015000_BASE_ADDRESS 268521472UL
+#define METAL_SIFIVE_PWM0_0_BASE_ADDRESS 268521472UL
+#define METAL_SIFIVE_PWM0_10015000_SIZE 4096UL
+#define METAL_SIFIVE_PWM0_0_SIZE 4096UL
+
+#define METAL_SIFIVE_PWM0
+#define METAL_SIFIVE_PWM0_PWMCFG 0UL
+#define METAL_SIFIVE_PWM0_PWMCOUNT 8UL
+#define METAL_SIFIVE_PWM0_PWMS 16UL
+#define METAL_SIFIVE_PWM0_PWMCMP0 32UL
+#define METAL_SIFIVE_PWM0_PWMCMP1 36UL
+#define METAL_SIFIVE_PWM0_PWMCMP2 40UL
+#define METAL_SIFIVE_PWM0_PWMCMP3 44UL
+
+/* From spi@10014000 */
+#define METAL_SIFIVE_SPI0_10014000_BASE_ADDRESS 268517376UL
+#define METAL_SIFIVE_SPI0_0_BASE_ADDRESS 268517376UL
+#define METAL_SIFIVE_SPI0_10014000_SIZE 4096UL
+#define METAL_SIFIVE_SPI0_0_SIZE 4096UL
+
+#define METAL_SIFIVE_SPI0
+#define METAL_SIFIVE_SPI0_SCKDIV 0UL
+#define METAL_SIFIVE_SPI0_SCKMODE 4UL
+#define METAL_SIFIVE_SPI0_CSID 16UL
+#define METAL_SIFIVE_SPI0_CSDEF 20UL
+#define METAL_SIFIVE_SPI0_CSMODE 24UL
+#define METAL_SIFIVE_SPI0_DELAY0 40UL
+#define METAL_SIFIVE_SPI0_DELAY1 44UL
+#define METAL_SIFIVE_SPI0_FMT 64UL
+#define METAL_SIFIVE_SPI0_TXDATA 72UL
+#define METAL_SIFIVE_SPI0_RXDATA 76UL
+#define METAL_SIFIVE_SPI0_TXMARK 80UL
+#define METAL_SIFIVE_SPI0_RXMARK 84UL
+#define METAL_SIFIVE_SPI0_FCTRL 96UL
+#define METAL_SIFIVE_SPI0_FFMT 100UL
+#define METAL_SIFIVE_SPI0_IE 112UL
+#define METAL_SIFIVE_SPI0_IP 116UL
+
+/* From serial@10013000 */
+#define METAL_SIFIVE_UART0_10013000_BASE_ADDRESS 268513280UL
+#define METAL_SIFIVE_UART0_0_BASE_ADDRESS 268513280UL
+#define METAL_SIFIVE_UART0_10013000_SIZE 4096UL
+#define METAL_SIFIVE_UART0_0_SIZE 4096UL
+
+#define METAL_SIFIVE_UART0
+#define METAL_SIFIVE_UART0_TXDATA 0UL
+#define METAL_SIFIVE_UART0_RXDATA 4UL
+#define METAL_SIFIVE_UART0_TXCTRL 8UL
+#define METAL_SIFIVE_UART0_RXCTRL 12UL
+#define METAL_SIFIVE_UART0_IE 16UL
+#define METAL_SIFIVE_UART0_IP 20UL
+#define METAL_SIFIVE_UART0_DIV 24UL
+
+#endif /* SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H*/
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__MEMORY_H
+#define METAL__MEMORY_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/*!
+ * @file memory.h
+ *
+ * @brief API for enumerating memory blocks
+ */
+
+struct _metal_memory_attributes {
+ int R : 1;
+ int W : 1;
+ int X : 1;
+ int C : 1;
+ int A : 1;
+};
+
+/*!
+ * @brief A handle for a memory block
+ */
+struct metal_memory {
+ const uintptr_t _base_address;
+ const size_t _size;
+ const struct _metal_memory_attributes _attrs;
+};
+
+/*!
+ * @brief Get the memory block which services the given address
+ *
+ * Given a physical memory address, get a handle for the memory block to which
+ * that address is mapped.
+ *
+ * @param address The address to query
+ * @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);
+
+/*!
+ * @brief Get the base address for a memory block
+ * @param memory The handle for the memory block
+ * @return The base address of the memory block
+ */
+inline uintptr_t metal_memory_get_base_address(const struct metal_memory *memory) {
+ return memory->_base_address;
+}
+
+/*!
+ * @brief Get the size of a memory block
+ * @param memory The handle for the memory block
+ * @return The size of the memory block
+ */
+inline size_t metal_memory_get_size(const struct metal_memory *memory) {
+ return memory->_size;
+}
+
+/*!
+ * @brief Query if a memory block supports atomic operations
+ * @param memory The handle for the memory block
+ * @return nonzero if the memory block supports atomic operations
+ */
+inline int metal_memory_supports_atomics(const struct metal_memory *memory) {
+ return memory->_attrs.A;
+}
+
+/*!
+ * @brief Query if a memory block is cacheable
+ * @param memory The handle for the memory block
+ * @return nonzero if the memory block is cachable
+ */
+inline int metal_memory_is_cachable(const struct metal_memory *memory) {
+ return memory->_attrs.C;
+}
+
+#endif /* METAL__MEMORY_H */
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__PMP_H
+#define METAL__PMP_H
+
+/*!
+ * @file metal/pmp.h
+ *
+ * @brief API for Configuring Physical Memory Protection on RISC-V Cores
+ *
+ * The Physical Memory Protection (PMP) interface on RISC-V cores
+ * is a form of memory protection unit which allows for a finite number
+ * of physical memory regions to be configured with certain access
+ * permissions.
+ *
+ * Additional information about the use and configuration rules for PMPs
+ * can be found by reading the RISC-V Privileged Architecture Specification.
+ */
+
+#include <stddef.h>
+#include <metal/machine.h>
+
+struct metal_pmp;
+
+/*!
+ * @brief Set of available PMP addressing modes
+ */
+enum metal_pmp_address_mode {
+ /*! @brief Disable the PMP region */
+ METAL_PMP_OFF = 0,
+ /*! @brief Use Top-of-Range mode */
+ METAL_PMP_TOR = 1,
+ /*! @brief Use naturally-aligned 4-byte region mode */
+ METAL_PMP_NA4 = 2,
+ /*! @brief Use naturally-aligned power-of-two mode */
+ METAL_PMP_NAPOT = 3
+};
+
+/*!
+ * @brief Configuration for a PMP region
+ */
+struct metal_pmp_config {
+ /*! @brief Sets whether reads to the PMP region succeed */
+ int R : 1;
+ /*! @brief Sets whether writes to the PMP region succeed */
+ int W : 1;
+ /*! @brief Sets whether the PMP region is executable */
+ int X : 1;
+
+ /*! @brief Sets the addressing mode of the PMP region */
+ enum metal_pmp_address_mode A : 2;
+
+ int _pad : 2;
+
+ /*! @brief Sets whether the PMP region is locked */
+ enum metal_pmp_locked {
+ METAL_PMP_UNLOCKED = 0,
+ METAL_PMP_LOCKED = 1
+ } L : 1;
+};
+
+/*!
+ * @brief A handle for the PMP device
+ */
+struct metal_pmp {
+ /* The minimum granularity of the PMP region. Set by metal_pmp_init */
+ uintptr_t _granularity[METAL_MAX_CORES];
+};
+
+/*!
+ * @brief Get the PMP device handle
+ */
+struct metal_pmp *metal_pmp_get_device(void);
+
+/*!
+ * @brief Initialize the PMP
+ * @param pmp The PMP device handle to be initialized
+ *
+ * The PMP initialization routine is optional and may be called as many times
+ * as is desired. The effect of the initialization routine is to attempt to set
+ * all regions to unlocked and disabled, as well as to clear the X, W, and R
+ * bits. Only the pmp configuration of the hart which executes the routine will
+ * be affected.
+ *
+ * If any regions are fused to preset values by the implementation or locked,
+ * those PMP regions will silently remain uninitialized.
+ */
+void metal_pmp_init(struct metal_pmp *pmp);
+
+/*!
+ * @brief Configure a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to configure
+ * @param config The desired configuration of the PMP region
+ * @param address The desired address of the PMP region
+ * @return 0 upon success
+ */
+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
+ * @param pmp The PMP device handle
+ * @param region The PMP region to read
+ * @param config Variable to store the PMP region configuration
+ * @param address Variable to store the PMP region address
+ * @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);
+
+/*!
+ * @brief Lock a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to lock
+ * @return 0 if the region is successfully locked
+ */
+int metal_pmp_lock(struct metal_pmp *pmp, unsigned int region);
+
+/*!
+ * @brief Set the address for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to set
+ * @param address The desired address of the PMP region
+ * @return 0 if the address is successfully set
+ */
+int metal_pmp_set_address(struct metal_pmp *pmp, unsigned int region, size_t address);
+
+/*!
+ * @brief Get the address of a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to read
+ * @return The address of the PMP region, or 0 if the region could not be read
+ */
+size_t metal_pmp_get_address(struct metal_pmp *pmp, unsigned int region);
+
+/*!
+ * @brief Set the addressing mode of a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to set
+ * @param mode The PMP addressing mode to 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);
+
+/*!
+ * @brief Get the addressing mode of a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to read
+ * @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);
+
+/*!
+ * @brief Set the executable bit for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to set
+ * @param X The desired value of the executable bit
+ * @return 0 if the executable bit is successfully set
+ */
+int metal_pmp_set_executable(struct metal_pmp *pmp, unsigned int region, int X);
+
+/*!
+ * @brief Get the executable bit for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to read
+ * @return the value of the executable bit
+ */
+int metal_pmp_get_executable(struct metal_pmp *pmp, unsigned int region);
+
+/*!
+ * @brief Set the writable bit for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to set
+ * @param W The desired value of the writable bit
+ * @return 0 if the writable bit is successfully set
+ */
+int metal_pmp_set_writeable(struct metal_pmp *pmp, unsigned int region, int W);
+
+/*!
+ * @brief Get the writable bit for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to read
+ * @return the value of the writable bit
+ */
+int metal_pmp_get_writeable(struct metal_pmp *pmp, unsigned int region);
+
+/*!
+ * @brief Set the readable bit for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to set
+ * @param R The desired value of the readable bit
+ * @return 0 if the readable bit is successfully set
+ */
+int metal_pmp_set_readable(struct metal_pmp *pmp, unsigned int region, int R);
+
+/*!
+ * @brief Set the readable bit for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to read
+ * @return the value of the readable bit
+ */
+int metal_pmp_get_readable(struct metal_pmp *pmp, unsigned int region);
+
+#endif
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__PRIVILEGE_H
+#define METAL__PRIVILEGE_H
+
+/*!
+ * @file metal/privilege.h
+ *
+ * @brief API for manipulating the privilege mode of a RISC-V system
+ *
+ * Additional information about privilege modes on RISC-V systems can be found
+ * by reading the RISC-V Privileged Architecture Specification v1.10.
+ */
+
+#include <stdint.h>
+
+enum metal_privilege_mode {
+ METAL_PRIVILEGE_USER = 0,
+ METAL_PRIVILEGE_SUPERVISOR = 1,
+ METAL_PRIVELEGE_MACHINE = 3,
+};
+
+#if __riscv_xlen == 32
+typedef uint32_t metal_xreg_t;
+#elif __riscv_xlen == 64
+typedef uint64_t metal_xreg_t;
+#endif
+
+#if __riscv_flen == 32
+typedef uint32_t metal_freg_t;
+#elif __riscv_flen == 64
+typedef uint64_t metal_freg_t;
+#endif
+
+struct metal_register_file {
+ metal_xreg_t ra;
+ metal_xreg_t sp;
+ metal_xreg_t gp;
+ metal_xreg_t tp;
+
+ metal_xreg_t t0;
+ metal_xreg_t t1;
+ metal_xreg_t t2;
+
+ metal_xreg_t s0;
+ metal_xreg_t s1;
+
+ metal_xreg_t a0;
+ metal_xreg_t a1;
+ metal_xreg_t a2;
+ metal_xreg_t a3;
+ metal_xreg_t a4;
+ metal_xreg_t a5;
+#ifndef __riscv_32e
+ metal_xreg_t a6;
+ metal_xreg_t a7;
+
+ metal_xreg_t s2;
+ metal_xreg_t s3;
+ metal_xreg_t s4;
+ metal_xreg_t s5;
+ metal_xreg_t s6;
+ metal_xreg_t s7;
+ metal_xreg_t s8;
+ metal_xreg_t s9;
+ metal_xreg_t s10;
+ metal_xreg_t s11;
+
+ metal_xreg_t t3;
+ metal_xreg_t t4;
+ metal_xreg_t t5;
+ metal_xreg_t t6;
+#endif /* __riscv_32e */
+
+#ifdef __riscv_flen
+ metal_freg_t ft0;
+ metal_freg_t ft1;
+ metal_freg_t ft2;
+ metal_freg_t ft3;
+ metal_freg_t ft4;
+ metal_freg_t ft5;
+ metal_freg_t ft6;
+ metal_freg_t ft7;
+
+ metal_freg_t fs0;
+ metal_freg_t fs1;
+
+ metal_freg_t fa0;
+ metal_freg_t fa1;
+ metal_freg_t fa2;
+ metal_freg_t fa3;
+ metal_freg_t fa4;
+ metal_freg_t fa5;
+ metal_freg_t fa6;
+ metal_freg_t fa7;
+
+ metal_freg_t fs2;
+ metal_freg_t fs3;
+ metal_freg_t fs4;
+ metal_freg_t fs5;
+ metal_freg_t fs6;
+ metal_freg_t fs7;
+ metal_freg_t fs8;
+ metal_freg_t fs9;
+ metal_freg_t fs10;
+ metal_freg_t fs11;
+
+ metal_freg_t ft8;
+ metal_freg_t ft9;
+ metal_freg_t ft10;
+ metal_freg_t ft11;
+#endif /* __riscv_flen */
+};
+
+typedef void (*metal_privilege_entry_point_t)();
+
+void metal_privilege_drop_to_mode(enum metal_privilege_mode mode,
+ struct metal_register_file regfile,
+ metal_privilege_entry_point_t entry_point);
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__SHUTDOWN_H
+#define METAL__SHUTDOWN_H
+
+/*!
+ * @file shutdown.h
+ * @brief API for shutting down a machine
+ */
+
+struct __metal_shutdown;
+
+struct __metal_shutdown_vtable {
+ void (*exit)(const struct __metal_shutdown *sd, int code) __attribute__((noreturn));
+};
+
+struct __metal_shutdown {
+ 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, int code) { sd->vtable->exit(sd, code); }
+
+/*!
+ * @brief The public METAL shutdown interface
+ *
+ * Shuts down the machine, if the machine enables an interface for
+ * shutting down. When no interface is provided, will cause the machine
+ * to spin indefinitely.
+ *
+ * @param code The return code to set. 0 indicates program success.
+ */
+void metal_shutdown(int code) __attribute__((noreturn));
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__SPI_H
+#define METAL__SPI_H
+
+struct metal_spi;
+
+/*! @brief The configuration for a SPI transfer */
+struct metal_spi_config {
+ /*! @brief The protocol for the SPI transfer */
+ enum {
+ METAL_SPI_SINGLE,
+ METAL_SPI_DUAL,
+ METAL_SPI_QUAD
+ } protocol;
+
+ /*! @brief The polarity of the SPI transfer, equivalent to CPOL */
+ unsigned int polarity : 1;
+ /*! @brief The phase of the SPI transfer, equivalent to CPHA */
+ unsigned int phase : 1;
+ /*! @brief The endianness of the SPI transfer */
+ unsigned int little_endian : 1;
+ /*! @brief The active state of the chip select line */
+ unsigned int cs_active_high : 1;
+ /*! @brief The chip select ID to activate for the SPI transfer */
+ unsigned int csid;
+};
+
+struct metal_spi_vtable {
+ 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 (*get_baud_rate)(struct metal_spi *spi);
+ int (*set_baud_rate)(struct metal_spi *spi, int baud_rate);
+};
+
+/*! @brief A handle for a SPI device */
+struct metal_spi {
+ const struct metal_spi_vtable *vtable;
+};
+
+/*! @brief Get a handle for a 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*/
+struct metal_spi *metal_spi_get_device(int device_num);
+
+/*! @brief Initialize a SPI device with a certain baud rate
+ * @param spi The handle for the SPI device to initialize
+ * @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); }
+
+/*! @brief Perform a SPI transfer
+ * @param spi The handle for the SPI device to perform the transfer
+ * @param config The configuration for the SPI 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 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
+ */
+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);
+}
+
+/*! @brief Get the current baud rate of the SPI device
+ * @param spi The handle for the SPI device
+ * @return The baud rate in Hz
+ */
+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
+ * @param spi The handle for the SPI device
+ * @param baud_rate The desired baud rate of the SPI device
+ * @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); }
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__SWITCH_H
+#define METAL__SWITCH_H
+
+/*!
+ * @file switch.h
+ * @brief API for reading toggle switches
+ */
+
+#include <metal/interrupt.h>
+
+struct metal_switch;
+
+struct metal_switch_vtable {
+ int (*switch_exist)(struct metal_switch *sw, char *label);
+ struct metal_interrupt* (*interrupt_controller)(struct metal_switch *sw);
+ int (*get_interrupt_id)(struct metal_switch *sw);
+};
+
+/*!
+ * @brief A handle for a switch
+ */
+struct metal_switch {
+ const struct metal_switch_vtable *vtable;
+};
+
+/*!
+ * @brief Get a handle for a 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
+ */
+struct metal_switch* metal_switch_get(char *label);
+
+/*!
+ * @brief Get the interrupt controller for a switch
+ * @param sw The handle for the switch
+ * @return The interrupt controller handle
+ */
+inline struct metal_interrupt*
+ metal_switch_interrupt_controller(struct metal_switch *sw) { return sw->vtable->interrupt_controller(sw); }
+
+/*!
+ * @brief Get the interrupt id for a switch
+ * @param sw The handle 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); }
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__TIMER_H
+#define METAL__TIMER_H
+
+/*!
+ * @file timer.h
+ * @brief API for reading and manipulating the machine timer
+ */
+
+/*!
+ * @brief Read the machine cycle count
+ * @param hartid The hart ID to read the cycle count of
+ * @param cyclecount The variable to hold the value
+ * @return 0 upon success
+ */
+int metal_timer_get_cyclecount(int hartid, unsigned long long *cyclecount);
+
+/*!
+ * @brief Get the machine timebase frequency
+ * @param hartid The hart ID to read the timebase of
+ * @param timebase The variable to hold the value
+ * @return 0 upon success
+ */
+int metal_timer_get_timebase_frequency(int hartid, unsigned long long *timebase);
+
+/*!
+ * @brief Set the machine timer tick interval in seconds
+ * @param hartid The hart ID to read the timebase of
+ * @param second The number of seconds to set the tick interval to
+ * @return 0 upon success
+ */
+int metal_timer_set_tick(int hartid, int second);
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__TTY_H
+#define METAL__TTY_H
+
+/*!
+ * @file tty.h
+ * @brief API for emulated serial teriminals
+ */
+
+/*!
+ * @brief Write a character to the default output device
+ *
+ * Write a character to the default output device, which for most
+ * targets is the UART serial port.
+ *
+ * @param c The character to write to the terminal
+ * @return 0 on success, or -1 on failure.
+ */
+int metal_tty_putc(unsigned char c);
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__UART_H
+#define METAL__UART_H
+
+/*!
+ * @file uart.h
+ * @brief API for UART serial ports
+ */
+
+#include <metal/interrupt.h>
+
+struct metal_uart;
+
+struct metal_uart_vtable {
+ void (*init)(struct metal_uart *uart, int baud_rate);
+ int (*putc)(struct metal_uart *uart, unsigned char c);
+ int (*getc)(struct metal_uart *uart, unsigned char *c);
+ int (*get_baud_rate)(struct metal_uart *uart);
+ int (*set_baud_rate)(struct metal_uart *uart, int baud_rate);
+ struct metal_interrupt* (*controller_interrupt)(struct metal_uart *uart);
+ int (*get_interrupt_id)(struct metal_uart *uart);
+};
+
+/*!
+ * @brief Handle for a UART serial device
+ */
+struct metal_uart {
+ const struct metal_uart_vtable *vtable;
+};
+
+/*!
+ * @brief Initialize UART device
+
+ * Initialize the UART device described by the UART handle. This function must 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 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); }
+
+/*!
+ * @brief Output a character over the UART
+ * @param uart The UART device handle
+ * @param c The character to send over the UART
+ * @return 0 upon success
+ */
+inline int metal_uart_putc(struct metal_uart *uart, unsigned char c) { return uart->vtable->putc(uart, c); }
+
+/*!
+ * @brief Read a character sent over the UART
+ * @param uart The UART device handle
+ * @param c The varible to hold the read character
+ * @return 0 upon success
+ */
+inline int metal_uart_getc(struct metal_uart *uart, unsigned char *c) { return uart->vtable->getc(uart, c); }
+
+/*!
+ * @brief Get the baud rate of the UART peripheral
+ * @param uart The UART device handle
+ * @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); }
+
+/*!
+ * @brief Set the baud rate of the UART peripheral
+ * @param uart The UART device handle
+ * @param baud_rate The baud rate to configure
+ * @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); }
+
+/*!
+ * @brief Get the interrupt controller of the UART peripheral
+ *
+ * Get the interrupt controller for the UART peripheral. The interrupt
+ * controller must be initialized before any interrupts can be registered
+ * or enabled with it.
+ *
+ * @param uart The UART device handle
+ * @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); }
+
+/*!
+ * @brief Get the interrupt ID of the UART controller
+ * @param uart The UART device handle
+ * @return The UART interrupt id
+ */
+inline int metal_uart_get_interrupt_id(struct metal_uart *uart) { return uart->vtable->get_interrupt_id(uart); }
+
+#endif
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+/* ----------------------------------- */
+/* ----------------------------------- */
+
+#ifndef ASSEMBLY
+
+#ifndef SIFIVE_HIFIVE1_REVB____METAL_INLINE_H
+#define SIFIVE_HIFIVE1_REVB____METAL_INLINE_H
+
+#include <metal/machine.h>
+
+
+/* --------------------- fixed_clock ------------ */
+extern inline unsigned long __metal_driver_fixed_clock_rate(const struct metal_clock *clock);
+
+
+/* --------------------- fixed_factor_clock ------------ */
+
+
+/* --------------------- 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_size(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 int __metal_driver_sifive_clint0_interrupt_lines(struct metal_interrupt *controller, int idx);
+
+
+/* --------------------- 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 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);
+
+
+/* --------------------- 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_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_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 int __metal_driver_sifive_plic0_interrupt_lines(struct metal_interrupt *controller, int idx);
+
+
+/* --------------------- sifive_clic0 ------------ */
+
+
+/* --------------------- 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_gpio0 ------------ */
+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 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 int __metal_driver_sifive_gpio0_interrupt_lines(struct metal_gpio *gpio, int idx);
+
+
+/* --------------------- sifive_gpio_button ------------ */
+
+
+/* --------------------- sifive_gpio_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 char * __metal_driver_sifive_gpio_led_label(struct metal_led *led);
+
+
+/* --------------------- sifive_gpio_switch ------------ */
+
+
+/* --------------------- 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_size(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_source_selector(struct metal_spi *spi);
+
+
+/* --------------------- sifive_test0 ------------ */
+
+
+/* --------------------- 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_size(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 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_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_source_selector(struct metal_uart *uart);
+
+
+/* --------------------- 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_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 long __metal_driver_sifive_fe310_g000_hfrosc_config_offset(const struct metal_clock *clock);
+
+
+/* --------------------- 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_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);
+
+
+/* --------------------- 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_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 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 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( );
+
+
+/* --------------------- fe310_g000_prci ------------ */
+extern inline long __metal_driver_sifive_fe310_g000_prci_base( );
+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( );
+
+
+/* --------------------- sifive_fu540_c000_l2 ------------ */
+
+
+/* From clock@0 */
+struct __metal_driver_fixed_clock __metal_dt_clock_0 = {
+ .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
+};
+
+/* From clock@2 */
+struct __metal_driver_fixed_clock __metal_dt_clock_2 = {
+ .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
+};
+
+/* From clock@5 */
+struct __metal_driver_fixed_clock __metal_dt_clock_5 = {
+ .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
+};
+
+struct metal_memory __metal_dt_mem_dtim_80000000 = {
+ ._base_address = 2147483648UL,
+ ._size = 16384UL,
+ ._attrs = {
+ .R = 1,
+ .W = 1,
+ .X = 1,
+ .C = 1,
+ .A = 1},
+};
+
+struct metal_memory __metal_dt_mem_spi_10014000 = {
+ ._base_address = 536870912UL,
+ ._size = 500000UL,
+ ._attrs = {
+ .R = 1,
+ .W = 1,
+ .X = 1,
+ .C = 1,
+ .A = 1},
+};
+
+/* From clint@2000000 */
+struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000 = {
+ .controller.vtable = &__metal_driver_vtable_riscv_clint0.clint_vtable,
+ .init_done = 0,
+};
+
+/* From cpu@0 */
+struct __metal_driver_cpu __metal_dt_cpu_0 = {
+ .cpu.vtable = &__metal_driver_vtable_cpu.cpu_vtable,
+};
+
+/* From interrupt_controller */
+struct __metal_driver_riscv_cpu_intc __metal_dt_cpu_0_interrupt_controller = {
+ .controller.vtable = &__metal_driver_vtable_riscv_cpu_intc.controller_vtable,
+ .init_done = 0,
+};
+
+/* From interrupt_controller@c000000 */
+struct __metal_driver_riscv_plic0 __metal_dt_interrupt_controller_c000000 = {
+ .controller.vtable = &__metal_driver_vtable_riscv_plic0.plic_vtable,
+ .init_done = 0,
+};
+
+/* From local_external_interrupts_0 */
+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 */
+struct __metal_driver_sifive_gpio0 __metal_dt_gpio_10012000 = {
+ .gpio.vtable = &__metal_driver_vtable_sifive_gpio0.gpio,
+};
+
+/* From led@0red */
+struct __metal_driver_sifive_gpio_led __metal_dt_led_0red = {
+ .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
+};
+
+/* From led@0green */
+struct __metal_driver_sifive_gpio_led __metal_dt_led_0green = {
+ .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
+};
+
+/* From led@0blue */
+struct __metal_driver_sifive_gpio_led __metal_dt_led_0blue = {
+ .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
+};
+
+/* From spi@10014000 */
+struct __metal_driver_sifive_spi0 __metal_dt_spi_10014000 = {
+ .spi.vtable = &__metal_driver_vtable_sifive_spi0.spi,
+};
+
+/* From serial@10013000 */
+struct __metal_driver_sifive_uart0 __metal_dt_serial_10013000 = {
+ .uart.vtable = &__metal_driver_vtable_sifive_uart0.uart,
+};
+
+/* From clock@3 */
+struct __metal_driver_sifive_fe310_g000_hfrosc __metal_dt_clock_3 = {
+ .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfrosc.clock,
+};
+
+/* From clock@1 */
+struct __metal_driver_sifive_fe310_g000_hfxosc __metal_dt_clock_1 = {
+ .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfxosc.clock,
+};
+
+/* From clock@4 */
+struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4 = {
+ .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_pll.clock,
+};
+
+/* From prci@10008000 */
+struct __metal_driver_sifive_fe310_g000_prci __metal_dt_prci_10008000 = {
+};
+
+
+#endif /* SIFIVE_HIFIVE1_REVB____METAL_INLINE_H*/
+#endif /* ! ASSEMBLY */
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+/* ----------------------------------- */
+/* ----------------------------------- */
+
+#ifndef SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H
+#define SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H
+
+/* From clock@0 */
+#define METAL_FIXED_CLOCK_0_CLOCK_FREQUENCY 16000000UL
+
+/* From clock@2 */
+#define METAL_FIXED_CLOCK_2_CLOCK_FREQUENCY 72000000UL
+
+/* From clock@5 */
+#define METAL_FIXED_CLOCK_5_CLOCK_FREQUENCY 32000000UL
+
+#define METAL_FIXED_CLOCK
+
+/* From clint@2000000 */
+#define METAL_RISCV_CLINT0_2000000_BASE_ADDRESS 33554432UL
+#define METAL_RISCV_CLINT0_0_BASE_ADDRESS 33554432UL
+#define METAL_RISCV_CLINT0_2000000_SIZE 65536UL
+#define METAL_RISCV_CLINT0_0_SIZE 65536UL
+
+#define METAL_RISCV_CLINT0
+#define METAL_RISCV_CLINT0_MSIP_BASE 0UL
+#define METAL_RISCV_CLINT0_MTIMECMP_BASE 16384UL
+#define METAL_RISCV_CLINT0_MTIME 49144UL
+
+/* From interrupt_controller@c000000 */
+#define METAL_RISCV_PLIC0_C000000_BASE_ADDRESS 201326592UL
+#define METAL_RISCV_PLIC0_0_BASE_ADDRESS 201326592UL
+#define METAL_RISCV_PLIC0_C000000_SIZE 67108864UL
+#define METAL_RISCV_PLIC0_0_SIZE 67108864UL
+#define METAL_RISCV_PLIC0_C000000_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_0_RISCV_NDEV 27UL
+
+#define METAL_RISCV_PLIC0
+#define METAL_RISCV_PLIC0_PRIORITY_BASE 0UL
+#define METAL_RISCV_PLIC0_PENDING_BASE 4096UL
+#define METAL_RISCV_PLIC0_ENABLE_BASE 8192UL
+#define METAL_RISCV_PLIC0_THRESHOLD 2097152UL
+#define METAL_RISCV_PLIC0_CLAIM 2097156UL
+
+/* 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_AON0
+#define METAL_SIFIVE_AON0_WDOGCFG 0UL
+#define METAL_SIFIVE_AON0_WDOGCOUNT 8UL
+#define METAL_SIFIVE_AON0_WDOGS 16UL
+#define METAL_SIFIVE_AON0_WDOGFEED 24UL
+#define METAL_SIFIVE_AON0_WDOGKEY 28UL
+#define METAL_SIFIVE_AON0_WDOGCMP 32UL
+#define METAL_SIFIVE_AON0_RTCCFG 64UL
+#define METAL_SIFIVE_AON0_RTCLO 72UL
+#define METAL_SIFIVE_AON0_RTCHI 72UL
+#define METAL_SIFIVE_AON0_RTCS 80UL
+#define METAL_SIFIVE_AON0_RTCCMP 96UL
+#define METAL_SIFIVE_AON0_LFROSCCFG 112UL
+#define METAL_SIFIVE_AON0_BACKUP0 128UL
+#define METAL_SIFIVE_AON0_BACKUP1 132UL
+#define METAL_SIFIVE_AON0_BACKUP2 136UL
+#define METAL_SIFIVE_AON0_BACKUP3 140UL
+#define METAL_SIFIVE_AON0_BACKUP4 144UL
+#define METAL_SIFIVE_AON0_BACKUP5 148UL
+#define METAL_SIFIVE_AON0_BACKUP6 152UL
+#define METAL_SIFIVE_AON0_BACKUP7 152UL
+#define METAL_SIFIVE_AON0_BACKUP8 160UL
+#define METAL_SIFIVE_AON0_BACKUP9 164UL
+#define METAL_SIFIVE_AON0_BACKUP10 168UL
+#define METAL_SIFIVE_AON0_BACKUP11 172UL
+#define METAL_SIFIVE_AON0_BACKUP12 176UL
+#define METAL_SIFIVE_AON0_BACKUP13 180UL
+#define METAL_SIFIVE_AON0_BACKUP14 184UL
+#define METAL_SIFIVE_AON0_BACKUP15 188UL
+#define METAL_SIFIVE_AON0_BACKUP16 192UL
+#define METAL_SIFIVE_AON0_BACKUP17 196UL
+#define METAL_SIFIVE_AON0_BACKUP18 200UL
+#define METAL_SIFIVE_AON0_BACKUP19 204UL
+#define METAL_SIFIVE_AON0_BACKUP20 208UL
+#define METAL_SIFIVE_AON0_BACKUP21 212UL
+#define METAL_SIFIVE_AON0_BACKUP22 216UL
+#define METAL_SIFIVE_AON0_BACKUP23 220UL
+#define METAL_SIFIVE_AON0_BACKUP24 224UL
+#define METAL_SIFIVE_AON0_BACKUP25 228UL
+#define METAL_SIFIVE_AON0_BACKUP26 232UL
+#define METAL_SIFIVE_AON0_BACKUP27 236UL
+#define METAL_SIFIVE_AON0_BACKUP28 240UL
+#define METAL_SIFIVE_AON0_BACKUP29 244UL
+#define METAL_SIFIVE_AON0_BACKUP30 248UL
+#define METAL_SIFIVE_AON0_BACKUP31 252UL
+#define METAL_SIFIVE_AON0_PMU_WAKEUP_BASE 256UL
+#define METAL_SIFIVE_AON0_PWM_SLEEP_BASE 288UL
+#define METAL_SIFIVE_AON0_PMUIE 320UL
+#define METAL_SIFIVE_AON0_PMUCAUSE 324UL
+#define METAL_SIFIVE_AON0_PMUSLEEP 328UL
+#define METAL_SIFIVE_AON0_PMUKEY 332UL
+
+/* From clock@3 */
+
+#define METAL_SIFIVE_FE310_G000_HFROSC
+
+/* From clock@1 */
+
+#define METAL_SIFIVE_FE310_G000_HFXOSC
+
+/* From prci@10008000 */
+#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_10008000_SIZE 32768UL
+#define METAL_SIFIVE_FE310_G000_PRCI_0_SIZE 32768UL
+
+#define METAL_SIFIVE_FE310_G000_PRCI
+#define METAL_SIFIVE_FE310_G000_PRCI_HFROSCCFG 0UL
+#define METAL_SIFIVE_FE310_G000_PRCI_HFXOSCCFG 4UL
+#define METAL_SIFIVE_FE310_G000_PRCI_PLLCFG 8UL
+#define METAL_SIFIVE_FE310_G000_PRCI_PLLOUTDIV 12UL
+
+/* From clock@4 */
+#define METAL_SIFIVE_FE310_G000_PLL_4_CLOCK_FREQUENCY 16000000UL
+
+#define METAL_SIFIVE_FE310_G000_PLL
+
+/* From gpio@10012000 */
+#define METAL_SIFIVE_GPIO0_10012000_BASE_ADDRESS 268509184UL
+#define METAL_SIFIVE_GPIO0_0_BASE_ADDRESS 268509184UL
+#define METAL_SIFIVE_GPIO0_10012000_SIZE 4096UL
+#define METAL_SIFIVE_GPIO0_0_SIZE 4096UL
+
+#define METAL_SIFIVE_GPIO0
+#define METAL_SIFIVE_GPIO0_VALUE 0UL
+#define METAL_SIFIVE_GPIO0_INPUT_EN 4UL
+#define METAL_SIFIVE_GPIO0_OUTPUT_EN 8UL
+#define METAL_SIFIVE_GPIO0_PORT 12UL
+#define METAL_SIFIVE_GPIO0_PUE 16UL
+#define METAL_SIFIVE_GPIO0_DS 20UL
+#define METAL_SIFIVE_GPIO0_RISE_IE 24UL
+#define METAL_SIFIVE_GPIO0_RISE_IP 28UL
+#define METAL_SIFIVE_GPIO0_FALL_IE 32UL
+#define METAL_SIFIVE_GPIO0_FALL_IP 36UL
+#define METAL_SIFIVE_GPIO0_HIGH_IE 40UL
+#define METAL_SIFIVE_GPIO0_HIGH_IP 44UL
+#define METAL_SIFIVE_GPIO0_LOW_IE 48UL
+#define METAL_SIFIVE_GPIO0_LOW_IP 52UL
+#define METAL_SIFIVE_GPIO0_IOF_EN 56UL
+#define METAL_SIFIVE_GPIO0_IOF_SEL 60UL
+#define METAL_SIFIVE_GPIO0_OUT_XOR 64UL
+
+/* From led@0red */
+
+/* From led@0green */
+
+/* From led@0blue */
+
+#define METAL_SIFIVE_GPIO_LEDS
+
+/* From i2c@10016000 */
+#define METAL_SIFIVE_I2C0_10016000_BASE_ADDRESS 268525568UL
+#define METAL_SIFIVE_I2C0_0_BASE_ADDRESS 268525568UL
+#define METAL_SIFIVE_I2C0_10016000_SIZE 4096UL
+#define METAL_SIFIVE_I2C0_0_SIZE 4096UL
+
+#define METAL_SIFIVE_I2C0
+#define METAL_SIFIVE_I2C0_PRESCALE_LOW 0UL
+#define METAL_SIFIVE_I2C0_PRESCALE_HIGH 4UL
+#define METAL_SIFIVE_I2C0_CONTROL 8UL
+#define METAL_SIFIVE_I2C0_TRANSMIT 12UL
+#define METAL_SIFIVE_I2C0_RECEIVE 12UL
+#define METAL_SIFIVE_I2C0_COMMAND 16UL
+#define METAL_SIFIVE_I2C0_STATUS 16UL
+
+/* From local_external_interrupts_0 */
+
+#define METAL_SIFIVE_LOCAL_EXTERNAL_INTERRUPTS0
+
+/* From pwm@10015000 */
+#define METAL_SIFIVE_PWM0_10015000_BASE_ADDRESS 268521472UL
+#define METAL_SIFIVE_PWM0_0_BASE_ADDRESS 268521472UL
+#define METAL_SIFIVE_PWM0_10015000_SIZE 4096UL
+#define METAL_SIFIVE_PWM0_0_SIZE 4096UL
+
+#define METAL_SIFIVE_PWM0
+#define METAL_SIFIVE_PWM0_PWMCFG 0UL
+#define METAL_SIFIVE_PWM0_PWMCOUNT 8UL
+#define METAL_SIFIVE_PWM0_PWMS 16UL
+#define METAL_SIFIVE_PWM0_PWMCMP0 32UL
+#define METAL_SIFIVE_PWM0_PWMCMP1 36UL
+#define METAL_SIFIVE_PWM0_PWMCMP2 40UL
+#define METAL_SIFIVE_PWM0_PWMCMP3 44UL
+
+/* From spi@10014000 */
+#define METAL_SIFIVE_SPI0_10014000_BASE_ADDRESS 268517376UL
+#define METAL_SIFIVE_SPI0_0_BASE_ADDRESS 268517376UL
+#define METAL_SIFIVE_SPI0_10014000_SIZE 4096UL
+#define METAL_SIFIVE_SPI0_0_SIZE 4096UL
+
+#define METAL_SIFIVE_SPI0
+#define METAL_SIFIVE_SPI0_SCKDIV 0UL
+#define METAL_SIFIVE_SPI0_SCKMODE 4UL
+#define METAL_SIFIVE_SPI0_CSID 16UL
+#define METAL_SIFIVE_SPI0_CSDEF 20UL
+#define METAL_SIFIVE_SPI0_CSMODE 24UL
+#define METAL_SIFIVE_SPI0_DELAY0 40UL
+#define METAL_SIFIVE_SPI0_DELAY1 44UL
+#define METAL_SIFIVE_SPI0_FMT 64UL
+#define METAL_SIFIVE_SPI0_TXDATA 72UL
+#define METAL_SIFIVE_SPI0_RXDATA 76UL
+#define METAL_SIFIVE_SPI0_TXMARK 80UL
+#define METAL_SIFIVE_SPI0_RXMARK 84UL
+#define METAL_SIFIVE_SPI0_FCTRL 96UL
+#define METAL_SIFIVE_SPI0_FFMT 100UL
+#define METAL_SIFIVE_SPI0_IE 112UL
+#define METAL_SIFIVE_SPI0_IP 116UL
+
+/* From serial@10013000 */
+#define METAL_SIFIVE_UART0_10013000_BASE_ADDRESS 268513280UL
+#define METAL_SIFIVE_UART0_0_BASE_ADDRESS 268513280UL
+#define METAL_SIFIVE_UART0_10013000_SIZE 4096UL
+#define METAL_SIFIVE_UART0_0_SIZE 4096UL
+
+#define METAL_SIFIVE_UART0
+#define METAL_SIFIVE_UART0_TXDATA 0UL
+#define METAL_SIFIVE_UART0_RXDATA 4UL
+#define METAL_SIFIVE_UART0_TXCTRL 8UL
+#define METAL_SIFIVE_UART0_RXCTRL 12UL
+#define METAL_SIFIVE_UART0_IE 16UL
+#define METAL_SIFIVE_UART0_IP 20UL
+#define METAL_SIFIVE_UART0_DIV 24UL
+
+#endif /* SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H*/
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+/* ----------------------------------- */
+/* ----------------------------------- */
+
+OUTPUT_ARCH("riscv")
+
+ENTRY(_enter)
+
+MEMORY
+{
+ ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 0x4000
+ flash (rxai!w) : ORIGIN = 0x20010000, LENGTH = 0x6a120
+}
+
+PHDRS
+{
+ flash PT_LOAD;
+ ram_init PT_LOAD;
+ itim_init PT_LOAD;
+ ram PT_NULL;
+ itim PT_NULL;
+}
+
+SECTIONS
+{
+ __stack_size = DEFINED(__stack_size) ? __stack_size : 0x400;
+ PROVIDE(__stack_size = __stack_size);
+ __heap_size = DEFINED(__heap_size) ? __heap_size : 0x4;
+ PROVIDE(__metal_boot_hart = 0);
+ PROVIDE(__metal_chicken_bit = 0);
+
+
+ .init :
+ {
+ KEEP (*(.text.metal.init.enter))
+ KEEP (*(SORT_NONE(.init)))
+ KEEP (*(.text.libgloss.start))
+ } >flash AT>flash :flash
+
+
+ .text :
+ {
+ *(.text.unlikely .text.unlikely.*)
+ *(.text.startup .text.startup.*)
+ *(.text .text.*)
+ *(.itim .itim.*)
+ *(.gnu.linkonce.t.*)
+ } >flash AT>flash :flash
+
+
+ .fini :
+ {
+ KEEP (*(SORT_NONE(.fini)))
+ } >flash AT>flash :flash
+
+
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
+
+ .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
+
+
+}
+
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+/* ----------------------------------- */
+/* ----------------------------------- */
+
+#ifndef ASSEMBLY
+
+#include <metal/machine/platform.h>
+
+#ifdef __METAL_MACHINE_MACROS
+
+#ifndef MACROS_IF_SIFIVE_HIFIVE1_REVB____METAL_H
+#define MACROS_IF_SIFIVE_HIFIVE1_REVB____METAL_H
+
+#define __METAL_CLINT_NUM_PARENTS 2
+
+#ifndef __METAL_CLINT_NUM_PARENTS
+#define __METAL_CLINT_NUM_PARENTS 0
+#endif
+#define __METAL_PLIC_SUBINTERRUPTS 27
+
+#define __METAL_PLIC_NUM_PARENTS 1
+
+#ifndef __METAL_PLIC_SUBINTERRUPTS
+#define __METAL_PLIC_SUBINTERRUPTS 0
+#endif
+#ifndef __METAL_PLIC_NUM_PARENTS
+#define __METAL_PLIC_NUM_PARENTS 0
+#endif
+#ifndef __METAL_CLIC_SUBINTERRUPTS
+#define __METAL_CLIC_SUBINTERRUPTS 0
+#endif
+
+#endif /* MACROS_IF_SIFIVE_HIFIVE1_REVB____METAL_H*/
+
+#else /* ! __METAL_MACHINE_MACROS */
+
+#ifndef MACROS_ELSE_SIFIVE_HIFIVE1_REVB____METAL_H
+#define MACROS_ELSE_SIFIVE_HIFIVE1_REVB____METAL_H
+
+#define __METAL_CLINT_2000000_INTERRUPTS 2
+
+#define METAL_MAX_CLINT_INTERRUPTS 2
+
+#define __METAL_CLINT_NUM_PARENTS 2
+
+#define __METAL_INTERRUPT_CONTROLLER_C000000_INTERRUPTS 1
+
+#define __METAL_PLIC_SUBINTERRUPTS 27
+
+#define METAL_MAX_PLIC_INTERRUPTS 1
+
+#define __METAL_PLIC_NUM_PARENTS 1
+
+#define __METAL_CLIC_SUBINTERRUPTS 0
+#define METAL_MAX_CLIC_INTERRUPTS 0
+
+#define __METAL_LOCAL_EXTERNAL_INTERRUPTS_0_INTERRUPTS 16
+
+#define METAL_MAX_LOCAL_EXT_INTERRUPTS 16
+
+#define METAL_MAX_GLOBAL_EXT_INTERRUPTS 0
+
+#define __METAL_GPIO_10012000_INTERRUPTS 16
+
+#define METAL_MAX_GPIO_INTERRUPTS 16
+
+#define __METAL_SERIAL_10013000_INTERRUPTS 1
+
+#define METAL_MAX_UART_INTERRUPTS 1
+
+
+#include <metal/drivers/fixed-clock.h>
+#include <metal/memory.h>
+#include <metal/drivers/riscv_clint0.h>
+#include <metal/drivers/riscv_cpu.h>
+#include <metal/drivers/riscv_plic0.h>
+#include <metal/pmp.h>
+#include <metal/drivers/sifive_local-external-interrupts0.h>
+#include <metal/drivers/sifive_gpio0.h>
+#include <metal/drivers/sifive_gpio-leds.h>
+#include <metal/drivers/sifive_spi0.h>
+#include <metal/drivers/sifive_uart0.h>
+#include <metal/drivers/sifive_fe310-g000_hfrosc.h>
+#include <metal/drivers/sifive_fe310-g000_hfxosc.h>
+#include <metal/drivers/sifive_fe310-g000_pll.h>
+#include <metal/drivers/sifive_fe310-g000_prci.h>
+
+/* From clock@0 */
+struct __metal_driver_fixed_clock __metal_dt_clock_0;
+
+/* From clock@2 */
+struct __metal_driver_fixed_clock __metal_dt_clock_2;
+
+/* From clock@5 */
+struct __metal_driver_fixed_clock __metal_dt_clock_5;
+
+struct metal_memory __metal_dt_mem_dtim_80000000;
+
+struct metal_memory __metal_dt_mem_spi_10014000;
+
+/* From clint@2000000 */
+struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000;
+
+/* From cpu@0 */
+struct __metal_driver_cpu __metal_dt_cpu_0;
+
+struct __metal_driver_riscv_cpu_intc __metal_dt_cpu_0_interrupt_controller;
+
+/* From interrupt_controller@c000000 */
+struct __metal_driver_riscv_plic0 __metal_dt_interrupt_controller_c000000;
+
+struct metal_pmp __metal_dt_pmp;
+
+/* From local_external_interrupts_0 */
+struct __metal_driver_sifive_local_external_interrupts0 __metal_dt_local_external_interrupts_0;
+
+/* From gpio@10012000 */
+struct __metal_driver_sifive_gpio0 __metal_dt_gpio_10012000;
+
+/* From led@0red */
+struct __metal_driver_sifive_gpio_led __metal_dt_led_0red;
+
+/* From led@0green */
+struct __metal_driver_sifive_gpio_led __metal_dt_led_0green;
+
+/* From led@0blue */
+struct __metal_driver_sifive_gpio_led __metal_dt_led_0blue;
+
+/* From spi@10014000 */
+struct __metal_driver_sifive_spi0 __metal_dt_spi_10014000;
+
+/* From serial@10013000 */
+struct __metal_driver_sifive_uart0 __metal_dt_serial_10013000;
+
+/* From clock@3 */
+struct __metal_driver_sifive_fe310_g000_hfrosc __metal_dt_clock_3;
+
+/* From clock@1 */
+struct __metal_driver_sifive_fe310_g000_hfxosc __metal_dt_clock_1;
+
+/* From clock@4 */
+struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4;
+
+/* From prci@10008000 */
+struct __metal_driver_sifive_fe310_g000_prci __metal_dt_prci_10008000;
+
+
+
+/* --------------------- fixed_clock ------------ */
+static inline unsigned long __metal_driver_fixed_clock_rate(const struct metal_clock *clock)
+{
+ if ((uintptr_t)clock == (uintptr_t)&__metal_dt_clock_0) {
+ return METAL_FIXED_CLOCK_0_CLOCK_FREQUENCY;
+ }
+ else if ((uintptr_t)clock == (uintptr_t)&__metal_dt_clock_2) {
+ return METAL_FIXED_CLOCK_2_CLOCK_FREQUENCY;
+ }
+ else if ((uintptr_t)clock == (uintptr_t)&__metal_dt_clock_5) {
+ return METAL_FIXED_CLOCK_5_CLOCK_FREQUENCY;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+
+/* --------------------- fixed_factor_clock ------------ */
+
+
+/* --------------------- sifive_clint0 ------------ */
+static inline unsigned long __metal_driver_sifive_clint0_control_base(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_clint_2000000) {
+ return METAL_RISCV_CLINT0_2000000_BASE_ADDRESS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline unsigned long __metal_driver_sifive_clint0_control_size(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_clint_2000000) {
+ return METAL_RISCV_CLINT0_2000000_SIZE;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_clint0_num_interrupts(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_clint_2000000) {
+ return METAL_MAX_CLINT_INTERRUPTS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline struct metal_interrupt * __metal_driver_sifive_clint0_interrupt_parents(struct metal_interrupt *controller, int idx)
+{
+ if (idx == 0) {
+ return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
+ }
+ else if (idx == 1) {
+ return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static inline int __metal_driver_sifive_clint0_interrupt_lines(struct metal_interrupt *controller, int idx)
+{
+ if (idx == 0) {
+ return 3;
+ }
+ else if (idx == 1) {
+ return 7;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+
+/* --------------------- cpu ------------ */
+static inline int __metal_driver_cpu_hartid(struct metal_cpu *cpu)
+{
+ if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
+ return 0;
+ }
+ else {
+ return -1;
+ }
+}
+
+static inline int __metal_driver_cpu_timebase(struct metal_cpu *cpu)
+{
+ if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
+ return 1000000;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline struct metal_interrupt * __metal_driver_cpu_interrupt_controller(struct metal_cpu *cpu)
+{
+ if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
+ return &__metal_dt_cpu_0_interrupt_controller.controller;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static inline int __metal_driver_cpu_num_pmp_regions(struct metal_cpu *cpu)
+{
+ if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
+ return 8;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+
+/* --------------------- sifive_plic0 ------------ */
+static inline unsigned long __metal_driver_sifive_plic0_control_base(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
+ return METAL_RISCV_PLIC0_C000000_BASE_ADDRESS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline unsigned long __metal_driver_sifive_plic0_control_size(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
+ return METAL_RISCV_PLIC0_C000000_SIZE;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_plic0_num_interrupts(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
+ return METAL_RISCV_PLIC0_C000000_RISCV_NDEV;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_plic0_max_priority(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
+ return METAL_RISCV_PLIC0_C000000_RISCV_MAX_PRIORITY;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline struct metal_interrupt * __metal_driver_sifive_plic0_interrupt_parents(struct metal_interrupt *controller, int idx)
+{
+ if (idx == 0) {
+ return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
+ }
+ else if (idx == 0) {
+ return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static inline int __metal_driver_sifive_plic0_interrupt_lines(struct metal_interrupt *controller, int idx)
+{
+ if (idx == 0) {
+ return 11;
+ }
+ else if (idx == 0) {
+ return 11;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+
+/* --------------------- sifive_clic0 ------------ */
+
+
+/* --------------------- sifive_local_external_interrupts0 ------------ */
+static inline struct metal_interrupt * __metal_driver_sifive_local_external_interrupts0_interrupt_parent(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_local_external_interrupts_0) {
+ return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static inline int __metal_driver_sifive_local_external_interrupts0_num_interrupts(struct metal_interrupt *controller)
+{
+ if ((uintptr_t)controller == (uintptr_t)&__metal_dt_local_external_interrupts_0) {
+ return METAL_MAX_LOCAL_EXT_INTERRUPTS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_local_external_interrupts0_interrupt_lines(struct metal_interrupt *controller, int idx)
+{
+ if (idx == 0) {
+ return 16;
+ }
+ else if (idx == 1) {
+ return 17;
+ }
+ else if (idx == 2) {
+ return 18;
+ }
+ else if (idx == 3) {
+ return 19;
+ }
+ else if (idx == 4) {
+ return 20;
+ }
+ else if (idx == 5) {
+ return 21;
+ }
+ else if (idx == 6) {
+ return 22;
+ }
+ else if (idx == 7) {
+ return 23;
+ }
+ else if (idx == 8) {
+ return 24;
+ }
+ else if (idx == 9) {
+ return 25;
+ }
+ else if (idx == 10) {
+ return 26;
+ }
+ else if (idx == 11) {
+ return 27;
+ }
+ else if (idx == 12) {
+ return 28;
+ }
+ else if (idx == 13) {
+ return 29;
+ }
+ else if (idx == 14) {
+ return 30;
+ }
+ else if (idx == 15) {
+ return 31;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+
+/* --------------------- sifive_global_external_interrupts0 ------------ */
+
+
+/* --------------------- sifive_gpio0 ------------ */
+static inline unsigned long __metal_driver_sifive_gpio0_base(struct metal_gpio *gpio)
+{
+ if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
+ return METAL_SIFIVE_GPIO0_10012000_BASE_ADDRESS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline unsigned long __metal_driver_sifive_gpio0_size(struct metal_gpio *gpio)
+{
+ if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
+ return METAL_SIFIVE_GPIO0_10012000_SIZE;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_gpio0_num_interrupts(struct metal_gpio *gpio)
+{
+ if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
+ return METAL_MAX_GPIO_INTERRUPTS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline struct metal_interrupt * __metal_driver_sifive_gpio0_interrupt_parent(struct metal_gpio *gpio)
+{
+ if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
+ return (struct metal_interrupt *)&__metal_dt_interrupt_controller_c000000.controller;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_gpio0_interrupt_lines(struct metal_gpio *gpio, int idx)
+{
+ if (((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 0)) {
+ return 7;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 1))) {
+ return 8;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 2))) {
+ return 9;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 3))) {
+ return 10;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 4))) {
+ return 11;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 5))) {
+ return 12;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 6))) {
+ return 13;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 7))) {
+ return 14;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 8))) {
+ return 15;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 9))) {
+ return 16;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 10))) {
+ return 17;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 11))) {
+ return 18;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 12))) {
+ return 19;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 13))) {
+ return 20;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 14))) {
+ return 21;
+ }
+ else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 15))) {
+ return 22;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+
+/* --------------------- sifive_gpio_button ------------ */
+
+
+/* --------------------- sifive_gpio_led ------------ */
+static inline struct metal_gpio * __metal_driver_sifive_gpio_led_gpio(struct metal_led *led)
+{
+ if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0red) {
+ return (struct metal_gpio *)&__metal_dt_gpio_10012000;
+ }
+ else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0green) {
+ return (struct metal_gpio *)&__metal_dt_gpio_10012000;
+ }
+ else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0blue) {
+ return (struct metal_gpio *)&__metal_dt_gpio_10012000;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static inline int __metal_driver_sifive_gpio_led_pin(struct metal_led *led)
+{
+ if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0red) {
+ return 22;
+ }
+ else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0green) {
+ return 19;
+ }
+ else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0blue) {
+ return 21;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline char * __metal_driver_sifive_gpio_led_label(struct metal_led *led)
+{
+ if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0red) {
+ return "LD0red";
+ }
+ else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0green) {
+ return "LD0green";
+ }
+ else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0blue) {
+ return "LD0blue";
+ }
+ else {
+ return "";
+ }
+}
+
+
+
+/* --------------------- sifive_gpio_switch ------------ */
+
+
+/* --------------------- sifive_spi0 ------------ */
+static inline unsigned long __metal_driver_sifive_spi0_control_base(struct metal_spi *spi)
+{
+ if ((uintptr_t)spi == (uintptr_t)&__metal_dt_spi_10014000) {
+ return METAL_SIFIVE_SPI0_10014000_BASE_ADDRESS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline unsigned long __metal_driver_sifive_spi0_control_size(struct metal_spi *spi)
+{
+ if ((uintptr_t)spi == (uintptr_t)&__metal_dt_spi_10014000) {
+ return METAL_SIFIVE_SPI0_10014000_SIZE;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline struct metal_clock * __metal_driver_sifive_spi0_clock(struct metal_spi *spi)
+{
+ return (struct metal_clock *)&__metal_dt_clock_4.clock;
+}
+
+static inline struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_spi0_pinmux(struct metal_spi *spi)
+{
+ return (struct __metal_driver_sifive_gpio0 *)&__metal_dt_gpio_10012000;
+}
+
+static inline unsigned long __metal_driver_sifive_spi0_pinmux_output_selector(struct metal_spi *spi)
+{
+ return 60;
+}
+
+static inline unsigned long __metal_driver_sifive_spi0_pinmux_source_selector(struct metal_spi *spi)
+{
+ return 60;
+}
+
+
+
+/* --------------------- sifive_test0 ------------ */
+
+
+/* --------------------- sifive_uart0 ------------ */
+static inline unsigned long __metal_driver_sifive_uart0_control_base(struct metal_uart *uart)
+{
+ if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
+ return METAL_SIFIVE_UART0_10013000_BASE_ADDRESS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline unsigned long __metal_driver_sifive_uart0_control_size(struct metal_uart *uart)
+{
+ if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
+ return METAL_SIFIVE_UART0_10013000_SIZE;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline int __metal_driver_sifive_uart0_num_interrupts(struct metal_uart *uart)
+{
+ if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
+ return METAL_MAX_UART_INTERRUPTS;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline struct metal_interrupt * __metal_driver_sifive_uart0_interrupt_parent(struct metal_uart *uart)
+{
+ if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
+ return (struct metal_interrupt *)&__metal_dt_interrupt_controller_c000000.controller;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static inline int __metal_driver_sifive_uart0_interrupt_line(struct metal_uart *uart)
+{
+ return 5;
+}
+
+static inline struct metal_clock * __metal_driver_sifive_uart0_clock(struct metal_uart *uart)
+{
+ return (struct metal_clock *)&__metal_dt_clock_4.clock;
+}
+
+static inline struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_uart0_pinmux(struct metal_uart *uart)
+{
+ return (struct __metal_driver_sifive_gpio0 *)&__metal_dt_gpio_10012000;
+}
+
+static inline unsigned long __metal_driver_sifive_uart0_pinmux_output_selector(struct metal_uart *uart)
+{
+ return 196608;
+}
+
+static inline unsigned long __metal_driver_sifive_uart0_pinmux_source_selector(struct metal_uart *uart)
+{
+ return 196608;
+}
+
+
+
+/* --------------------- sifive_fe310_g000_hfrosc ------------ */
+static inline struct metal_clock * __metal_driver_sifive_fe310_g000_hfrosc_ref(const struct metal_clock *clock)
+{
+ return (struct metal_clock *)&__metal_dt_clock_2.clock;
+}
+
+static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_base(const struct metal_clock *clock)
+{
+ return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
+}
+
+static inline const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_vtable(struct metal_clock *clock)
+{
+ return &__metal_driver_vtable_sifive_fe310_g000_prci;
+}
+
+static inline long __metal_driver_sifive_fe310_g000_hfrosc_config_offset(const struct metal_clock *clock)
+{
+ return METAL_SIFIVE_FE310_G000_PRCI_HFROSCCFG;
+}
+
+
+
+/* --------------------- sifive_fe310_g000_hfxosc ------------ */
+static inline struct metal_clock * __metal_driver_sifive_fe310_g000_hfxosc_ref(const struct metal_clock *clock)
+{
+ return (struct metal_clock *)&__metal_dt_clock_0.clock;
+}
+
+static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfxosc_config_base(const struct metal_clock *clock)
+{
+ return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
+}
+
+static inline long __metal_driver_sifive_fe310_g000_hfxosc_config_offset(const struct metal_clock *clock)
+{
+ return METAL_SIFIVE_FE310_G000_PRCI_HFXOSCCFG;
+}
+
+
+
+/* --------------------- sifive_fe310_g000_pll ------------ */
+static inline struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllsel0(const struct metal_clock *clock)
+{
+ return (struct metal_clock *)&__metal_dt_clock_3.clock;
+}
+
+static inline struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllref(const struct metal_clock *clock)
+{
+ return (struct metal_clock *)&__metal_dt_clock_1.clock;
+}
+
+static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_divider_base(const struct metal_clock *clock)
+{
+ return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
+}
+
+static inline long __metal_driver_sifive_fe310_g000_pll_divider_offset(const struct metal_clock *clock)
+{
+ return METAL_SIFIVE_FE310_G000_PRCI_PLLOUTDIV;
+}
+
+static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_config_base( )
+{
+ return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
+}
+
+static inline long __metal_driver_sifive_fe310_g000_pll_config_offset( )
+{
+ return METAL_SIFIVE_FE310_G000_PRCI_PLLCFG;
+}
+
+static inline long __metal_driver_sifive_fe310_g000_pll_init_rate( )
+{
+ return 16000000;
+}
+
+
+
+/* --------------------- sifive_fe310_g000_prci ------------ */
+static inline long __metal_driver_sifive_fe310_g000_prci_base( )
+{
+ return METAL_SIFIVE_FE310_G000_PRCI_10008000_BASE_ADDRESS;
+}
+
+static inline long __metal_driver_sifive_fe310_g000_prci_size( )
+{
+ return METAL_SIFIVE_FE310_G000_PRCI_10008000_SIZE;
+}
+
+static inline const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_prci_vtable( )
+{
+ return &__metal_driver_vtable_sifive_fe310_g000_prci;
+}
+
+
+
+/* --------------------- sifive_fu540_c000_l2 ------------ */
+
+
+#define __METAL_DT_MAX_MEMORIES 2
+
+asm (".weak __metal_memory_table");
+struct metal_memory *__metal_memory_table[] = {
+ &__metal_dt_mem_dtim_80000000,
+ &__metal_dt_mem_spi_10014000};
+
+/* From serial@10013000 */
+#define __METAL_DT_STDOUT_UART_HANDLE (&__metal_dt_serial_10013000.uart)
+
+#define __METAL_DT_SERIAL_10013000_HANDLE (&__metal_dt_serial_10013000.uart)
+
+#define __METAL_DT_STDOUT_UART_BAUD 115200
+
+/* From clint@2000000 */
+#define __METAL_DT_RISCV_CLINT0_HANDLE (&__metal_dt_clint_2000000.controller)
+
+#define __METAL_DT_CLINT_2000000_HANDLE (&__metal_dt_clint_2000000.controller)
+
+#define __METAL_DT_MAX_HARTS 1
+
+asm (".weak __metal_cpu_table");
+struct __metal_driver_cpu *__metal_cpu_table[] = {
+ &__metal_dt_cpu_0};
+
+/* From interrupt_controller@c000000 */
+#define __METAL_DT_RISCV_PLIC0_HANDLE (&__metal_dt_interrupt_controller_c000000.controller)
+
+#define __METAL_DT_INTERRUPT_CONTROLLER_C000000_HANDLE (&__metal_dt_interrupt_controller_c000000.controller)
+
+#define __METAL_DT_PMP_HANDLE (&__metal_dt_pmp)
+
+/* From local_external_interrupts_0 */
+#define __METAL_DT_SIFIVE_LOCAL_EXINTR0_HANDLE (&__metal_dt_local_external_interrupts_0.irc)
+
+#define __METAL_DT_LOCAL_EXTERNAL_INTERRUPTS_0_HANDLE (&__metal_dt_local_external_interrupts_0.irc)
+
+#define __MEE_DT_MAX_GPIOS 1
+
+asm (".weak __metal_gpio_table");
+struct __metal_driver_sifive_gpio0 *__metal_gpio_table[] = {
+ &__metal_dt_gpio_10012000};
+
+#define __METAL_DT_MAX_BUTTONS 0
+
+asm (".weak __metal_button_table");
+struct __metal_driver_sifive_gpio_button *__metal_button_table[] = {
+ NULL };
+#define __METAL_DT_MAX_LEDS 3
+
+asm (".weak __metal_led_table");
+struct __metal_driver_sifive_gpio_led *__metal_led_table[] = {
+ &__metal_dt_led_0red,
+ &__metal_dt_led_0green,
+ &__metal_dt_led_0blue};
+
+#define __METAL_DT_MAX_SWITCHES 0
+
+asm (".weak __metal_switch_table");
+struct __metal_driver_sifive_gpio_switch *__metal_switch_table[] = {
+ NULL };
+#define __METAL_DT_MAX_SPIS 1
+
+asm (".weak __metal_spi_table");
+struct __metal_driver_sifive_spi0 *__metal_spi_table[] = {
+ &__metal_dt_spi_10014000};
+
+/* From clock@4 */
+#define __METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE (&__metal_dt_clock_4)
+
+#define __METAL_DT_CLOCK_4_HANDLE (&__metal_dt_clock_4)
+
+#endif /* MACROS_ELSE_SIFIVE_HIFIVE1_REVB____METAL_H*/
+
+#endif /* ! __METAL_MACHINE_MACROS */
+
+#endif /* ! ASSEMBLY */
--- /dev/null
+[{000214A0-0000-0000-C000-000000000046}]\r
+Prop3=19,11\r
+[InternetShortcut]\r
+IDList=\r
+URL=https://github.com/sifive/freedom-metal-docs\r
--- /dev/null
+/* Copyright (c) 2017-2018 SiFive Inc. All rights reserved.
+
+ This copyrighted material is made available to anyone wishing to use,
+ modify, copy, or redistribute it subject to the terms and conditions
+ of the FreeBSD License. This program is distributed in the hope that
+ it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
+ including the implied warranties of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. A copy of this license is available at
+ http://www.opensource.org/licenses.
+*/
+
+/* crt0.S: Entry point for RISC-V METAL programs. */
+
+.section .text.libgloss.start
+.global _start
+.type _start, @function
+
+ /* _start is defined by the METAL to have been called with the following
+ * arguments:
+ * a0: the hart ID of the currently executing hart. Harts can start at
+ * any arbitrary point, it's the C library's job to ensure the code is
+ * safe.
+ * a1: a pointer to a description of the machine on which this code is
+ * currently executing. This is probably 0 on an embedded system
+ * because they tend to not be dynamically portable. As such, newlib
+ * ignores this argument.
+ * a2: a pointer to a function that must be run after the envirnoment has
+ * been initialized, but before user code can be expected to be run.
+ * If this is 0 then there is no function to be run. */
+_start:
+.cfi_startproc
+.cfi_undefined ra
+
+ /* This is a bit funky: it's not usually sane for _start to return, but in
+ * this case we actually want to in order to signal an error to the METAL. */
+ mv s0, ra
+
+ /* Before doing anything we must initialize the global pointer, as we cannot
+ * safely perform any access that may be relaxed without GP being set. This
+ * is done with relaxation disabled to avoid relaxing the address calculation
+ * to just "addi gp, gp, 0". */
+.option push
+.option norelax
+ la gp, __global_pointer$
+.option pop
+
+ /* The METAL is designed for a bare-metal environment and therefor is expected
+ * 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 */
+ la t0, __metal_boot_hart
+ bne a0, t0, _skip_init
+
+ /* Embedded systems frequently require relocating the data segment before C
+ * code can be run -- for example, the data segment may exist in flash upon
+ * boot and then need to get relocated into a non-persistant writable memory
+ * before C code can execute. If this is the case we do so here. This step
+ * is optional: if the METAL provides an environment in which this relocation
+ * is not necessary then it must simply set metal_segment_data_source_start to
+ * be equal to metal_segment_data_target_start. */
+ la t0, metal_segment_data_source_start
+ la t1, metal_segment_data_target_start
+ la t2, metal_segment_data_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:
+
+ /* Copy the ITIM section */
+ la t0, metal_segment_itim_source_start
+ la t1, metal_segment_itim_target_start
+ la t2, metal_segment_itim_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 ITIM writes
+ complete */
+ fence.i
+
+ /* Zero the BSS segment. */
+ la t1, metal_segment_bss_target_start
+ la t2, metal_segment_bss_target_end
+
+ bge t1, t2, 2f
+
+1:
+#if __riscv_xlen == 32
+ sw x0, 0(t1)
+ addi t1, t1, 4
+ blt t1, t2, 1b
+#else
+ sd x0, 0(t1)
+ addi t1, t1, 8
+ blt t1, t2, 1b
+#endif
+2:
+
+ /* 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
+ * requested to do so. */
+ beqz a2, 1f
+ jalr a2
+1:
+
+ /* The RISC-V port only uses new-style constructors and destructors. */
+ la a0, __libc_fini_array
+ call atexit
+ call __libc_init_array
+
+_skip_init:
+
+ /* Synchronize harts so that secondary harts wait until hart 0 finishes
+ initializing */
+ call __metal_synchronize_harts
+
+ /* Check RISC-V isa and enable FS bits if Floating Point architecture. */
+ csrr a5, misa
+ li a4, 0x10028
+ and a5, a5, a4
+ beqz a5, 1f
+ csrr a5, mstatus
+ lui a4, 0x2
+ or a5, a5, a4
+ csrw mstatus, a5
+ csrwi fcsr, 0
+1:
+
+ /* 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
+ * instead just setup as close to a NOP as we can. */
+ li a0, 1 /* argc=1 */
+ la a1, argv /* argv = {"libgloss", NULL} */
+ la a2, envp /* envp = {NULL} */
+ call secondary_main
+
+ /* Call exit to handle libc's cleanup routines. Under normal contains this
+ * shouldn't even get called, but I'm still not using a tail call here
+ * because returning to the METAL is the right thing to do in pathological
+ * situations. */
+ call exit
+
+ /* And here's where we return. Again, it's a bit odd but the METAL defines
+ * this as a bad idea (ie, as opposed to leaving it undefined) and at this
+ * point it's really the only thing left to do. */
+ mv ra, s0
+ ret
+
+.cfi_endproc
+
+/* RISC-V systems always use __libc_{init,fini}_array, but for compatibility we
+ * define _{init,fini} to do nothing. */
+.global _init
+.type _init, @function
+.global _fini
+.type _fini, @function
+_init:
+_fini:
+ ret
+.size _init, .-_init
+.size _fini, .-_fini
+
+/* By default, secondary_main will cause secondary harts to spin forever.
+ * Users can redefine secondary_main themselves to run code on secondary harts */
+.weak secondary_main
+.global secondary_main
+.type secondary_main, @function
+
+secondary_main:
+ addi sp, sp, -16
+#if __riscv_xlen == 32
+ sw ra, 4(sp)
+#else
+ sd ra, 8(sp)
+#endif
+ csrr t0, mhartid
+ la t1, __metal_boot_hart
+ beq t0, t1, 2f
+1:
+ wfi
+ j 1b
+2:
+ call main
+#if __riscv_xlen == 32
+ lw ra, 4(sp)
+#else
+ ld ra, 8(sp)
+#endif
+ addi sp, sp, 16
+ ret
+
+/* This shim allows main() to be passed a set of arguments that can satisfy the
+ * requirements of the C API. */
+.section .rodata.libgloss.start
+argv:
+.dc.a name
+envp:
+.dc.a 0
+name:
+.asciz "libgloss"
+
--- /dev/null
+#include <errno.h>
+#include <sys/time.h>
+
+int
+nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+/* 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 */
+}
+
--- /dev/null
+#include <errno.h>
+
+int
+_access(const char *file, int mode)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+
+int
+_chdir(const char *path)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+#include <sys/types.h>
+
+int
+_chmod(const char *path, mode_t mode)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <sys/types.h>
+#include <errno.h>
+
+int
+_chown(const char *path, uid_t owner, gid_t group)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+
+int
+_close(int file)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+
+int
+_execve(const char *name, char *const argv[], char *const env[])
+{
+ errno = ENOMEM;
+ return -1;
+}
--- /dev/null
+#include <metal/shutdown.h>
+
+void
+_exit(int exit_status)
+{
+ metal_shutdown(exit_status);
+ while (1);
+}
--- /dev/null
+#include <errno.h>
+
+int
+_faccessat(int dirfd, const char *file, int mode, int flags)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+
+int
+_fork()
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+#include <sys/stat.h>
+
+int
+_fstat(int file, struct stat *st)
+{
+ errno = -ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+#include <sys/stat.h>
+
+int
+_fstatat(int dirfd, const char *file, struct stat *st, int flags)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+#include <sys/timeb.h>
+
+int
+_ftime(struct timeb *tp)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+
+char *
+_getcwd(char *buf, size_t size)
+{
+ errno = -ENOSYS;
+ return NULL;
+}
--- /dev/null
+#include <errno.h>
+
+int
+_getpid()
+{
+ return 1;
+}
--- /dev/null
+#include <errno.h>
+#include <metal/timer.h>
+#include <sys/time.h>
+
+int
+_gettimeofday(struct timeval *tp, void *tzp)
+{
+ int rv;
+ unsigned long long mcc, timebase;
+ rv = metal_timer_get_cyclecount(0, &mcc);
+ if (rv != 0) {
+ return -1;
+ }
+ rv = metal_timer_get_timebase_frequency(0, &timebase);
+ if (rv != 0) {
+ return -1;
+ }
+ tp->tv_sec = mcc / timebase;
+ tp->tv_usec = mcc % timebase * 1000000 / timebase;
+ return 0;
+}
--- /dev/null
+#include <unistd.h>
+
+int
+_isatty(int file)
+{
+ return (file == STDOUT_FILENO);
+}
--- /dev/null
+#include <errno.h>
+
+int
+_kill(int pid, int sig)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+
+int _link(const char *old_name, const char *new_name)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <sys/types.h>
+#include <errno.h>
+
+off_t
+_lseek(int file, off_t ptr, int dir)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+#include <sys/stat.h>
+
+int _lstat(const char *file, struct stat *st)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+
+int
+_open(const char *name, int flags, int mode)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+
+int
+_openat(int dirfd, const char *name, int flags, int mode)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <sys/types.h>
+#include <errno.h>
+
+ssize_t
+_read(int file, void *ptr, size_t len)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <sys/types.h>
+
+/* brk is handled entirely within the C library. This limits METAL programs that
+ * use the C library to be disallowed from dynamically allocating memory
+ * without talking to the C library, but that sounds like a sane way to go
+ * about it. Note that there is no error checking anywhere in this file, users
+ * will simply get the relevant error when actually trying to use the memory
+ * that's been allocated. */
+extern char metal_segment_heap_target_start;
+extern char metal_segment_heap_target_end;
+static char *brk = &metal_segment_heap_target_start;
+
+int
+_brk(void *addr)
+{
+ brk = addr;
+ return 0;
+}
+
+char *
+_sbrk(ptrdiff_t incr)
+{
+ char *old = brk;
+
+ /* If __heap_size == 0, we can't allocate memory on the heap */
+ if(&metal_segment_heap_target_start == &metal_segment_heap_target_end) {
+ return (void *)-1;
+ }
+
+ /* Don't move the break past the end of the heap */
+ if ((brk + incr) < &metal_segment_heap_target_end) {
+ brk += incr;
+ } else {
+ brk = &metal_segment_heap_target_end;
+ return (void *)-1;
+ }
+
+ return old;
+}
--- /dev/null
+#include <errno.h>
+#include <sys/stat.h>
+
+int
+_stat(const char *file, struct stat *st)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <unistd.h>
+#include <time.h>
+
+/* Get configurable system variables. */
+
+long
+_sysconf(int name)
+{
+ switch (name)
+ {
+ case _SC_CLK_TCK:
+ return CLOCKS_PER_SEC;
+ }
+
+ return -1;
+}
--- /dev/null
+#include <sys/times.h>
+#include <sys/time.h>
+#include <metal/timer.h>
+#include <errno.h>
+
+extern int _gettimeofday(struct timeval *, void *);
+
+/* Timing information for current process. From
+ newlib/libc/include/sys/times.h the tms struct fields are as follows:
+
+ - clock_t tms_utime : user clock ticks
+ - clock_t tms_stime : system clock ticks
+ - clock_t tms_cutime : children's user clock ticks
+ - clock_t tms_cstime : children's system clock ticks
+
+ Since maven does not currently support processes we set both of the
+ children's times to zero. Eventually we might want to separately
+ account for user vs system time, but for now we just return the total
+ number of cycles since starting the program. */
+clock_t
+_times(struct tms *buf)
+{
+ int rv;
+ // when called for the first time, initialize t0
+ static struct timeval t0;
+ if (t0.tv_sec == 0 && t0.tv_usec == 0)
+ _gettimeofday (&t0, 0);
+
+ struct timeval t;
+ _gettimeofday (&t, 0);
+
+ unsigned long long timebase;
+ rv = metal_timer_get_timebase_frequency(0, &timebase);
+ if (rv != 0) {
+ return -1;
+ }
+
+ long long utime = (t.tv_sec - t0.tv_sec) * 1000000 + (t.tv_usec - t0.tv_usec);
+ buf->tms_utime = utime * timebase / 1000000;
+ buf->tms_stime = buf->tms_cstime = buf->tms_cutime = 0;
+ return 0;
+}
--- /dev/null
+#include <errno.h>
+
+int
+_unlink(const char *name)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+struct utimbuf;
+
+int
+_utime(const char *path, const struct utimbuf *times)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <errno.h>
+
+int _wait(int *status)
+{
+ errno = ENOSYS;
+ return -1;
+}
--- /dev/null
+#include <metal/tty.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+
+/* Write to a file. */
+ssize_t
+_write(int file, const void *ptr, size_t len)
+{
+ if (file != STDOUT_FILENO) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ const char *bptr = ptr;
+ for (size_t i = 0; i < len; ++i)
+ metal_tty_putc(bptr[i]);
+ return 0;
+}
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__BUTTON_H
+#define METAL__BUTTON_H
+
+/*!
+ * @file button.h
+ * API for interfacing with physical buttons
+ */
+
+#include <metal/interrupt.h>
+
+struct metal_button;
+
+struct metal_button_vtable {
+ int (*button_exist)(struct metal_button *button, char *label);
+ struct metal_interrupt* (*interrupt_controller)(struct metal_button *button);
+ int (*get_interrupt_id)(struct metal_button *button);
+};
+
+/*!
+ * @brief A button device handle
+ *
+ * A `struct metal_button` is an implementation-defined object which represents
+ * a button on a development board.
+ */
+struct metal_button {
+ const struct metal_button_vtable *vtable;
+};
+
+/*!
+ * @brief Get a reference to a button
+ *
+ * @param label The DeviceTree label for the button
+ * @return A handle for the button
+ */
+struct metal_button* metal_button_get(char *label);
+
+
+/*!
+ * @brief Get the interrupt controller for a button
+ *
+ * @param button The handle for the button
+ * @return A pointer to the interrupt controller responsible for handling
+ * button interrupts.
+ */
+__inline__ struct metal_interrupt*
+ metal_button_interrupt_controller(struct metal_button *button) { return button->vtable->interrupt_controller(button); }
+
+/*!
+ * @brief Get the interrupt id for a button
+ *
+ * @param button The handle for the 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); }
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__CACHE_H
+#define METAL__CACHE_H
+
+/*!
+ * @file cache.h
+ *
+ * @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
+ */
+struct metal_cache {
+ const struct __metal_cache_vtable *vtable;
+};
+
+/*!
+ * @brief Initialize a cache
+ * @param cache The handle for the cache to initialize
+ * @param ways The number of ways to enable
+ *
+ * Initializes a cache with the requested number of ways enabled.
+ */
+__inline__ void metal_cache_init(struct metal_cache *cache, int ways) {
+ cache->vtable->init(cache, ways);
+}
+
+/*!
+ * @brief Get the current number of enabled cache ways
+ * @param cache The handle for the cache
+ * @return The current number of enabled cache ways
+ */
+__inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache) {
+ return cache->vtable->get_enabled_ways(cache);
+}
+
+/*!
+ * @brief Enable the requested number of cache ways
+ * @param cache The handle for the cache
+ * @param ways The number of ways to enabled
+ * @return 0 if the ways are successfully enabled
+ */
+__inline__ int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways) {
+ return cache->vtable->set_enabled_ways(cache, 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);
+
+/*!
+ * @brief Flush icache for L1 on the requested core
+ * @param hartid The core to flush
+ * @return None
+ */
+void metal_icache_l1_flush(int hartid);
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__CLOCK_H
+#define METAL__CLOCK_H
+
+/*!
+ * @file clock.h
+ * @brief API for manipulating clock sources
+ *
+ * The clock interface allows for controlling the rate of various clocks in the system.
+ */
+
+struct metal_clock;
+
+#include <stddef.h>
+
+/* The generic interface to all clocks. */
+struct __metal_clock_vtable {
+ long (*get_rate_hz)(const struct metal_clock *clk);
+ long (*set_rate_hz)(struct metal_clock *clk, long hz);
+};
+
+/*!
+ * @brief Function signature of clock rate change callbacks
+ */
+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 Type for the linked list of callbacks for clock rate changes
+ */
+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
+ * @brief The handle for a clock
+ *
+ * Clocks are defined as a pointer to a `struct metal_clock`, the contents of which
+ * are implementation defined. Users of the clock interface must call 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
+ * defined, making it impossible to call any of these functions without invoking
+ * implementation-defined behavior.
+ */
+struct metal_clock {
+ const struct __metal_clock_vtable *vtable;
+
+ /* Pre-rate change callback linked list */
+ metal_clock_callback *_pre_rate_change_callback;
+
+ /* Post-rate change callback linked list */
+ metal_clock_callback *_post_rate_change_callback;
+};
+
+/*!
+ * @brief Returns the current rate of the given clock
+ *
+ * @param clk The handle for the clock
+ * @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); }
+
+/*!
+ * @brief Set the current rate of a clock
+ *
+ * @param clk The handle for the clock
+ * @param hz The desired rate in Hz
+ * @return The new rate of the clock in Hz.
+ *
+ * Attempts to set the current rate of the given clock to as close as possible
+ * to the given rate in Hz. Returns the actual value that's been selected, which
+ * could be anything!
+ *
+ * Prior to and after the rate change of the clock, this will call the registered
+ * pre- and post-rate change callbacks.
+ */
+__inline__ long metal_clock_set_rate_hz(struct metal_clock *clk, long hz)
+{
+ _metal_clock_call_all_callbacks(clk->_pre_rate_change_callback);
+
+ long out = clk->vtable->set_rate_hz(clk, hz);
+
+ _metal_clock_call_all_callbacks(clk->_post_rate_change_callback);
+
+ return out;
+}
+
+/*!
+ * @brief Register a callback that must be called before a rate change
+ *
+ * @param clk The handle for the clock
+ * @param cb The callback to be registered
+ */
+__inline__ void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb)
+{
+ clk->_pre_rate_change_callback = _metal_clock_append_to_callbacks(clk->_pre_rate_change_callback, cb);
+}
+
+/*!
+ * @brief Registers a callback that must be called after a rate change
+ *
+ * @param clk The handle for the clock
+ * @param cb The callback to be registered
+ */
+__inline__ void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb)
+{
+ clk->_post_rate_change_callback = _metal_clock_append_to_callbacks(clk->_post_rate_change_callback, cb);
+}
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__COMPILER_H
+#define METAL__COMPILER_H
+
+#define __METAL_DECLARE_VTABLE(type) \
+ extern const struct type type;
+
+#define __METAL_DEFINE_VTABLE(type) \
+ const struct type type
+
+#define __METAL_GET_FIELD(reg, mask) \
+ (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
+
+/* Set field with mask for a given value */
+#define __METAL_SET_FIELD(reg, mask, val) \
+ (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
+
+void _metal_trap(int ecode);
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+
+/* SPDX-License-Identifier: Apache-2.0 */
+
+/*! @file cpu.h
+ * @brief API for accessing CPU capabilities.
+ */
+
+#ifndef METAL__CPU_H
+#define METAL__CPU_H
+
+#include <stdint.h>
+#include <metal/interrupt.h>
+
+struct metal_cpu;
+
+/*!
+ * @brief Function signature for exception handlers
+ */
+typedef void (*metal_exception_handler_t) (struct metal_cpu *cpu, int ecode);
+
+struct metal_cpu_vtable {
+ unsigned long long (*mcycle_get)(struct metal_cpu *cpu);
+ unsigned long long (*timebase_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);
+ struct metal_interrupt* (*tmr_controller_interrupt)(struct metal_cpu *cpu);
+ int (*get_tmr_interrupt_id)(struct metal_cpu *cpu);
+ struct metal_interrupt* (*sw_controller_interrupt)(struct metal_cpu *cpu);
+ int (*get_sw_interrupt_id)(struct metal_cpu *cpu);
+ int (*set_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);
+ struct metal_interrupt* (*controller_interrupt)(struct metal_cpu *cpu);
+ int (*exception_register)(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler);
+ int (*get_ilen)(struct metal_cpu *cpu, uintptr_t epc);
+ uintptr_t (*get_epc)(struct metal_cpu *cpu);
+ int (*set_epc)(struct metal_cpu *cpu, uintptr_t epc);
+};
+
+/*! @brief A device handle for a CPU hart
+ */
+struct metal_cpu {
+ const struct metal_cpu_vtable *vtable;
+};
+
+/*! @brief Get a reference to a CPU hart
+ *
+ * @param hartid The ID of the desired CPU hart
+ * @return A pointer to the CPU device handle
+ */
+struct metal_cpu* metal_cpu_get(unsigned int hartid);
+
+/*! @brief Get the hartid of the CPU hart executing this function
+ *
+ * @return The hartid of the current CPU hart */
+int metal_cpu_get_current_hartid(void);
+
+/*! @brief Get the number of CPU harts
+ *
+ * @return The number of CPU harts */
+int metal_cpu_get_num_harts(void);
+
+/*! @brief Get the CPU cycle count timer value
+ *
+ * Get the value of the cycle count timer for a given CPU
+ *
+ * @param cpu The CPU device handle
+ * @return The value of the CPU cycle count timer
+ */
+__inline__ unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu)
+{ return cpu->vtable->mcycle_get(cpu); }
+
+/*! @brief Get the timebase of the CPU
+ *
+ * Get the value of the timebase of the cycle count timer
+ *
+ * @param cpu The CPU device handle
+ * @return The value of the cycle count timer timebase
+ */
+__inline__ unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu)
+{ return cpu->vtable->timebase_get(cpu); }
+
+/*! @brief Get the value of the mtime RTC
+ *
+ * Get the value of the mtime real-time clock. The CPU interrupt controller
+ * must be initialized before this function is called or the return value
+ * will be 0.
+ *
+ * @param cpu The CPU device handle
+ * @return The value of mtime, or 0 if failure
+ */
+__inline__ unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu)
+{ return cpu->vtable->mtime_get(cpu); }
+
+/*! @brief Set the value of the RTC mtimecmp RTC
+ *
+ * Set the value of the mtime real-time clock compare register. The CPU
+ * interrupt controller must be initialized before this function is called
+ * or the return value will be -1;
+ *
+ * @param cpu The CPU device handle
+ * @param time The value to set the compare register to
+ * @return The value of mtimecmp or -1 if error
+ */
+__inline__ int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time)
+{ return cpu->vtable->mtimecmp_set(cpu, time); }
+
+/*! @brief Get a reference to RTC timer interrupt controller
+ *
+ * Get a reference to the interrupt controller for the real-time clock interrupt.
+ * The controller returned by this function must be initialized before any interrupts
+ * are registered or enabled with it.
+ *
+ * @param cpu The CPU device handle
+ * @return A pointer to the timer interrupt handle
+ */
+__inline__ struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu)
+{ return cpu->vtable->tmr_controller_interrupt(cpu); }
+
+/*! @brief Get the RTC timer interrupt id
+ *
+ * Get the interrupt ID of the real-time clock interrupt
+ *
+ * @param cpu The CPU device handle
+ * @return The timer interrupt ID
+ */
+__inline__ int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu)
+{ return cpu->vtable->get_tmr_interrupt_id(cpu); }
+
+/*! @brief Get a reference to the software interrupt controller
+ *
+ * Get a reference to the interrupt controller for the software/inter-process
+ * interrupt. The controller returned by this function must be initialized before
+ * any interrupts are registered or enabled with it.
+ *
+ * @param cpu The CPU device handle
+ * @return A pointer to the software interrupt handle
+ */
+__inline__ struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu)
+{ return cpu->vtable->sw_controller_interrupt(cpu); }
+
+/*! @brief Get the software interrupt id
+ *
+ * Get the interrupt ID for the software/inter-process interrupt
+ *
+ * @param cpu The CPU device handle
+ * @return the software interrupt ID
+ */
+__inline__ int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu)
+{ return cpu->vtable->get_sw_interrupt_id(cpu); }
+
+/*!
+ * @brief Set the inter-process interrupt for a hart
+ *
+ * Trigger a software/inter-process interrupt for a hart. The CPU interrupt
+ * controller for the CPU handle passed to this function must be initialized
+ * before this function is called.
+ *
+ * @param cpu The CPU device handle
+ * @param hartid The CPU hart ID to be interrupted
+ * @return 0 upon success
+ */
+__inline__ int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid)
+{ return cpu->vtable->set_sw_ipi(cpu, hartid); }
+
+/*!
+ * @brief Clear the inter-process interrupt for a hart
+ *
+ * Clear the software/inter-process interrupt for a hart. The CPU interrupt
+ * controller for the CPU handle passed to this function must be initialized
+ * before this function is called.
+ *
+ * @param cpu The CPU device handle
+ * @param hartid The CPU hart ID to clear
+ * @return 0 upon success
+ */
+__inline__ int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid)
+{ return cpu->vtable->clear_sw_ipi(cpu, hartid); }
+
+/*!
+ * @brief Get the value of MSIP for the given hart
+ *
+ * Get the value of the machine software interrupt pending bit for
+ * the given hart. The CPU interrupt controller for the CPU handle passed
+ * as argument to this function must be initialized before this function
+ * is called.
+ *
+ * @param cpu the CPU device handle
+ * @param hartid The CPU hart to read
+ * @return 0 upon success
+ */
+__inline__ int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid)
+{ return cpu->vtable->get_msip(cpu, hartid); }
+
+/*!
+ * @brief Get the interrupt controller for the CPU
+ *
+ * Get the CPU interrupt controller. The controller returned by this
+ * function must be initialized before any interrupts are registered
+ * or enabled and before any exception handlers are registered with
+ * this CPU.
+ *
+ * @param cpu The CPU device handle
+ * @return The handle for the CPU interrupt controller
+ */
+__inline__ struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu)
+{ return cpu->vtable->controller_interrupt(cpu); }
+
+/*!
+ * @brief Register an exception handler
+ *
+ * Register an exception handler for the CPU. The CPU interrupt controller must be initialized
+ * before this function is called.
+ *
+ * @param cpu The CPU device handle
+ * @param ecode The exception code to register a handler for
+ * @param handler Callback function for the exception handler
+ * @return 0 upon success
+ */
+__inline__ int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler)
+{ return cpu->vtable->exception_register(cpu, ecode, handler); }
+
+/*!
+ * @brief Get the length of an instruction in bytes
+ *
+ * Get the length of an instruction in bytes.
+ *
+ * On RISC-V platforms, this is useful for detecting whether an instruction is
+ * compressed (2 bytes long) or uncompressed (4 bytes long).
+ *
+ * This function is useful in conjuction with `metal_cpu_get_exception_pc()`
+ * and `metal_cpu_set_exception_pc()` in order to cause the exception handler to
+ * return execution after the faulting instruction.
+ *
+ * @param cpu The CPU device handle
+ * @param epc The address of the instruction to measure
+ * @return the length of the instruction in bytes
+ */
+__inline__ int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
+{ return cpu->vtable->get_ilen(cpu, epc); }
+
+/*!
+ * @brief Get the program counter of the current exception.
+ *
+ * This function must be called within an exception handler. The behavior is
+ * undefined outside of an exception handler.
+ *
+ * @param cpu The CPU device handle
+ * @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)
+{ return cpu->vtable->get_epc(cpu); }
+
+/*!
+ * @brief Set the exception program counter
+ *
+ * This function must be called within an exception handler. The behavior
+ * is undefined outside of an exception handler.
+ *
+ * This function can be used to cause an exception handler to return execution
+ * to an address other than the one that caused the exception.
+ *
+ * @param cpu the CPU device handle
+ * @param epc The address to set the exception program counter to
+ * @return 0 upon success
+ */
+__inline__ int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc)
+{ return cpu->vtable->set_epc(cpu, epc); }
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__FIXED_CLOCK_H
+#define METAL__DRIVERS__FIXED_CLOCK_H
+
+struct __metal_driver_fixed_clock;
+
+#include <metal/compiler.h>
+#include <metal/clock.h>
+
+struct __metal_driver_vtable_fixed_clock {
+ struct __metal_clock_vtable clock;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_fixed_clock)
+
+struct __metal_driver_fixed_clock {
+ struct metal_clock clock;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__FIXED_FACTOR_CLOCK_H
+#define METAL__DRIVERS__FIXED_FACTOR_CLOCK_H
+
+struct __metal_driver_fixed_factor_clock;
+
+#include <metal/compiler.h>
+#include <metal/clock.h>
+
+struct __metal_driver_vtable_fixed_factor_clock {
+ struct __metal_clock_vtable clock;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_fixed_factor_clock)
+
+struct __metal_driver_fixed_factor_clock {
+ struct metal_clock clock;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__RISCV_CLINT0_H
+#define METAL__DRIVERS__RISCV_CLINT0_H
+
+#include <metal/compiler.h>
+#include <metal/drivers/riscv_cpu.h>
+
+struct __metal_driver_vtable_riscv_clint0 {
+ struct metal_interrupt_vtable clint_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_clint0)
+
+#define __METAL_MACHINE_MACROS
+#include <metal/machine.h>
+struct __metal_driver_riscv_clint0 {
+ struct metal_interrupt controller;
+ int init_done;
+};
+#undef __METAL_MACHINE_MACROS
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__RISCV_CPU_H
+#define METAL__DRIVERS__RISCV_CPU_H
+
+#include <stdint.h>
+#include <metal/cpu.h>
+#include <metal/compiler.h>
+
+#define METAL_MAX_CORES 8
+#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_DEFAULT_RTC_FREQ 32768
+
+#define METAL_DISABLE 0
+#define METAL_ENABLE 1
+
+#define METAL_ISA_A_EXTENSIONS 0x0001
+#define METAL_ISA_C_EXTENSIONS 0x0004
+#define METAL_ISA_D_EXTENSIONS 0x0008
+#define METAL_ISA_E_EXTENSIONS 0x0010
+#define METAL_ISA_F_EXTENSIONS 0x0020
+#define METAL_ISA_G_EXTENSIONS 0x0040
+#define METAL_ISA_I_EXTENSIONS 0x0100
+#define METAL_ISA_M_EXTENSIONS 0x1000
+#define METAL_ISA_N_EXTENSIONS 0x2000
+#define METAL_ISA_Q_EXTENSIONS 0x10000
+#define METAL_ISA_S_EXTENSIONS 0x40000
+#define METAL_ISA_U_EXTENSIONS 0x100000
+#define METAL_ISA_V_EXTENSIONS 0x200000
+#define METAL_ISA_XL32_EXTENSIONS 0x40000000UL
+#define METAL_ISA_XL64_EXTENSIONS 0x8000000000000000UL
+#define METAL_ISA_XL128_EXTENSIONS 0xC000000000000000UL
+
+#define METAL_MTVEC_DIRECT 0x00
+#define METAL_MTVEC_VECTORED 0x01
+#define METAL_MTVEC_CLIC 0x02
+#define METAL_MTVEC_CLIC_VECTORED 0x03
+#define METAL_MTVEC_CLIC_RESERVED 0x3C
+#define METAL_MTVEC_MASK 0x3F
+#if __riscv_xlen == 32
+#define METAL_MCAUSE_INTR 0x80000000UL
+#define METAL_MCAUSE_CAUSE 0x000003FFUL
+#else
+#define METAL_MCAUSE_INTR 0x8000000000000000UL
+#define METAL_MCAUSE_CAUSE 0x00000000000003FFUL
+#endif
+#define METAL_MCAUSE_MINHV 0x40000000UL
+#define METAL_MCAUSE_MPP 0x30000000UL
+#define METAL_MCAUSE_MPIE 0x08000000UL
+#define METAL_MCAUSE_MPIL 0x00FF0000UL
+#define METAL_MSTATUS_MIE 0x00000008UL
+#define METAL_MSTATUS_MPIE 0x00000080UL
+#define METAL_MSTATUS_MPP 0x00001800UL
+#define METAL_MSTATUS_FS_INIT 0x00002000UL
+#define METAL_MSTATUS_FS_CLEAN 0x00004000UL
+#define METAL_MSTATUS_FS_DIRTY 0x00006000UL
+#define METAL_MSTATUS_MPRV 0x00020000UL
+#define METAL_MSTATUS_MXR 0x00080000UL
+#define METAL_MINTSTATUS_MIL 0xFF000000UL
+#define METAL_MINTSTATUS_SIL 0x0000FF00UL
+#define METAL_MINTSTATUS_UIL 0x000000FFUL
+
+#define METAL_LOCAL_INTR(X) (16 + X)
+#define METAL_MCAUSE_EVAL(cause) (cause & METAL_MCAUSE_INTR)
+#define METAL_INTERRUPT(cause) (METAL_MCAUSE_EVAL(cause) ? 1 : 0)
+#define METAL_EXCEPTION(cause) (METAL_MCAUSE_EVAL(cause) ? 0 : 1)
+#define METAL_SW_INTR_EXCEPTION (METAL_MCAUSE_INTR + 3)
+#define METAL_TMR_INTR_EXCEPTION (METAL_MCAUSE_INTR + 7)
+#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_RESERVE0 1
+#define METAL_LOCAL_INTR_RESERVE1 2
+#define METAL_LOCAL_INTR_RESERVE2 4
+#define METAL_LOCAL_INTERRUPT_SW 8 /* Bit3 0x008 */
+#define METAL_LOCAL_INTR_RESERVE4 16
+#define METAL_LOCAL_INTR_RESERVE5 32
+#define METAL_LOCAL_INTR_RESERVE6 64
+#define METAL_LOCAL_INTERRUPT_TMR 128 /* Bit7 0x080 */
+#define METAL_LOCAL_INTR_RESERVE8 256
+#define METAL_LOCAL_INTR_RESERVE9 512
+#define METAL_LOCAL_INTR_RESERVE10 1024
+#define METAL_LOCAL_INTERRUPT_EXT 2048 /* Bit11 0x800 */
+/* Bit12 to Bit15 are Reserved */
+#define METAL_LOCAL_INTERRUPT(X) (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 {
+ METAL_MACHINE_PRIVILEGE_MODE,
+ METAL_SUPERVISOR_PRIVILEGE_MODE,
+ METAL_USER_PRIVILEGE_MODE,
+} metal_privilege_mode_e;
+
+typedef enum {
+ METAL_INTERRUPT_ID_BASE,
+ METAL_INTERRUPT_ID_SW = (METAL_INTERRUPT_ID_BASE + 3),
+ METAL_INTERRUPT_ID_TMR = (METAL_INTERRUPT_ID_BASE + 7),
+ METAL_INTERRUPT_ID_EXT = (METAL_INTERRUPT_ID_BASE + 11),
+ METAL_INTERRUPT_ID_CSW = (METAL_INTERRUPT_ID_BASE + 12),
+ METAL_INTERRUPT_ID_LC0 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(0)),
+ METAL_INTERRUPT_ID_LC1 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(1)),
+ METAL_INTERRUPT_ID_LC2 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(2)),
+ METAL_INTERRUPT_ID_LC3 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(3)),
+ METAL_INTERRUPT_ID_LC4 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(4)),
+ METAL_INTERRUPT_ID_LC5 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(5)),
+ METAL_INTERRUPT_ID_LC6 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(6)),
+ METAL_INTERRUPT_ID_LC7 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(7)),
+ METAL_INTERRUPT_ID_LC8 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(8)),
+ METAL_INTERRUPT_ID_LC9 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(9)),
+ METAL_INTERRUPT_ID_LC10 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(10)),
+ METAL_INTERRUPT_ID_LC11 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(11)),
+ METAL_INTERRUPT_ID_LC12 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(12)),
+ METAL_INTERRUPT_ID_LC13 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(13)),
+ METAL_INTERRUPT_ID_LC14 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(14)),
+ METAL_INTERRUPT_ID_LC15 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(15)),
+ METAL_INTERRUPT_ID_LCMX,
+ METAL_INTERRUPT_ID_GL0 = METAL_INTERRUPT_ID_LCMX,
+ METAL_INTERRUPT_ID_GLMX = (METAL_MCAUSE_CAUSE + 1),
+} metal_interrupt_id_e;
+
+typedef enum {
+ METAL_IAM_EXCEPTION_CODE, /* Instruction address misaligned */
+ METAL_IAF_EXCEPTION_CODE, /* Instruction access faultd */
+ METAL_II_EXCEPTION_CODE, /* Illegal instruction */
+ METAL_BREAK_EXCEPTION_CODE, /* Breakpoint */
+ METAL_LAM_EXCEPTION_CODE, /* Load address misaligned */
+ METAL_LAF_EXCEPTION_CODE, /* Load access fault */
+ METAL_SAMOAM_EXCEPTION_CODE, /* Store/AMO address misaligned */
+ METAL_SAMOAF_EXCEPTION_CODE, /* Store/AMO access fault */
+ METAL_ECALL_U_EXCEPTION_CODE, /* Environment call from U-mode */
+ METAL_R9_EXCEPTION_CODE, /* Reserved */
+ METAL_R10_EXCEPTION_CODE, /* Reserved */
+ METAL_ECALL_M_EXCEPTION_CODE, /* Environment call from M-mode */
+ METAL_MAX_EXCEPTION_CODE,
+} metal_exception_code_e;
+
+typedef enum {
+ METAL_TIMER_MTIME_GET = 1,
+ METAL_SOFTWARE_IPI_CLEAR,
+ METAL_SOFTWARE_IPI_SET,
+ METAL_SOFTWARE_MSIP_GET,
+ METAL_MAX_INTERRUPT_GET,
+ METAL_INDEX_INTERRUPT_GET,
+} metal_interrup_cmd_e;
+
+typedef struct __metal_interrupt_data {
+ long long pad : 64;
+ metal_interrupt_handler_t handler;
+ void *sub_int;
+ void *exint_data;
+} __metal_interrupt_data;
+
+/* CPU interrupt controller */
+
+uintptr_t __metal_myhart_id(void);
+
+struct __metal_driver_vtable_riscv_cpu_intc {
+ struct metal_interrupt_vtable controller_vtable;
+};
+
+
+void __metal_interrupt_global_enable(void);
+void __metal_interrupt_global_disable(void);
+metal_vector_mode __metal_controller_interrupt_vector_mode(void);
+void __metal_controller_interrupt_vector(metal_vector_mode mode, void *vec_table);
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_cpu_intc)
+
+struct __metal_driver_riscv_cpu_intc {
+ struct metal_interrupt controller;
+ int init_done;
+ uintptr_t metal_mtvec_table[METAL_MAX_MI];
+ __metal_interrupt_data metal_int_table[METAL_MAX_MI];
+ metal_exception_handler_t metal_exception_table[METAL_MAX_ME];
+};
+
+/* CPU driver*/
+struct __metal_driver_vtable_cpu {
+ struct metal_cpu_vtable cpu_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_cpu)
+
+struct __metal_driver_cpu {
+ struct metal_cpu cpu;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__RISCV_PLIC0_H
+#define METAL__DRIVERS__RISCV_PLIC0_H
+
+#include <metal/compiler.h>
+#include <metal/drivers/riscv_cpu.h>
+
+#define METAL_PLIC_SOURCE_MASK 0x1F
+#define METAL_PLIC_SOURCE_SHIFT 5
+#define METAL_PLIC_SOURCE_PRIORITY_SHIFT 2
+#define METAL_PLIC_SOURCE_PENDING_SHIFT 0
+
+struct __metal_driver_vtable_riscv_plic0 {
+ struct metal_interrupt_vtable plic_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_plic0)
+
+#define __METAL_MACHINE_MACROS
+#include <metal/machine.h>
+struct __metal_driver_riscv_plic0 {
+ struct metal_interrupt controller;
+ int init_done;
+ metal_interrupt_handler_t metal_exint_table[__METAL_PLIC_SUBINTERRUPTS];
+ __metal_interrupt_data metal_exdata_table[__METAL_PLIC_SUBINTERRUPTS];
+};
+#undef __METAL_MACHINE_MACROS
+
+#endif
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_CCACHE0_H
+#define METAL__DRIVERS__SIFIVE_CCACHE0_H
+
+#include <metal/cache.h>
+#include <metal/compiler.h>
+
+struct __metal_driver_vtable_sifive_ccache0 {
+ struct __metal_cache_vtable cache;
+};
+
+struct __metal_driver_sifive_ccache0;
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_ccache0)
+
+struct __metal_driver_sifive_ccache0 {
+ struct metal_cache cache;
+};
+
+#endif
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_CLIC0_H
+#define METAL__DRIVERS__SIFIVE_CLIC0_H
+
+#include <metal/compiler.h>
+#include <metal/drivers/riscv_cpu.h>
+
+#define METAL_CLIC_MAX_NMBITS 2
+#define METAL_CLIC_MAX_NLBITS 8
+#define METAL_CLIC_MAX_NVBITS 1
+
+#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MMODE 0x00
+#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE1 0x20
+#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE2 0x40
+#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MASK 0x60
+#define METAL_SIFIVE_CLIC0_CLICCFG_NLBITS_MASK 0x1E
+#define METAL_SIFIVE_CLIC0_CLICCFG_NVBIT_MASK 0x01
+
+#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_MAX_INTERRUPT_LEVEL ((1 << METAL_CLIC_MAX_NLBITS) - 1)
+
+struct __metal_driver_vtable_sifive_clic0 {
+ struct metal_interrupt_vtable clic_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_clic0)
+
+#define __METAL_MACHINE_MACROS
+#include <metal/machine.h>
+struct __metal_driver_sifive_clic0 {
+ struct metal_interrupt controller;
+ int init_done;
+ int pad[14];
+ metal_interrupt_vector_handler_t metal_mtvt_table[__METAL_CLIC_SUBINTERRUPTS];
+ __metal_interrupt_data metal_exint_table[__METAL_CLIC_SUBINTERRUPTS];
+};
+#undef __METAL_MACHINE_MACROS
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef 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/io.h>
+
+struct __metal_driver_vtable_sifive_fe310_g000_hfrosc {
+ struct __metal_clock_vtable clock;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfrosc)
+
+struct __metal_driver_sifive_fe310_g000_hfrosc {
+ struct metal_clock clock;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_HFXOSC_H
+#define METAL__DRIVERS__SIFIVE_FE310_G000_HFXOSC_H
+
+#include <metal/clock.h>
+#include <metal/drivers/sifive_fe310-g000_prci.h>
+
+struct __metal_driver_vtable_sifive_fe310_g000_hfxosc {
+ struct __metal_clock_vtable clock;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfxosc)
+
+struct __metal_driver_sifive_fe310_g000_hfxosc {
+ struct metal_clock clock;
+};
+
+#endif
--- /dev/null
+/* 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/compiler.h>
+#include <metal/clock.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
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_PLL_H
+#define METAL__DRIVERS__SIFIVE_FE310_G000_PLL_H
+
+struct __metal_driver_sifive_fe310_g000_pll;
+
+#include <metal/clock.h>
+#include <metal/drivers/sifive_fe310-g000_prci.h>
+#include <metal/machine.h>
+
+struct __metal_driver_vtable_sifive_fe310_g000_pll {
+ void (*init)(struct __metal_driver_sifive_fe310_g000_pll *pll);
+ struct __metal_clock_vtable clock;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_pll)
+
+struct __metal_driver_sifive_fe310_g000_pll {
+ struct metal_clock clock;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_PRCI_H
+#define METAL__DRIVERS__SIFIVE_FE310_G000_PRCI_H
+
+#include <metal/compiler.h>
+#include <metal/io.h>
+
+struct __metal_driver_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 (*set_reg)(const struct __metal_driver_sifive_fe310_g000_prci *, long offset, long value);
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci)
+
+struct __metal_driver_sifive_fe310_g000_prci {
+ const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable;
+};
+
+#endif
+
--- /dev/null
+/* 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
+
+#include <metal/cache.h>
+#include <metal/compiler.h>
+
+struct __metal_driver_vtable_sifive_fu540_c000_l2 {
+ struct __metal_cache_vtable cache;
+};
+
+struct __metal_driver_sifive_fu540_c000_l2;
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2)
+
+struct __metal_driver_sifive_fu540_c000_l2 {
+ struct metal_cache cache;
+};
+
+#endif
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0_H
+#define METAL__DRIVERS__SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0_H
+
+#include <metal/compiler.h>
+#include <metal/drivers/riscv_cpu.h>
+
+struct __metal_driver_vtable_sifive_global_external_interrupts0 {
+ struct metal_interrupt_vtable global0_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_global_external_interrupts0)
+
+struct __metal_driver_sifive_global_external_interrupts0 {
+ struct metal_interrupt irc;
+ int init_done;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H
+#define METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H
+
+#include <string.h>
+#include <metal/button.h>
+#include <metal/compiler.h>
+
+struct __metal_driver_vtable_sifive_button {
+ struct metal_button_vtable button_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_button)
+
+struct __metal_driver_sifive_gpio_button {
+ struct metal_button button;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_GPIO_LEDS_H
+#define METAL__DRIVERS__SIFIVE_GPIO_LEDS_H
+
+#include <metal/drivers/sifive_gpio0.h>
+#include <metal/led.h>
+#include <metal/compiler.h>
+
+struct __metal_driver_vtable_sifive_led {
+ struct metal_led_vtable led_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_led)
+
+struct __metal_driver_sifive_gpio_led {
+ struct metal_led led;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H
+#define METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H
+
+#include <metal/drivers/sifive_gpio0.h>
+#include <metal/switch.h>
+#include <metal/compiler.h>
+
+struct __metal_driver_vtable_sifive_switch {
+ struct metal_switch_vtable switch_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_switch)
+
+struct __metal_driver_sifive_gpio_switch {
+ struct metal_switch flip;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_GPIO0_H
+#define METAL__DRIVERS__SIFIVE_GPIO0_H
+
+#include <metal/compiler.h>
+#include <metal/gpio.h>
+
+struct __metal_driver_vtable_sifive_gpio0 {
+ const struct __metal_gpio_vtable gpio;
+};
+
+//struct __metal_driver_sifive_gpio0;
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_gpio0)
+
+struct __metal_driver_sifive_gpio0 {
+ struct metal_gpio gpio;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_EXTERNAL_INTERRUPTS0_H
+#define METAL__DRIVERS__SIFIVE_EXTERNAL_INTERRUPTS0_H
+
+#include <metal/compiler.h>
+#include <metal/drivers/riscv_cpu.h>
+
+struct __metal_driver_vtable_sifive_local_external_interrupts0 {
+ struct metal_interrupt_vtable local0_vtable;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_local_external_interrupts0)
+
+struct __metal_driver_sifive_local_external_interrupts0 {
+ struct metal_interrupt irc;
+ int init_done;
+};
+
+
+#endif
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_RTC0_H
+#define METAL__DRIVERS__SIFIVE_RTC0_H
+
+#include <metal/io.h>
+#include <metal/compiler.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
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_SPI0_H
+#define METAL__DRIVERS__SIFIVE_SPI0_H
+
+#include <metal/drivers/sifive_gpio0.h>
+#include <metal/clock.h>
+#include <metal/compiler.h>
+#include <metal/io.h>
+#include <metal/spi.h>
+
+struct __metal_driver_vtable_sifive_spi0 {
+ const struct metal_spi_vtable spi;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_spi0)
+
+struct __metal_driver_sifive_spi0 {
+ struct metal_spi spi;
+ unsigned long baud_rate;
+ metal_clock_callback pre_rate_change_callback;
+ metal_clock_callback post_rate_change_callback;
+};
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_TEST0_H
+#define METAL__DRIVERS__SIFIVE_TEST0_H
+
+#include <metal/compiler.h>
+#include <metal/shutdown.h>
+
+struct __metal_driver_vtable_sifive_test0 {
+ const struct __metal_shutdown_vtable shutdown;
+};
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_test0)
+
+struct __metal_driver_sifive_test0 {
+ struct __metal_shutdown shutdown;
+};
+
+
+#endif
--- /dev/null
+/* 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 */
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef 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/io.h>
+#include <metal/uart.h>
+#include <metal/compiler.h>
+
+struct __metal_driver_vtable_sifive_uart0 {
+ const struct metal_uart_vtable uart;
+};
+
+struct __metal_driver_sifive_uart0;
+
+__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_uart0)
+
+struct __metal_driver_sifive_uart0 {
+ struct metal_uart uart;
+ unsigned long baud_rate;
+ metal_clock_callback pre_rate_change_callback;
+ metal_clock_callback post_rate_change_callback;
+};
+
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__DRIVERS__SIFIVE_WDOG0_H
+#define METAL__DRIVERS__SIFIVE_WDOG0_H
+
+#include <metal/io.h>
+#include <metal/compiler.h>
+
+#include <metal/watchdog.h>
+#include <metal/clock.h>
+#include <metal/interrupt.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
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__GPIO_H
+#define METAL__GPIO_H
+
+#include <metal/compiler.h>
+#include <metal/interrupt.h>
+
+/*!
+ * @file gpio.h
+ * @brief API for manipulating general-purpose input/output
+ */
+
+struct metal_gpio;
+
+struct __metal_gpio_vtable {
+ 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 *);
+ int (*disable_output)(struct metal_gpio *, long pins);
+ int (*enable_output)(struct metal_gpio *, long pins);
+ int (*output_set)(struct metal_gpio *, long value);
+ int (*output_clear)(struct metal_gpio *, long value);
+ int (*output_toggle)(struct metal_gpio *, long value);
+ 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
+ * @brief The handle for a GPIO interface
+ */
+struct metal_gpio {
+ const struct __metal_gpio_vtable *vtable;
+};
+
+/*!
+ * @brief Get a GPIO device handle
+ * @param device_num The GPIO device index
+ * @return The GPIO device handle, or NULL if there is no device at that index
+ */
+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
+ * @param gpio The handle for the GPIO interface
+ * @param pin The pin number indexed from 0
+ * @return 0 if the input is successfully disabled
+ */
+__inline__ int metal_gpio_disable_input(struct metal_gpio *gpio, int pin) {
+ if(!gpio) {
+ return 1;
+ }
+
+ return gpio->vtable->disable_input(gpio, (1 << pin));
+}
+
+/*!
+ * @brief Enable 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 enabled
+ */
+__inline__ int metal_gpio_enable_output(struct metal_gpio *gpio, int pin) {
+ if(!gpio) {
+ return 1;
+ }
+
+ 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
+ * @param gpio The handle for the GPIO interface
+ * @param pin The pin number indexed from 0
+ * @param value The value to set the pin to
+ * @return 0 if the output is successfully set
+ */
+__inline__ int metal_gpio_set_pin(struct metal_gpio *gpio, int pin, int value) {
+ if(!gpio) {
+ return 1;
+ }
+
+ if(value == 0) {
+ return gpio->vtable->output_clear(gpio, (1 << pin));
+ } else {
+ return gpio->vtable->output_set(gpio, (1 << pin));
+ }
+}
+
+/*!
+ * @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_input_pin(struct metal_gpio *gpio, int pin) {
+ if(!gpio) {
+ 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);
+
+ if(value & (1 << pin)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ * @brief Clears the value of the GPIO pin
+ * @param gpio The handle for the GPIO interface
+ * @param pin The pin number indexed from 0
+ * @return 0 if the pin is successfully cleared
+ */
+__inline__ int metal_gpio_clear_pin(struct metal_gpio *gpio, int pin) {
+ if(!gpio) {
+ return 1;
+ }
+
+ return gpio->vtable->output_clear(gpio, (1 << pin));
+}
+
+/*!
+ * @brief Toggles the value of the GPIO pin
+ * @param gpio The handle for the GPIO interface
+ * @param pin The pin number indexed from 0
+ * @return 0 if the pin is successfully toggled
+ */
+__inline__ int metal_gpio_toggle_pin(struct metal_gpio *gpio, int pin) {
+ if(!gpio) {
+ return 1;
+ }
+
+ return gpio->vtable->output_toggle(gpio, (1 << pin));
+}
+
+/*!
+ * @brief Enables and sets the pinmux for a GPIO pin
+ * @param gpio The handle for the GPIO interface
+ * @param pin The bitmask for the pin to enable pinmux on
+ * @param io_function The IO function to set
+ * @return 0 if the pinmux is successfully set
+ */
+__inline__ int metal_gpio_enable_pinmux(struct metal_gpio *gpio, int pin, int io_function) {
+ if(!gpio) {
+ return 1;
+ }
+
+ 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
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__INTERRUPT_H
+#define METAL__INTERRUPT_H
+
+/*! @file interrupt.h
+ * @brief API for registering and manipulating interrupts
+ */
+
+#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
+ */
+typedef enum metal_vector_mode_ {
+ METAL_DIRECT_MODE = 0,
+ METAL_VECTOR_MODE = 1,
+ METAL_SELECTIVE_NONVECTOR_MODE = 2,
+ METAL_SELECTIVE_VECTOR_MODE = 3,
+ METAL_HARDWARE_VECTOR_MODE = 4
+} 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 Function signature for interrupt callback handlers
+ */
+typedef void (*metal_interrupt_handler_t) (int, void *);
+typedef void (*metal_interrupt_vector_handler_t) (void);
+
+struct metal_interrupt;
+
+struct metal_interrupt_vtable {
+ 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,
+ 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_disable)(struct metal_interrupt *controller, int id);
+ int (*interrupt_vector_enable)(struct metal_interrupt *controller, int id);
+ int (*interrupt_vector_disable)(struct metal_interrupt *controller, int id);
+ unsigned int (*interrupt_get_threshold)(struct metal_interrupt *controller);
+ 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);
+ int (*command_request)(struct metal_interrupt *controller, int cmd, void *data);
+ int (*mtimecmp_set)(struct metal_interrupt *controller, int hartid, unsigned long long time);
+};
+
+/*!
+ * @brief A handle for an interrupt
+ */
+struct metal_interrupt {
+ const struct metal_interrupt_vtable *vtable;
+};
+
+/*!
+ * @brief Initialize a given interrupt controller
+ *
+ * Initialize a given interrupt controller. This function must be called
+ * before any interrupts are registered or enabled with the handler. It
+ * is invalid to initialize an interrupt controller more than once.
+ *
+ * @param controller The handle for the interrupt controller
+ */
+__inline__ void metal_interrupt_init(struct metal_interrupt *controller)
+{
+ 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
+ * @param controller The handle for the interrupt controller
+ * @param id The interrupt ID to register
+ * @param handler The interrupt handler callback
+ * @param priv_data Private data for the interrupt handler
+ * @return 0 upon success
+ */
+__inline__ int metal_interrupt_register_handler(struct metal_interrupt *controller,
+ int id,
+ metal_interrupt_handler_t handler,
+ void *priv_data)
+{
+ return controller->vtable->interrupt_register(controller, id, handler, 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);
+}
+
+/*!
+ * @brief Enable an interrupt
+ * @param controller The handle for the interrupt controller
+ * @param id The interrupt ID to enable
+ * @return 0 upon success
+ */
+__inline__ int metal_interrupt_enable(struct metal_interrupt *controller, int id)
+{
+ return controller->vtable->interrupt_enable(controller, id);
+}
+
+/*!
+ * @brief Disable an interrupt
+ * @param controller The handle for the interrupt controller
+ * @param id The interrupt ID to disable
+ * @return 0 upon success
+ */
+__inline__ int metal_interrupt_disable(struct metal_interrupt *controller, int 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 Enable an interrupt vector
+ * @param controller The handle for the interrupt controller
+ * @param id The interrupt ID to enable
+ * @return 0 upon success
+ */
+__inline__ int metal_interrupt_vector_enable(struct metal_interrupt *controller, int id)
+{
+ return controller->vtable->interrupt_vector_enable(controller, id);
+}
+
+/*!
+ * @brief Disable an interrupt vector
+ * @param controller The handle for the interrupt controller
+ * @param id The interrupt ID to disable
+ * @return 0 upon success
+ */
+__inline__ int metal_interrupt_vector_disable(struct metal_interrupt *controller, int id)
+{
+ return controller->vtable->interrupt_vector_disable(controller, id);
+}
+
+/*!
+ * @brief Default interrupt vector handler, that can be overriden by user
+ * @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);
+}
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__IO_H
+#define METAL__IO_H
+
+/* This macro enforces that the compiler will not elide the given access. */
+#define __METAL_ACCESS_ONCE(x) (*(__typeof__(*x) volatile *)(x))
+
+/* Allows users to specify arbitrary fences. */
+#define __METAL_IO_FENCE(pred, succ) __asm__ volatile ("fence " #pred "," #succ ::: "memory");
+
+/* Types that explicitly describe an address as being used for memory-mapped
+ * IO. These should only be accessed via __METAL_ACCESS_ONCE. */
+typedef unsigned char __metal_io_u8;
+typedef unsigned short __metal_io_u16;
+typedef unsigned int __metal_io_u32;
+#if __riscv_xlen >= 64
+typedef unsigned long __metal_io_u64;
+#endif
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__ITIM_H
+#define METAL__ITIM_H
+
+/*! @file itim.h
+ *
+ * API for manipulating ITIM allocation
+ */
+
+
+/*! @def METAL_PLACE_IN_ITIM
+ * @brief Link a function into the ITIM
+ *
+ * Link a function into the ITIM (Instruction Tightly Integrated
+ * Memory) if the ITIM is present on the target device.
+ */
+#define METAL_PLACE_IN_ITIM __attribute__((section(".itim")))
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__LED_H
+#define METAL__LED_H
+
+/*!
+ * @file led.h
+ * @brief API for manipulating LEDs
+ */
+
+struct metal_led;
+
+struct metal_led_vtable {
+ int (*led_exist)(struct metal_led *led, char *label);
+ void (*led_enable)(struct metal_led *led);
+ void (*led_on)(struct metal_led *led);
+ void (*led_off)(struct metal_led *led);
+ void (*led_toggle)(struct metal_led *led);
+};
+
+/*!
+ * @brief A handle for an LED
+ */
+struct metal_led {
+ const struct metal_led_vtable *vtable;
+};
+
+/*!
+ * @brief Get a handle for an 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
+ */
+struct metal_led* metal_led_get(char *label);
+
+/*!
+ * @brief Get a handle for a channel of an RGB LED
+ * @param label The DeviceTree label for the desired LED
+ * @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
+ */
+struct metal_led* metal_led_get_rgb(char *label, char *color);
+
+/*!
+ * @brief Enable an LED
+ * @param led The handle for the LED
+ */
+__inline__ void metal_led_enable(struct metal_led *led) { led->vtable->led_enable(led); }
+
+/*!
+ * @brief Turn an LED on
+ * @param led The handle for the LED
+ */
+__inline__ void metal_led_on(struct metal_led *led) { led->vtable->led_on(led); }
+
+/*!
+ * @brief Turn an LED off
+ * @param led The handle for the LED
+ */
+__inline__ void metal_led_off(struct metal_led *led) { led->vtable->led_off(led); }
+
+/*!
+ * @brief Toggle the on/off state of an LED
+ * @param led The handle for the LED
+ */
+__inline__ void metal_led_toggle(struct metal_led *led) { led->vtable->led_toggle(led); }
+
+#endif
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__LOCK_H
+#define METAL__LOCK_H
+
+#include <metal/machine.h>
+#include <metal/memory.h>
+#include <metal/compiler.h>
+
+/*!
+ * @file lock.h
+ * @brief An API for creating and using a software lock/mutex
+ */
+
+/* TODO: How can we make the exception code platform-independant? */
+#define _METAL_STORE_AMO_ACCESS_FAULT 7
+
+#define METAL_LOCK_BACKOFF_CYCLES 32
+#define METAL_LOCK_BACKOFF_EXPONENT 2
+
+/*!
+ * @def METAL_LOCK_DECLARE
+ * @brief Declare a 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.
+ */
+#define METAL_LOCK_DECLARE(name) \
+ __attribute__((section(".data.locks"))) \
+ struct metal_lock name
+
+/*!
+ * @brief A handle for a lock
+ */
+struct metal_lock {
+ int _state;
+};
+
+/*!
+ * @brief Initialize a lock
+ * @param lock The handle for a lock
+ * @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
+ * will result in a Store/AMO access fault.
+ */
+__inline__ int metal_lock_init(struct metal_lock *lock) {
+#ifdef __riscv_atomic
+ /* 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));
+ if(!lock_mem) {
+ return 1;
+ }
+
+ /* If the memory doesn't support atomics, report an error */
+ if(!metal_memory_supports_atomics(lock_mem)) {
+ return 2;
+ }
+
+ lock->_state = 0;
+
+ return 0;
+#else
+ return 3;
+#endif
+}
+
+/*!
+ * @brief Take a lock
+ * @param lock The handle for a lock
+ * @return 0 if the lock is successfully taken
+ *
+ * If the lock initialization failed, attempts to take a lock will result in
+ * a Store/AMO access fault.
+ */
+__inline__ int metal_lock_take(struct metal_lock *lock) {
+#ifdef __riscv_atomic
+ int old = 1;
+ int new = 1;
+
+ int backoff = 1;
+ const int max_backoff = METAL_LOCK_BACKOFF_CYCLES * METAL_MAX_CORES;
+
+ while(1) {
+ __asm__ volatile("amoswap.w.aq %[old], %[new], (%[state])"
+ : [old] "=r" (old)
+ : [new] "r" (new), [state] "r" (&(lock->_state))
+ : "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;
+#else
+ /* Store the memory address in mtval like a normal store/amo access fault */
+ __asm__ ("csrw mtval, %[state]"
+ :: [state] "r" (&(lock->_state)));
+
+ /* Trigger a Store/AMO access fault */
+ _metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);
+
+ /* If execution returns, indicate failure */
+ return 1;
+#endif
+}
+
+/*!
+ * @brief Give back a held lock
+ * @param lock The handle for a lock
+ * @return 0 if the lock is successfully given
+ *
+ * If the lock initialization failed, attempts to give a lock will result in
+ * a Store/AMO access fault.
+ */
+__inline__ int metal_lock_give(struct metal_lock *lock) {
+#ifdef __riscv_atomic
+ __asm__ volatile("amoswap.w.rl x0, x0, (%[state])"
+ :: [state] "r" (&(lock->_state))
+ : "memory");
+
+ return 0;
+#else
+ /* Store the memory address in mtval like a normal store/amo access fault */
+ __asm__ ("csrw mtval, %[state]"
+ :: [state] "r" (&(lock->_state)));
+
+ /* Trigger a Store/AMO access fault */
+ _metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);
+
+ /* If execution returns, indicate failure */
+ return 1;
+#endif
+}
+
+#endif /* METAL__LOCK_H */
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__MEMORY_H
+#define METAL__MEMORY_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/*!
+ * @file memory.h
+ *
+ * @brief API for enumerating memory blocks
+ */
+
+struct _metal_memory_attributes {
+ unsigned int R : 1;
+ unsigned int W : 1;
+ unsigned int X : 1;
+ unsigned int C : 1;
+ unsigned int A : 1;
+};
+
+/*!
+ * @brief A handle for a memory block
+ */
+struct metal_memory {
+ const uintptr_t _base_address;
+ const size_t _size;
+ const struct _metal_memory_attributes _attrs;
+};
+
+/*!
+ * @brief Get the memory block which services the given address
+ *
+ * Given a physical memory address, get a handle for the memory block to which
+ * that address is mapped.
+ *
+ * @param address The address to query
+ * @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);
+
+/*!
+ * @brief Get the base address for a memory block
+ * @param memory The handle for the memory block
+ * @return The base address of the memory block
+ */
+__inline__ uintptr_t metal_memory_get_base_address(const struct metal_memory *memory) {
+ return memory->_base_address;
+}
+
+/*!
+ * @brief Get the size of a memory block
+ * @param memory The handle for the memory block
+ * @return The size of the memory block
+ */
+__inline__ size_t metal_memory_get_size(const struct metal_memory *memory) {
+ return memory->_size;
+}
+
+/*!
+ * @brief Query if a memory block supports atomic operations
+ * @param memory The handle for the memory block
+ * @return nonzero if the memory block supports atomic operations
+ */
+__inline__ int metal_memory_supports_atomics(const struct metal_memory *memory) {
+ return memory->_attrs.A;
+}
+
+/*!
+ * @brief Query if a memory block is cacheable
+ * @param memory The handle for the memory block
+ * @return nonzero if the memory block is cachable
+ */
+__inline__ int metal_memory_is_cachable(const struct metal_memory *memory) {
+ return memory->_attrs.C;
+}
+
+#endif /* METAL__MEMORY_H */
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__PMP_H
+#define METAL__PMP_H
+
+/*!
+ * @file metal/pmp.h
+ *
+ * @brief API for Configuring Physical Memory Protection on RISC-V Cores
+ *
+ * The Physical Memory Protection (PMP) interface on RISC-V cores
+ * is a form of memory protection unit which allows for a finite number
+ * of physical memory regions to be configured with certain access
+ * permissions.
+ *
+ * Additional information about the use and configuration rules for PMPs
+ * can be found by reading the RISC-V Privileged Architecture Specification.
+ */
+
+#include <stddef.h>
+#include <metal/machine.h>
+
+struct metal_pmp;
+
+/*!
+ * @brief Set of available PMP addressing modes
+ */
+enum metal_pmp_address_mode {
+ /*! @brief Disable the PMP region */
+ METAL_PMP_OFF = 0,
+ /*! @brief Use Top-of-Range mode */
+ METAL_PMP_TOR = 1,
+ /*! @brief Use naturally-aligned 4-byte region mode */
+ METAL_PMP_NA4 = 2,
+ /*! @brief Use naturally-aligned power-of-two mode */
+ METAL_PMP_NAPOT = 3
+};
+
+/*!
+ * @brief Configuration for a PMP region
+ */
+struct metal_pmp_config {
+ /*! @brief Sets whether reads to the PMP region succeed */
+ unsigned int R : 1;
+ /*! @brief Sets whether writes to the PMP region succeed */
+ unsigned int W : 1;
+ /*! @brief Sets whether the PMP region is executable */
+ unsigned int X : 1;
+
+ /*! @brief Sets the addressing mode of the PMP region */
+ enum metal_pmp_address_mode A : 2;
+
+ int _pad : 2;
+
+ /*! @brief Sets whether the PMP region is locked */
+ enum metal_pmp_locked {
+ METAL_PMP_UNLOCKED = 0,
+ METAL_PMP_LOCKED = 1
+ } L : 1;
+};
+
+/*!
+ * @brief A handle for the PMP device
+ */
+struct metal_pmp {
+ /* The minimum granularity of the PMP region. Set by metal_pmp_init */
+ uintptr_t _granularity[METAL_MAX_CORES];
+};
+
+/*!
+ * @brief Get the PMP device handle
+ */
+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
+ * @param pmp The PMP device handle to be initialized
+ *
+ * The PMP initialization routine is optional and may be called as many times
+ * as is desired. The effect of the initialization routine is to attempt to set
+ * all regions to unlocked and disabled, as well as to clear the X, W, and R
+ * bits. Only the pmp configuration of the hart which executes the routine will
+ * be affected.
+ *
+ * If any regions are fused to preset values by the implementation or locked,
+ * those PMP regions will silently remain uninitialized.
+ */
+void metal_pmp_init(struct metal_pmp *pmp);
+
+/*!
+ * @brief Configure a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to configure
+ * @param config The desired configuration of the PMP region
+ * @param address The desired address of the PMP region
+ * @return 0 upon success
+ */
+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
+ * @param pmp The PMP device handle
+ * @param region The PMP region to read
+ * @param config Variable to store the PMP region configuration
+ * @param address Variable to store the PMP region address
+ * @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);
+
+/*!
+ * @brief Lock a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to lock
+ * @return 0 if the region is successfully locked
+ */
+int metal_pmp_lock(struct metal_pmp *pmp, unsigned int region);
+
+/*!
+ * @brief Set the address for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to set
+ * @param address The desired address of the PMP region
+ * @return 0 if the address is successfully set
+ */
+int metal_pmp_set_address(struct metal_pmp *pmp, unsigned int region, size_t address);
+
+/*!
+ * @brief Get the address of a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to read
+ * @return The address of the PMP region, or 0 if the region could not be read
+ */
+size_t metal_pmp_get_address(struct metal_pmp *pmp, unsigned int region);
+
+/*!
+ * @brief Set the addressing mode of a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to set
+ * @param mode The PMP addressing mode to 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);
+
+/*!
+ * @brief Get the addressing mode of a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to read
+ * @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);
+
+/*!
+ * @brief Set the executable bit for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to set
+ * @param X The desired value of the executable bit
+ * @return 0 if the executable bit is successfully set
+ */
+int metal_pmp_set_executable(struct metal_pmp *pmp, unsigned int region, int X);
+
+/*!
+ * @brief Get the executable bit for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to read
+ * @return the value of the executable bit
+ */
+int metal_pmp_get_executable(struct metal_pmp *pmp, unsigned int region);
+
+/*!
+ * @brief Set the writable bit for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to set
+ * @param W The desired value of the writable bit
+ * @return 0 if the writable bit is successfully set
+ */
+int metal_pmp_set_writeable(struct metal_pmp *pmp, unsigned int region, int W);
+
+/*!
+ * @brief Get the writable bit for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to read
+ * @return the value of the writable bit
+ */
+int metal_pmp_get_writeable(struct metal_pmp *pmp, unsigned int region);
+
+/*!
+ * @brief Set the readable bit for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to set
+ * @param R The desired value of the readable bit
+ * @return 0 if the readable bit is successfully set
+ */
+int metal_pmp_set_readable(struct metal_pmp *pmp, unsigned int region, int R);
+
+/*!
+ * @brief Set the readable bit for a PMP region
+ * @param pmp The PMP device handle
+ * @param region The PMP region to read
+ * @return the value of the readable bit
+ */
+int metal_pmp_get_readable(struct metal_pmp *pmp, unsigned int region);
+
+#endif
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__PRIVILEGE_H
+#define METAL__PRIVILEGE_H
+
+/*!
+ * @file metal/privilege.h
+ *
+ * @brief API for manipulating the privilege mode of a RISC-V system
+ *
+ * Additional information about privilege modes on RISC-V systems can be found
+ * by reading the RISC-V Privileged Architecture Specification v1.10.
+ */
+
+#include <stdint.h>
+
+enum metal_privilege_mode {
+ METAL_PRIVILEGE_USER = 0,
+ METAL_PRIVILEGE_SUPERVISOR = 1,
+ METAL_PRIVILEGE_MACHINE = 3,
+};
+
+#if __riscv_xlen == 32
+typedef uint32_t metal_xreg_t;
+#elif __riscv_xlen == 64
+typedef uint64_t metal_xreg_t;
+#endif
+
+#if __riscv_flen == 32
+typedef uint32_t metal_freg_t;
+#elif __riscv_flen == 64
+typedef uint64_t metal_freg_t;
+#endif
+
+struct metal_register_file {
+ metal_xreg_t ra;
+ metal_xreg_t sp;
+ metal_xreg_t gp;
+ metal_xreg_t tp;
+
+ metal_xreg_t t0;
+ metal_xreg_t t1;
+ metal_xreg_t t2;
+
+ metal_xreg_t s0;
+ metal_xreg_t s1;
+
+ metal_xreg_t a0;
+ metal_xreg_t a1;
+ metal_xreg_t a2;
+ metal_xreg_t a3;
+ metal_xreg_t a4;
+ metal_xreg_t a5;
+#ifndef __riscv_32e
+ metal_xreg_t a6;
+ metal_xreg_t a7;
+
+ metal_xreg_t s2;
+ metal_xreg_t s3;
+ metal_xreg_t s4;
+ metal_xreg_t s5;
+ metal_xreg_t s6;
+ metal_xreg_t s7;
+ metal_xreg_t s8;
+ metal_xreg_t s9;
+ metal_xreg_t s10;
+ metal_xreg_t s11;
+
+ metal_xreg_t t3;
+ metal_xreg_t t4;
+ metal_xreg_t t5;
+ metal_xreg_t t6;
+#endif /* __riscv_32e */
+
+#ifdef __riscv_flen
+ metal_freg_t ft0;
+ metal_freg_t ft1;
+ metal_freg_t ft2;
+ metal_freg_t ft3;
+ metal_freg_t ft4;
+ metal_freg_t ft5;
+ metal_freg_t ft6;
+ metal_freg_t ft7;
+
+ metal_freg_t fs0;
+ metal_freg_t fs1;
+
+ metal_freg_t fa0;
+ metal_freg_t fa1;
+ metal_freg_t fa2;
+ metal_freg_t fa3;
+ metal_freg_t fa4;
+ metal_freg_t fa5;
+ metal_freg_t fa6;
+ metal_freg_t fa7;
+
+ metal_freg_t fs2;
+ metal_freg_t fs3;
+ metal_freg_t fs4;
+ metal_freg_t fs5;
+ metal_freg_t fs6;
+ metal_freg_t fs7;
+ metal_freg_t fs8;
+ metal_freg_t fs9;
+ metal_freg_t fs10;
+ metal_freg_t fs11;
+
+ metal_freg_t ft8;
+ metal_freg_t ft9;
+ metal_freg_t ft10;
+ metal_freg_t ft11;
+#endif /* __riscv_flen */
+};
+
+typedef void (*metal_privilege_entry_point_t)(void);
+
+void metal_privilege_drop_to_mode(enum metal_privilege_mode mode,
+ struct metal_register_file regfile,
+ metal_privilege_entry_point_t entry_point);
+
+#endif
--- /dev/null
+/* 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
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__SHUTDOWN_H
+#define METAL__SHUTDOWN_H
+
+/*!
+ * @file shutdown.h
+ * @brief API for shutting down a machine
+ */
+
+struct __metal_shutdown;
+
+struct __metal_shutdown_vtable {
+ void (*exit)(const struct __metal_shutdown *sd, int code) __attribute__((noreturn));
+};
+
+struct __metal_shutdown {
+ 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, int code) { sd->vtable->exit(sd, code); }
+
+/*!
+ * @brief The public METAL shutdown interface
+ *
+ * Shuts down the machine, if the machine enables an interface for
+ * shutting down. When no interface is provided, will cause the machine
+ * to spin indefinitely.
+ *
+ * @param code The return code to set. 0 indicates program success.
+ */
+void metal_shutdown(int code) __attribute__((noreturn));
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__SPI_H
+#define METAL__SPI_H
+
+struct metal_spi;
+
+/*! @brief The configuration for a SPI transfer */
+struct metal_spi_config {
+ /*! @brief The protocol for the SPI transfer */
+ enum {
+ METAL_SPI_SINGLE,
+ METAL_SPI_DUAL,
+ METAL_SPI_QUAD
+ } protocol;
+
+ /*! @brief The polarity of the SPI transfer, equivalent to CPOL */
+ unsigned int polarity : 1;
+ /*! @brief The phase of the SPI transfer, equivalent to CPHA */
+ unsigned int phase : 1;
+ /*! @brief The endianness of the SPI transfer */
+ unsigned int little_endian : 1;
+ /*! @brief The active state of the chip select line */
+ unsigned int cs_active_high : 1;
+ /*! @brief The chip select ID to activate for the SPI transfer */
+ 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 {
+ 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 (*get_baud_rate)(struct metal_spi *spi);
+ int (*set_baud_rate)(struct metal_spi *spi, int baud_rate);
+};
+
+/*! @brief A handle for a SPI device */
+struct metal_spi {
+ const struct metal_spi_vtable *vtable;
+};
+
+/*! @brief Get a handle for a 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*/
+struct metal_spi *metal_spi_get_device(unsigned int device_num);
+
+/*! @brief Initialize a SPI device with a certain baud rate
+ * @param spi The handle for the SPI device to initialize
+ * @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); }
+
+/*! @brief Perform a SPI transfer
+ * @param spi The handle for the SPI device to perform the transfer
+ * @param config The configuration for the SPI 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 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
+ */
+__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);
+}
+
+/*! @brief Get the current baud rate of the SPI device
+ * @param spi The handle for the SPI device
+ * @return The baud rate in Hz
+ */
+__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
+ * @param spi The handle for the SPI device
+ * @param baud_rate The desired baud rate of the SPI device
+ * @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); }
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__SWITCH_H
+#define METAL__SWITCH_H
+
+/*!
+ * @file switch.h
+ * @brief API for reading toggle switches
+ */
+
+#include <metal/interrupt.h>
+
+struct metal_switch;
+
+struct metal_switch_vtable {
+ int (*switch_exist)(struct metal_switch *sw, char *label);
+ struct metal_interrupt* (*interrupt_controller)(struct metal_switch *sw);
+ int (*get_interrupt_id)(struct metal_switch *sw);
+};
+
+/*!
+ * @brief A handle for a switch
+ */
+struct metal_switch {
+ const struct metal_switch_vtable *vtable;
+};
+
+/*!
+ * @brief Get a handle for a 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
+ */
+struct metal_switch* metal_switch_get(char *label);
+
+/*!
+ * @brief Get the interrupt controller for a switch
+ * @param sw The handle for the switch
+ * @return The interrupt controller handle
+ */
+__inline__ struct metal_interrupt*
+ metal_switch_interrupt_controller(struct metal_switch *sw) { return sw->vtable->interrupt_controller(sw); }
+
+/*!
+ * @brief Get the interrupt id for a switch
+ * @param sw The handle 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); }
+
+#endif
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__TIME_H
+#define METAL__TIME_H
+
+#include <time.h>
+
+/*!
+ * @file time.h
+ * @brief API for dealing with time
+ */
+
+int metal_gettimeofday(struct timeval *tp, void *tzp);
+
+time_t metal_time(void);
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__TIMER_H
+#define METAL__TIMER_H
+
+/*!
+ * @file timer.h
+ * @brief API for reading and manipulating the machine timer
+ */
+
+/*!
+ * @brief Read the machine cycle count
+ * @param hartid The hart ID to read the cycle count of
+ * @param cyclecount The variable to hold the value
+ * @return 0 upon success
+ */
+int metal_timer_get_cyclecount(int hartid, unsigned long long *cyclecount);
+
+/*!
+ * @brief Get the machine timebase frequency
+ * @param hartid The hart ID to read the timebase of
+ * @param timebase The variable to hold the value
+ * @return 0 upon success
+ */
+int metal_timer_get_timebase_frequency(int hartid, unsigned long long *timebase);
+
+/*!
+ * @brief Set the machine timer tick interval in seconds
+ * @param hartid The hart ID to read the timebase of
+ * @param second The number of seconds to set the tick interval to
+ * @return 0 upon success
+ */
+int metal_timer_set_tick(int hartid, int second);
+
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__TTY_H
+#define METAL__TTY_H
+
+/*!
+ * @file tty.h
+ * @brief API for emulated serial teriminals
+ */
+
+/*!
+ * @brief Write a character to the default output device
+ *
+ * Write a character to the default output device, which for most
+ * targets is the UART serial port.
+ *
+ * putc() does CR/LF mapping.
+ * putc_raw() does not.
+ *
+ * @param c The character to write to the terminal
+ * @return 0 on success, or -1 on failure.
+ */
+int metal_tty_putc(int c);
+
+/*!
+ * @brief Write a raw character to the default output device
+ *
+ * Write a character to the default output device, which for most
+ * targets is the UART serial port.
+ *
+ * putc() does CR/LF mapping.
+ * putc_raw() does not.
+ *
+ * @param c The character to write to the terminal
+ * @return 0 on success, or -1 on failure.
+ */
+int metal_tty_putc_raw(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
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef METAL__UART_H
+#define METAL__UART_H
+
+/*!
+ * @file uart.h
+ * @brief API for UART serial ports
+ */
+
+#include <metal/interrupt.h>
+
+struct metal_uart;
+#undef getc
+#undef putc
+struct metal_uart_vtable {
+ void (*init)(struct metal_uart *uart, int baud_rate);
+ int (*putc)(struct metal_uart *uart, int c);
+ int (*txready)(struct metal_uart *uart);
+ int (*getc)(struct metal_uart *uart, int *c);
+ int (*get_baud_rate)(struct metal_uart *uart);
+ int (*set_baud_rate)(struct metal_uart *uart, int baud_rate);
+ struct metal_interrupt* (*controller_interrupt)(struct metal_uart *uart);
+ int (*get_interrupt_id)(struct metal_uart *uart);
+};
+
+/*!
+ * @brief Handle for a UART serial device
+ */
+struct metal_uart {
+ const struct metal_uart_vtable *vtable;
+};
+
+/*!
+ * @brief Initialize UART device
+
+ * Initialize the UART device described by the UART handle. This function must 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 baud_rate the baud rate to set the UART to
+ */
+__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
+ * @param uart The UART device handle
+ * @param c The character to send over the UART
+ * @return 0 upon success
+ */
+__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
+ * @param uart The UART device handle
+ * @param c The varible to hold the read character
+ * @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, int *c) { return uart->vtable->getc(uart, c); }
+
+/*!
+ * @brief Get the baud rate of the UART peripheral
+ * @param uart The UART device handle
+ * @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); }
+
+/*!
+ * @brief Set the baud rate of the UART peripheral
+ * @param uart The UART device handle
+ * @param baud_rate The baud rate to configure
+ * @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); }
+
+/*!
+ * @brief Get the interrupt controller of the UART peripheral
+ *
+ * Get the interrupt controller for the UART peripheral. The interrupt
+ * controller must be initialized before any interrupts can be registered
+ * or enabled with it.
+ *
+ * @param uart The UART device handle
+ * @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); }
+
+/*!
+ * @brief Get the interrupt ID of the UART controller
+ * @param uart The UART device handle
+ * @return The UART interrupt id
+ */
+__inline__ int metal_uart_get_interrupt_id(struct metal_uart *uart) { return uart->vtable->get_interrupt_id(uart); }
+
+#endif
--- /dev/null
+/* 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 */
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/button.h>
+#include <metal/machine.h>
+
+struct metal_button* metal_button_get (char *label)
+{
+ int i;
+ struct metal_button *button;
+
+ if ((__METAL_DT_MAX_BUTTONS == 0) || (label == NULL)) {
+ return NULL;
+ }
+
+ for (i = 0; i < __METAL_DT_MAX_BUTTONS; i++) {
+ button = (struct metal_button*)__metal_button_table[i];
+ if (button->vtable->button_exist(button, label)) {
+ return button;
+ }
+ }
+ return NULL;
+}
+
+extern __inline__ struct metal_interrupt*
+ metal_button_interrupt_controller(struct metal_button *button);
+extern __inline__ int metal_button_get_interrupt_id(struct metal_button *button);
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/cache.h>
+#include <metal/machine.h>
+
+extern __inline__ void metal_cache_init(struct metal_cache *cache, int ways);
+extern __inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache);
+extern __inline__ int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways);
+
+int metal_dcache_l1_available(int hartid) {
+ switch (hartid) {
+ case 0:
+#ifdef __METAL_CPU_0_DCACHE_HANDLE
+ return __METAL_CPU_0_DCACHE_HANDLE;
+#endif
+ break;
+ case 1:
+#ifdef __METAL_CPU_1_DCACHE_HANDLE
+ return __METAL_CPU_1_DCACHE_HANDLE;
+#endif
+ break;
+ case 2:
+#ifdef __METAL_CPU_2_DCACHE_HANDLE
+ return __METAL_CPU_2_DCACHE_HANDLE;
+#endif
+ break;
+ case 3:
+#ifdef __METAL_CPU_3_DCACHE_HANDLE
+ return __METAL_CPU_3_DCACHE_HANDLE;
+#endif
+ break;
+ case 4:
+#ifdef __METAL_CPU_4_DCACHE_HANDLE
+ return __METAL_CPU_4_DCACHE_HANDLE;
+#endif
+ break;
+ case 5:
+#ifdef __METAL_CPU_5_DCACHE_HANDLE
+ return __METAL_CPU_5_DCACHE_HANDLE;
+#endif
+ break;
+ case 6:
+#ifdef __METAL_CPU_6_DCACHE_HANDLE
+ return __METAL_CPU_6_DCACHE_HANDLE;
+#endif
+ break;
+ case 7:
+#ifdef __METAL_CPU_7_DCACHE_HANDLE
+ return __METAL_CPU_7_DCACHE_HANDLE;
+#endif
+ break;
+ case 8:
+#ifdef __METAL_CPU_8_DCACHE_HANDLE
+ return __METAL_CPU_8_DCACHE_HANDLE;
+#endif
+ break;
+ }
+ return 0;
+}
+
+int metal_icache_l1_available(int hartid) {
+ switch (hartid) {
+ case 0:
+#ifdef __METAL_CPU_0_ICACHE_HANDLE
+ return __METAL_CPU_0_ICACHE_HANDLE;
+#endif
+ break;
+ case 1:
+#ifdef __METAL_CPU_1_ICACHE_HANDLE
+ return __METAL_CPU_1_ICACHE_HANDLE;
+#endif
+ break;
+ case 2:
+#ifdef __METAL_CPU_2_ICACHE_HANDLE
+ return __METAL_CPU_2_ICACHE_HANDLE;
+#endif
+ break;
+ case 3:
+#ifdef __METAL_CPU_3_ICACHE_HANDLE
+ return __METAL_CPU_3_ICACHE_HANDLE;
+#endif
+ break;
+ case 4:
+#ifdef __METAL_CPU_4_ICACHE_HANDLE
+ return __METAL_CPU_4_ICACHE_HANDLE;
+#endif
+ break;
+ case 5:
+#ifdef __METAL_CPU_5_ICACHE_HANDLE
+ return __METAL_CPU_5_ICACHE_HANDLE;
+#endif
+ break;
+ case 6:
+#ifdef __METAL_CPU_6_ICACHE_HANDLE
+ return __METAL_CPU_6_ICACHE_HANDLE;
+#endif
+ break;
+ case 7:
+#ifdef __METAL_CPU_7_ICACHE_HANDLE
+ return __METAL_CPU_7_ICACHE_HANDLE;
+#endif
+ break;
+ case 8:
+#ifdef __METAL_CPU_8_ICACHE_HANDLE
+ return __METAL_CPU_8_ICACHE_HANDLE;
+#endif
+ break;
+ }
+ return 0;
+}
+
+/*!
+ * @brief CFlush.D.L1 instruction is a custom instruction implemented as a
+ * state machine in L1 Data Cache (D$) with funct3=0, (for core with data caches)
+ * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
+ * 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0
+ * |--------|--------|--------|--------|--------|--------|--------|--------|
+ * +-------------+------------+----------+------+--------+-----------------+
+ * |sign immediate12b (simm12)| rs1 | func3| rd | opcode |
+ * |-1-1-1-1 -1-1-0-0 -0-0-0-0|-x-x-x-x-x|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1|
+ * +--------------------------+----------+------+--------+-----------------+
+ * 31 -0x40 20 15 0 12 x0 7 0x73 0
+ * +--------+--------+--------+----------+------+--------+--------+--------+
+ * where,
+ * rs1 = 0x0, CFLUSH.D.L1 writes back and invalidates all lines in the L1 D$
+ * rs1 != x0, CFLUSH.D.L1 writes back and invalidates the L1 D$ line containing
+ * the virtual address in integer register rs1.
+ */
+void metal_dcache_l1_flush(int hartid, uintptr_t address)
+{
+ if (metal_dcache_l1_available(hartid)) {
+ // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
+ __asm__ __volatile__ (".insn i 0x73, 0, x0, %0, -0x40" : : "r" (address));
+ __asm__ __volatile__ ("fence.i"); // FENCE
+ }
+}
+
+/*!
+ * @brief CDiscard.D.L1 instruction is a custom instruction implemented as a
+ * state machine in L1 Data Cache (D$) with funct3=0, (for core with data caches)
+ * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
+ * 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0
+ * |--------|--------|--------|--------|--------|--------|--------|--------|
+ * +-------------+------------+----------+------+--------+-----------------+
+ * |sign immediate12b (simm12)| rs1 | func3| rd | opcode |
+ * |-1-1-1-1 -1-1-0-0 -0-0-0-0|-x-x-x-x-x|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1|
+ * +--------------------------+----------+------+--------+-----------------+
+ * 31 -0x3E 20 15 0 12 x0 7 0x73 0
+ * +--------+--------+--------+----------+------+--------+--------+--------+
+ * where,
+ * rs1 = 0x0, CDISCARD.D.L1 invalidates all lines in the L1 D$ with no writes back.
+ * rs1 != x0, CDISCARD.D.L1 invalidates the L1 D$ line containing the virtual address
+ * in integer register rs1, with no writes back.
+ */
+void metal_dcache_l1_discard(int hartid, uintptr_t address)
+{
+ if (metal_dcache_l1_available(hartid)) {
+ // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
+ __asm__ __volatile__ (".insn i 0x73, 0, x0, %0, -0x3E" : : "r" (address));
+ __asm__ __volatile__ ("fence.i"); // FENCE
+ }
+}
+
+/*!
+ * @brief CFlush.I.L1 instruction is a custom instruction implemented as a state
+ * machine in L1 Instruction Cache (I$) with funct3=0, (for core with data caches)
+ * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
+ * 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0
+ * |--------|--------|--------|--------|--------|--------|--------|--------|
+ * +-------------+------------+----------+------+--------+-----------------+
+ * |sign immediate12b (simm12)| rs1 | func3| rd | opcode |
+ * |-1-1-1-1 -1-1-0-0 -0-0-0-0|-0-0-0-0-0|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1|
+ * +--------------------------+----------+------+--------+-----------------+
+ * 31 -0x3F 20 15 0 12 x0 7 0x73 0
+ * +--------+--------+--------+----------+------+--------+--------+--------+
+ * CFLUSH.I.L1 invalidates all lines in the L1 I$.
+ */
+void metal_icache_l1_flush(int hartid)
+{
+ if (metal_icache_l1_available(hartid)) {
+ // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
+ __asm__ __volatile__ (".insn i 0x73, 0, x0, x0, -0x3F" : : );
+ __asm__ __volatile__ ("fence.i"); // FENCE
+ }
+}
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/clock.h>
+
+extern __inline__ void _metal_clock_call_all_callbacks(const metal_clock_callback *const list);
+extern __inline__ metal_clock_callback *_metal_clock_append_to_callbacks(metal_clock_callback *list, metal_clock_callback *const cb);
+
+extern __inline__ long metal_clock_get_rate_hz(const struct metal_clock *clk);
+extern __inline__ long metal_clock_set_rate_hz(struct metal_clock *clk, long hz);
+extern __inline__ void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb);
+extern __inline__ void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb);
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/cpu.h>
+#include <metal/machine.h>
+
+struct metal_cpu* metal_cpu_get(unsigned int hartid)
+{
+ if (hartid < __METAL_DT_MAX_HARTS) {
+ return (struct metal_cpu *)__metal_cpu_table[hartid];
+ }
+ return NULL;
+}
+
+int metal_cpu_get_current_hartid()
+{
+#ifdef __riscv
+ int mhartid;
+ __asm__ volatile("csrr %0, mhartid" : "=r" (mhartid));
+ return mhartid;
+#endif
+}
+
+int metal_cpu_get_num_harts()
+{
+ return __METAL_DT_MAX_HARTS;
+}
+
+extern __inline__ unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu);
+
+extern __inline__ unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu);
+
+extern __inline__ unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu);
+
+extern __inline__ int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time);
+
+extern __inline__ struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu);
+
+extern __inline__ int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu);
+
+extern __inline__ struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu);
+
+extern __inline__ int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu);
+
+extern __inline__ int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid);
+
+extern __inline__ int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid);
+
+extern __inline__ int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid);
+
+extern __inline__ struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu);
+
+extern __inline__ int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler);
+
+extern __inline__ int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc);
+
+extern __inline__ uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu);
+
+extern __inline__ int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc);
--- /dev/null
+/* Copyright 2018 SiFive, Inc. */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_FIXED_CLOCK
+
+#include <metal/drivers/fixed-clock.h>
+#include <stddef.h>
+#include <metal/machine.h>
+
+long __metal_driver_fixed_clock_get_rate_hz(const struct metal_clock *gclk)
+{
+ return __metal_driver_fixed_clock_rate(gclk);
+}
+
+long __metal_driver_fixed_clock_set_rate_hz(struct metal_clock *gclk, long target_hz)
+{
+ return __metal_driver_fixed_clock_get_rate_hz(gclk);
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_fixed_clock) = {
+ .clock.get_rate_hz = __metal_driver_fixed_clock_get_rate_hz,
+ .clock.set_rate_hz = __metal_driver_fixed_clock_set_rate_hz,
+};
+
+#endif /* METAL_FIXED_CLOCK */
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc. */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_FIXED_FACTOR_CLOCK
+
+#include <metal/drivers/fixed-factor-clock.h>
+#include <stddef.h>
+#include <metal/machine.h>
+
+long __metal_driver_fixed_factor_clock_get_rate_hz(const struct metal_clock *gclk)
+{
+ struct metal_clock *parent = __metal_driver_fixed_factor_clock_parent(gclk);
+ long parent_rate = 1;
+ if(parent) {
+ parent_rate = parent->vtable->get_rate_hz(parent);
+ }
+
+ return __metal_driver_fixed_factor_clock_mult(gclk) * parent_rate / __metal_driver_fixed_factor_clock_div(gclk);
+}
+
+long __metal_driver_fixed_factor_clock_set_rate_hz(struct metal_clock *gclk, long target_hz)
+{
+ return __metal_driver_fixed_factor_clock_get_rate_hz(gclk);
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_fixed_factor_clock) = {
+ .clock.get_rate_hz = __metal_driver_fixed_factor_clock_get_rate_hz,
+ .clock.set_rate_hz = __metal_driver_fixed_factor_clock_set_rate_hz,
+};
+#endif /* METAL_FIXED_FACTOR_CLOCK */
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/inline.h>
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_RISCV_CLINT0
+
+#include <metal/io.h>
+#include <metal/cpu.h>
+#include <metal/drivers/riscv_clint0.h>
+#include <metal/machine.h>
+
+unsigned long long __metal_clint0_mtime_get (struct __metal_driver_riscv_clint0 *clint)
+{
+ __metal_io_u32 lo, hi;
+ unsigned long control_base = __metal_driver_sifive_clint0_control_base(&clint->controller);
+
+ /* Guard against rollover when reading */
+ do {
+ hi = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_RISCV_CLINT0_MTIME + 4));
+ lo = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_RISCV_CLINT0_MTIME));
+ } while (__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_RISCV_CLINT0_MTIME + 4)) != hi);
+
+ return (((unsigned long long)hi) << 32) | lo;
+}
+
+int __metal_driver_riscv_clint0_mtimecmp_set(struct metal_interrupt *controller,
+ int hartid,
+ unsigned long long time)
+{
+ struct __metal_driver_riscv_clint0 *clint =
+ (struct __metal_driver_riscv_clint0 *)(controller);
+ unsigned long control_base = __metal_driver_sifive_clint0_control_base(&clint->controller);
+ /* Per spec, the RISC-V MTIME/MTIMECMP registers are 64 bit,
+ * and are NOT internally latched for multiword transfers.
+ * Need to be careful about sequencing to avoid triggering
+ * spurious interrupts: For that set the high word to a max
+ * value first.
+ */
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_RISCV_CLINT0_MTIMECMP_BASE + 4)) = 0xFFFFFFFF;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_RISCV_CLINT0_MTIMECMP_BASE)) = (__metal_io_u32)time;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_RISCV_CLINT0_MTIMECMP_BASE + 4)) = (__metal_io_u32)(time >> 32);
+ return 0;
+}
+
+static struct metal_interrupt *_get_cpu_intc()
+{
+ int hartid = 0;
+ __asm__ volatile("csrr %[hartid], mhartid"
+ : [hartid] "=r" (hartid) :: "memory");
+
+ struct metal_cpu *cpu = metal_cpu_get(hartid);
+
+ return metal_cpu_interrupt_controller(cpu);
+}
+
+void __metal_driver_riscv_clint0_init (struct metal_interrupt *controller)
+{
+ int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller);
+ struct __metal_driver_riscv_clint0 *clint =
+ (struct __metal_driver_riscv_clint0 *)(controller);
+
+ if ( !clint->init_done ) {
+ /* Register its interrupts with with parent controller, aka sw and timerto its default isr */
+ for (int i = 0; i < num_interrupts; i++) {
+ struct metal_interrupt *intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i);
+ int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i);
+ intc->vtable->interrupt_register(intc, line, NULL, controller);
+ }
+ clint->init_done = 1;
+ }
+}
+
+int __metal_driver_riscv_clint0_register (struct metal_interrupt *controller,
+ int id, metal_interrupt_handler_t isr,
+ void *priv)
+{
+ int rc = -1;
+ metal_vector_mode mode = __metal_controller_interrupt_vector_mode();
+ struct metal_interrupt *intc = NULL;
+ struct metal_interrupt *cpu_intc = _get_cpu_intc();
+ int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller);
+
+ if ( (mode != METAL_VECTOR_MODE) && (mode != METAL_DIRECT_MODE) ) {
+ return rc;
+ }
+
+ for(int i = 0; i < num_interrupts; i++) {
+ int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i);
+ intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i);
+ if (cpu_intc == intc && id == line) {
+ break;
+ }
+ intc = NULL;
+ }
+
+ /* Register its interrupts with parent controller */
+ if (intc) {
+ rc = intc->vtable->interrupt_register(intc, id, isr, priv);
+ }
+ return rc;
+}
+
+int __metal_driver_riscv_clint0_vector_register (struct metal_interrupt *controller,
+ int id, metal_interrupt_vector_handler_t isr,
+ void *priv)
+{
+ /* Not supported. User can override the 'weak' handler with their own */
+ int rc = -1;
+ return rc;
+}
+
+metal_vector_mode __metal_driver_riscv_clint0_get_vector_mode (struct metal_interrupt *controller)
+{
+ return __metal_controller_interrupt_vector_mode();
+}
+
+int __metal_driver_riscv_clint0_set_vector_mode (struct metal_interrupt *controller, metal_vector_mode mode)
+{
+ int rc = -1;
+ struct metal_interrupt *intc = _get_cpu_intc();
+
+ if (intc) {
+ /* Valid vector modes are VECTOR and DIRECT, anything else is invalid (-1) */
+ switch (mode) {
+ case METAL_VECTOR_MODE:
+ case METAL_DIRECT_MODE:
+ rc = intc->vtable->interrupt_set_vector_mode(intc, mode);
+ break;
+ case METAL_HARDWARE_VECTOR_MODE:
+ case METAL_SELECTIVE_NONVECTOR_MODE:
+ case METAL_SELECTIVE_VECTOR_MODE:
+ break;
+ }
+ }
+ return rc;
+}
+
+int __metal_driver_riscv_clint0_enable (struct metal_interrupt *controller, int id)
+{
+ int rc = -1;
+
+ if ( id ) {
+ struct metal_interrupt *intc = NULL;
+ struct metal_interrupt *cpu_intc = _get_cpu_intc();
+ int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller);
+
+ for(int i = 0; i < num_interrupts; i++) {
+ int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i);
+ intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i);
+ if(cpu_intc == intc && id == line) {
+ break;
+ }
+ intc = NULL;
+ }
+
+ /* Enable its interrupts with parent controller */
+ if (intc) {
+ rc = intc->vtable->interrupt_enable(intc, id);
+ }
+ }
+
+ return rc;
+}
+
+int __metal_driver_riscv_clint0_disable (struct metal_interrupt *controller, int id)
+{
+ int rc = -1;
+
+ if ( id ) {
+ struct metal_interrupt *intc = NULL;
+ struct metal_interrupt *cpu_intc = _get_cpu_intc();
+ int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller);
+
+ for(int i = 0; i < num_interrupts; i++) {
+ int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i);
+ intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i);
+ if(cpu_intc == intc && id == line) {
+ break;
+ }
+ intc = NULL;
+ }
+
+ /* Disable its interrupts with parent controller */
+ if (intc) {
+ rc = intc->vtable->interrupt_disable(intc, id);
+ }
+ }
+
+ return rc;
+}
+
+int __metal_driver_riscv_clint0_command_request (struct metal_interrupt *controller,
+ int command, void *data)
+{
+ int hartid;
+ int rc = -1;
+ struct __metal_driver_riscv_clint0 *clint =
+ (struct __metal_driver_riscv_clint0 *)(controller);
+ unsigned long control_base = __metal_driver_sifive_clint0_control_base(controller);
+
+ switch (command) {
+ case METAL_TIMER_MTIME_GET:
+ if (data) {
+ *(unsigned long long *)data = __metal_clint0_mtime_get(clint);
+ rc = 0;
+ }
+ break;
+ case METAL_SOFTWARE_IPI_CLEAR:
+ if (data) {
+ hartid = *(int *)data;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ (hartid * 4))) = METAL_DISABLE;
+ rc = 0;
+ }
+ break;
+ case METAL_SOFTWARE_IPI_SET:
+ if (data) {
+ hartid = *(int *)data;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ (hartid * 4))) = METAL_ENABLE;
+ /* Callers of this function assume it's blocking, in the sense that
+ * the IPI is guarnteed to have been delivered before the function
+ * returns. We can't really guarnteed it's delivered, but we can
+ * read back the control register after writing it in at least an
+ * attempt to provide some semblence of ordering here. The fence
+ * ensures the read is order after the write -- it wouldn't be
+ * necessary under RVWMO because this is the same address, but we
+ * don't have an IO memory model so I'm being a bit overkill here.
+ */
+ __METAL_IO_FENCE(o,i);
+ rc = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ (hartid * 4)));
+ rc = 0;
+ }
+ break;
+ case METAL_SOFTWARE_MSIP_GET:
+ rc = 0;
+ if (data) {
+ hartid = *(int *)data;
+ rc = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ (hartid * 4)));
+ }
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+int __metal_driver_riscv_clint0_clear_interrupt (struct metal_interrupt *controller, int id)
+{
+ int hartid = metal_cpu_get_current_hartid();
+ return __metal_driver_riscv_clint0_command_request(controller,
+ METAL_SOFTWARE_IPI_CLEAR, &hartid);
+}
+
+int __metal_driver_riscv_clint0_set_interrupt (struct metal_interrupt *controller, int id)
+{
+ int hartid = metal_cpu_get_current_hartid();
+ return __metal_driver_riscv_clint0_command_request(controller,
+ METAL_SOFTWARE_IPI_SET, &hartid);
+}
+
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_clint0) = {
+ .clint_vtable.interrupt_init = __metal_driver_riscv_clint0_init,
+ .clint_vtable.interrupt_register = __metal_driver_riscv_clint0_register,
+ .clint_vtable.interrupt_vector_register = __metal_driver_riscv_clint0_vector_register,
+ .clint_vtable.interrupt_enable = __metal_driver_riscv_clint0_enable,
+ .clint_vtable.interrupt_disable = __metal_driver_riscv_clint0_disable,
+ .clint_vtable.interrupt_get_vector_mode = __metal_driver_riscv_clint0_get_vector_mode,
+ .clint_vtable.interrupt_set_vector_mode = __metal_driver_riscv_clint0_set_vector_mode,
+ .clint_vtable.interrupt_clear = __metal_driver_riscv_clint0_clear_interrupt,
+ .clint_vtable.interrupt_set = __metal_driver_riscv_clint0_set_interrupt,
+ .clint_vtable.command_request = __metal_driver_riscv_clint0_command_request,
+ .clint_vtable.mtimecmp_set = __metal_driver_riscv_clint0_mtimecmp_set,
+};
+
+#endif /* METAL_RISCV_CLINT0 */
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <stdint.h>
+#include <metal/io.h>
+#include <metal/shutdown.h>
+#include <metal/machine.h>
+
+extern void __metal_vector_table();
+unsigned long long __metal_driver_cpu_mtime_get(struct metal_cpu *cpu);
+int __metal_driver_cpu_mtimecmp_set(struct metal_cpu *cpu, unsigned long long time);
+
+struct metal_cpu *__metal_driver_cpu_get(int hartid)
+{
+ if (hartid < __METAL_DT_MAX_HARTS) {
+ return &(__metal_cpu_table[hartid]->cpu);
+ }
+ return (struct metal_cpu *)NULL;
+}
+
+uintptr_t __metal_myhart_id (void)
+{
+ uintptr_t myhart;
+ __asm__ volatile ("csrr %0, mhartid" : "=r"(myhart));
+ return myhart;
+}
+
+void __metal_zero_memory (unsigned char *base, unsigned int size)
+{
+ volatile unsigned char *ptr;
+ for (ptr = base; ptr < (base + size); ptr++){
+ *ptr = 0;
+ }
+}
+
+void __metal_interrupt_global_enable (void) {
+ uintptr_t m;
+ __asm__ volatile ("csrrs %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT));
+}
+
+void __metal_interrupt_global_disable (void) {
+ uintptr_t m;
+ __asm__ volatile ("csrrc %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT));
+}
+
+void __metal_interrupt_software_enable (void) {
+ uintptr_t m;
+ __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW));
+}
+
+void __metal_interrupt_software_disable (void) {
+ uintptr_t m;
+ __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW));
+}
+
+void __metal_interrupt_timer_enable (void) {
+ uintptr_t m;
+ __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR));
+}
+
+void __metal_interrupt_timer_disable (void) {
+ uintptr_t m;
+ __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR));
+}
+
+void __metal_interrupt_external_enable (void) {
+ uintptr_t m;
+ __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT));
+}
+
+void __metal_interrupt_external_disable (void) {
+ unsigned long m;
+ __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT));
+}
+
+void __metal_interrupt_local_enable (int id) {
+ uintptr_t b = 1 << id;
+ uintptr_t m;
+ __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(b));
+}
+
+void __metal_interrupt_local_disable (int id) {
+ uintptr_t b = 1 << id;
+ uintptr_t m;
+ __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(b));
+}
+
+void __metal_default_exception_handler (struct metal_cpu *cpu, int ecode) {
+ metal_shutdown(100);
+}
+
+void __metal_default_interrupt_handler (int id, void *priv) {
+ metal_shutdown(200);
+}
+
+/* The metal_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_interrupt_vector_handler (void) {
+ metal_shutdown(300);
+}
+
+/* The metal_software_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_software_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_SW].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_SW].handler(METAL_INTERRUPT_ID_SW, priv);
+ }
+}
+
+void __metal_default_sw_handler (int id, void *priv) {
+ uintptr_t mcause;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ __asm__ volatile ("csrr %0, mcause" : "=r"(mcause));
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ intc->metal_exception_table[mcause & METAL_MCAUSE_CAUSE]((struct metal_cpu *)cpu, id);
+ }
+}
+
+/* The metal_timer_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_timer_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_TMR].handler(METAL_INTERRUPT_ID_TMR, priv);
+ }
+}
+
+void __metal_default_timer_handler (int id, void *priv) {
+ struct metal_cpu *cpu = __metal_driver_cpu_get(__metal_myhart_id());
+ unsigned long long time = __metal_driver_cpu_mtime_get(cpu);
+
+ /* Set a 10 cycle timer */
+ __metal_driver_cpu_mtimecmp_set(cpu, time + 10);
+}
+
+/* The metal_external_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_external_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_EXT].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_EXT].handler(METAL_INTERRUPT_ID_EXT, priv);
+ }
+}
+
+void __metal_exception_handler(void) __attribute__((interrupt, aligned(128)));
+void __metal_exception_handler (void) {
+ int id;
+ void *priv;
+ uintptr_t mcause, mepc, mtval, mtvec;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ __asm__ volatile ("csrr %0, mcause" : "=r"(mcause));
+ __asm__ volatile ("csrr %0, mepc" : "=r"(mepc));
+ __asm__ volatile ("csrr %0, mtval" : "=r"(mtval));
+ __asm__ volatile ("csrr %0, mtvec" : "=r"(mtvec));
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ id = mcause & METAL_MCAUSE_CAUSE;
+ if (mcause & METAL_MCAUSE_INTR) {
+ if ((id < METAL_INTERRUPT_ID_CSW) ||
+ ((mtvec & METAL_MTVEC_MASK) == METAL_MTVEC_DIRECT)) {
+ priv = intc->metal_int_table[id].exint_data;
+ intc->metal_int_table[id].handler(id, priv);
+ return;
+ }
+ if ((mtvec & METAL_MTVEC_MASK) == METAL_MTVEC_CLIC) {
+ uintptr_t mtvt;
+ metal_interrupt_handler_t mtvt_handler;
+
+ __asm__ volatile ("csrr %0, 0x307" : "=r"(mtvt));
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
+ mtvt_handler = (metal_interrupt_handler_t)*(uintptr_t *)mtvt;
+ mtvt_handler(id, priv);
+ return;
+ }
+ } else {
+ intc->metal_exception_table[id]((struct metal_cpu *)cpu, id);
+ }
+ }
+}
+
+/* The metal_lc0_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc0_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC0].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC0].handler(METAL_INTERRUPT_ID_LC0, priv);
+ }
+}
+
+/* The metal_lc1_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc1_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC1].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC1].handler(METAL_INTERRUPT_ID_LC1, priv);
+ }
+}
+
+/* The metal_lc2_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc2_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC2].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC2].handler(METAL_INTERRUPT_ID_LC2, priv);
+ }
+}
+
+/* The metal_lc3_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc3_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC3].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC3].handler(METAL_INTERRUPT_ID_LC3, priv);
+ }
+}
+
+/* The metal_lc4_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc4_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC4].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC4].handler(METAL_INTERRUPT_ID_LC4, priv);
+ }
+}
+
+/* The metal_lc5_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc5_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC5].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC5].handler(METAL_INTERRUPT_ID_LC5, priv);
+ }
+}
+
+/* The metal_lc6_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc6_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC6].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC6].handler(METAL_INTERRUPT_ID_LC6, priv);
+ }
+}
+
+/* The metal_lc7_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc7_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC7].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC7].handler(METAL_INTERRUPT_ID_LC7, priv);
+ }
+}
+
+/* The metal_lc8_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc8_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC8].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC8].handler(METAL_INTERRUPT_ID_LC8, priv);
+ }
+}
+
+/* The metal_lc9_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc9_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC9].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC9].handler(METAL_INTERRUPT_ID_LC9, priv);
+ }
+}
+
+/* The metal_lc10_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc10_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC10].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC10].handler(METAL_INTERRUPT_ID_LC10, priv);
+ }
+}
+
+/* The metal_lc11_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc11_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC11].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC11].handler(METAL_INTERRUPT_ID_LC11, priv);
+ }
+}
+
+/* The metal_lc12_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc12_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC12].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC12].handler(METAL_INTERRUPT_ID_LC12, priv);
+ }
+}
+
+/* The metal_lc13_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc13_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC13].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC13].handler(METAL_INTERRUPT_ID_LC13, priv);
+ }
+}
+
+/* The metal_lc14_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc14_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC14].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC14].handler(METAL_INTERRUPT_ID_LC14, priv);
+ }
+}
+
+/* The metal_lc15_interrupt_vector_handler() function can be redefined. */
+void __attribute__((weak, interrupt)) metal_lc15_interrupt_vector_handler (void) {
+ void *priv;
+ struct __metal_driver_riscv_cpu_intc *intc;
+ struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
+
+ if ( cpu ) {
+ intc = (struct __metal_driver_riscv_cpu_intc *)
+ __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
+ priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC15].exint_data;
+ intc->metal_int_table[METAL_INTERRUPT_ID_LC15].handler(METAL_INTERRUPT_ID_LC15, priv);
+ }
+}
+
+metal_vector_mode __metal_controller_interrupt_vector_mode (void)
+{
+ uintptr_t val;
+
+ asm volatile ("csrr %0, mtvec" : "=r"(val));
+ val &= METAL_MTVEC_MASK;
+
+ switch (val) {
+ case METAL_MTVEC_CLIC:
+ return METAL_SELECTIVE_VECTOR_MODE;
+ case METAL_MTVEC_CLIC_VECTORED:
+ return METAL_HARDWARE_VECTOR_MODE;
+ case METAL_MTVEC_VECTORED:
+ return METAL_VECTOR_MODE;
+ }
+ return METAL_DIRECT_MODE;
+}
+
+void __metal_controller_interrupt_vector (metal_vector_mode mode, void *vec_table)
+{
+ uintptr_t trap_entry, val;
+
+ __asm__ volatile ("csrr %0, mtvec" : "=r"(val));
+ val &= ~(METAL_MTVEC_CLIC_VECTORED | METAL_MTVEC_CLIC_RESERVED);
+ trap_entry = (uintptr_t)vec_table;
+
+ switch (mode) {
+ case METAL_SELECTIVE_NONVECTOR_MODE:
+ case METAL_SELECTIVE_VECTOR_MODE:
+ __asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry));
+ __asm__ volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC));
+ break;
+ case METAL_HARDWARE_VECTOR_MODE:
+ __asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry));
+ __asm__ volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC_VECTORED));
+ break;
+ case METAL_VECTOR_MODE:
+ __asm__ volatile ("csrw mtvec, %0" :: "r"(trap_entry | METAL_MTVEC_VECTORED));
+ break;
+ case METAL_DIRECT_MODE:
+ __asm__ volatile ("csrw mtvec, %0" :: "r"(trap_entry & ~METAL_MTVEC_CLIC_VECTORED));
+ break;
+ }
+}
+
+int __metal_valid_interrupt_id (int id)
+{
+ switch (id) {
+ case METAL_INTERRUPT_ID_SW:
+ case METAL_INTERRUPT_ID_TMR:
+ case METAL_INTERRUPT_ID_EXT:
+ case METAL_INTERRUPT_ID_LC0:
+ case METAL_INTERRUPT_ID_LC1:
+ case METAL_INTERRUPT_ID_LC2:
+ case METAL_INTERRUPT_ID_LC3:
+ case METAL_INTERRUPT_ID_LC4:
+ case METAL_INTERRUPT_ID_LC5:
+ case METAL_INTERRUPT_ID_LC6:
+ case METAL_INTERRUPT_ID_LC7:
+ case METAL_INTERRUPT_ID_LC8:
+ case METAL_INTERRUPT_ID_LC9:
+ case METAL_INTERRUPT_ID_LC10:
+ case METAL_INTERRUPT_ID_LC11:
+ case METAL_INTERRUPT_ID_LC12:
+ case METAL_INTERRUPT_ID_LC13:
+ case METAL_INTERRUPT_ID_LC14:
+ case METAL_INTERRUPT_ID_LC15:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+int __metal_local_interrupt_enable (struct metal_interrupt *controller,
+ metal_interrupt_id_e id, int enable)
+{
+ int rc = 0;
+
+ if ( !controller) {
+ return -1;
+ }
+
+ switch (id) {
+ case METAL_INTERRUPT_ID_BASE:
+ if (enable) {
+ __metal_interrupt_global_enable();
+ } else {
+ __metal_interrupt_global_disable();
+ }
+ break;
+ case METAL_INTERRUPT_ID_SW:
+ if (enable) {
+ __metal_interrupt_software_enable();
+ } else {
+ __metal_interrupt_software_disable();
+ }
+ break;
+ case METAL_INTERRUPT_ID_TMR:
+ if (enable) {
+ __metal_interrupt_timer_enable();
+ } else {
+ __metal_interrupt_timer_disable();
+ }
+ break;
+ case METAL_INTERRUPT_ID_EXT:
+ if (enable) {
+ __metal_interrupt_external_enable();
+ } else {
+ __metal_interrupt_external_disable();
+ }
+ break;
+ case METAL_INTERRUPT_ID_LC0:
+ case METAL_INTERRUPT_ID_LC1:
+ case METAL_INTERRUPT_ID_LC2:
+ case METAL_INTERRUPT_ID_LC3:
+ case METAL_INTERRUPT_ID_LC4:
+ case METAL_INTERRUPT_ID_LC5:
+ case METAL_INTERRUPT_ID_LC6:
+ case METAL_INTERRUPT_ID_LC7:
+ case METAL_INTERRUPT_ID_LC8:
+ case METAL_INTERRUPT_ID_LC9:
+ case METAL_INTERRUPT_ID_LC10:
+ case METAL_INTERRUPT_ID_LC11:
+ case METAL_INTERRUPT_ID_LC12:
+ case METAL_INTERRUPT_ID_LC13:
+ case METAL_INTERRUPT_ID_LC14:
+ case METAL_INTERRUPT_ID_LC15:
+ if (enable) {
+ __metal_interrupt_local_enable(id);
+ } else {
+ __metal_interrupt_local_disable(id);
+ }
+ break;
+ default:
+ rc = -1;
+ }
+ return rc;
+}
+
+int __metal_exception_register (struct metal_interrupt *controller,
+ int ecode, metal_exception_handler_t isr)
+{
+ struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
+
+ if ((ecode < METAL_MAX_EXCEPTION_CODE) && isr) {
+ intc->metal_exception_table[ecode] = isr;
+ return 0;
+ }
+ return -1;
+}
+
+void __metal_driver_riscv_cpu_controller_interrupt_init (struct metal_interrupt *controller)
+{
+ struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
+ uintptr_t val;
+
+ if ( !intc->init_done ) {
+ /* Disable and clear all interrupt sources */
+ __asm__ volatile ("csrc mie, %0" :: "r"(-1));
+ __asm__ volatile ("csrc mip, %0" :: "r"(-1));
+
+ /* Read the misa CSR to determine if the delegation registers exist */
+ uintptr_t misa;
+ __asm__ volatile ("csrr %0, misa" : "=r" (misa));
+
+ /* The delegation CSRs exist if user mode interrupts (N extension) or
+ * supervisor mode (S extension) are supported */
+ if((misa & METAL_ISA_N_EXTENSIONS) || (misa & METAL_ISA_S_EXTENSIONS)) {
+ /* Disable interrupt and exception delegation */
+ __asm__ volatile ("csrc mideleg, %0" :: "r"(-1));
+ __asm__ volatile ("csrc medeleg, %0" :: "r"(-1));
+ }
+
+ /* The satp CSR exists if supervisor mode (S extension) is supported */
+ if(misa & METAL_ISA_S_EXTENSIONS) {
+ /* Clear the entire CSR to make sure that satp.MODE = 0 */
+ __asm__ volatile ("csrc satp, %0" :: "r"(-1));
+ }
+
+ /* Default to use direct interrupt, setup sw cb table*/
+ for (int i = 0; i < METAL_MAX_MI; i++) {
+ intc->metal_int_table[i].handler = NULL;
+ intc->metal_int_table[i].sub_int = NULL;
+ intc->metal_int_table[i].exint_data = NULL;
+ }
+ for (int i = 0; i < METAL_MAX_ME; i++) {
+ intc->metal_exception_table[i] = __metal_default_exception_handler;
+ }
+ __metal_controller_interrupt_vector(METAL_DIRECT_MODE, (void *)(uintptr_t)&__metal_exception_handler);
+ __asm__ volatile ("csrr %0, misa" : "=r"(val));
+ if (val & (METAL_ISA_D_EXTENSIONS | METAL_ISA_F_EXTENSIONS | METAL_ISA_Q_EXTENSIONS)) {
+ /* Floating point architecture, so turn on FP register saving*/
+ __asm__ volatile ("csrr %0, mstatus" : "=r"(val));
+ __asm__ volatile ("csrw mstatus, %0" :: "r"(val | METAL_MSTATUS_FS_INIT));
+ }
+ intc->init_done = 1;
+ }
+}
+
+int __metal_driver_riscv_cpu_controller_interrupt_register(struct metal_interrupt *controller,
+ int id, metal_interrupt_handler_t isr,
+ void *priv)
+{
+ int rc = 0;
+ struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
+
+ if ( !__metal_valid_interrupt_id(id) ) {
+ return -11;
+ }
+
+ if (isr) {
+ intc->metal_int_table[id].handler = isr;
+ intc->metal_int_table[id].exint_data = priv;
+ } else {
+ switch (id) {
+ case METAL_INTERRUPT_ID_SW:
+ intc->metal_int_table[id].handler = __metal_default_sw_handler;
+ intc->metal_int_table[id].sub_int = priv;
+ break;
+ case METAL_INTERRUPT_ID_TMR:
+ intc->metal_int_table[id].handler = __metal_default_timer_handler;
+ intc->metal_int_table[id].sub_int = priv;
+ break;
+ case METAL_INTERRUPT_ID_EXT:
+ case METAL_INTERRUPT_ID_LC0:
+ case METAL_INTERRUPT_ID_LC1:
+ case METAL_INTERRUPT_ID_LC2:
+ case METAL_INTERRUPT_ID_LC3:
+ case METAL_INTERRUPT_ID_LC4:
+ case METAL_INTERRUPT_ID_LC5:
+ case METAL_INTERRUPT_ID_LC6:
+ case METAL_INTERRUPT_ID_LC7:
+ case METAL_INTERRUPT_ID_LC8:
+ case METAL_INTERRUPT_ID_LC9:
+ case METAL_INTERRUPT_ID_LC10:
+ case METAL_INTERRUPT_ID_LC11:
+ case METAL_INTERRUPT_ID_LC12:
+ case METAL_INTERRUPT_ID_LC13:
+ case METAL_INTERRUPT_ID_LC14:
+ case METAL_INTERRUPT_ID_LC15:
+ intc->metal_int_table[id].handler = __metal_default_interrupt_handler;
+ intc->metal_int_table[id].sub_int = priv;
+ break;
+ default:
+ rc = -12;
+ }
+ }
+ return rc;
+}
+
+int __metal_driver_riscv_cpu_controller_interrupt_enable (struct metal_interrupt *controller,
+ int id)
+{
+ return __metal_local_interrupt_enable(controller, id, METAL_ENABLE);
+}
+
+int __metal_driver_riscv_cpu_controller_interrupt_disable (struct metal_interrupt *controller,
+ int id)
+{
+ return __metal_local_interrupt_enable(controller, id, METAL_DISABLE);
+}
+
+int __metal_driver_riscv_cpu_controller_interrupt_enable_vector(struct metal_interrupt *controller,
+ int id, metal_vector_mode mode)
+{
+ struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
+
+ if (id == METAL_INTERRUPT_ID_BASE) {
+ if (mode == METAL_DIRECT_MODE) {
+ __metal_controller_interrupt_vector(mode, (void *)(uintptr_t)&__metal_exception_handler);
+ return 0;
+ }
+ if (mode == METAL_VECTOR_MODE) {
+ __metal_controller_interrupt_vector(mode, (void *)&intc->metal_mtvec_table);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int __metal_driver_riscv_cpu_controller_interrupt_disable_vector(struct metal_interrupt *controller,
+ int id)
+{
+ if (id == METAL_INTERRUPT_ID_BASE) {
+ __metal_controller_interrupt_vector(METAL_DIRECT_MODE, (void *)(uintptr_t)&__metal_exception_handler);
+ return 0;
+ }
+ return -1;
+}
+
+metal_vector_mode __metal_driver_riscv_cpu_controller_get_vector_mode (struct metal_interrupt *controller)
+{
+ return __metal_controller_interrupt_vector_mode();
+}
+
+int __metal_driver_riscv_cpu_controller_set_vector_mode (struct metal_interrupt *controller,
+ metal_vector_mode mode)
+{
+ struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
+ ( void ) intc;
+
+ if (mode == METAL_DIRECT_MODE) {
+ __metal_controller_interrupt_vector(mode, (void *)(uintptr_t)&__metal_exception_handler);
+ return 0;
+ }
+ if (mode == METAL_VECTOR_MODE) {
+ __metal_controller_interrupt_vector(mode, (void *)__metal_vector_table);
+ return 0;
+ }
+ return -1;
+}
+
+int __metal_driver_riscv_cpu_controller_command_request (struct metal_interrupt *controller,
+ int cmd, void *data)
+{
+ /* NOP for now, unless local interrupt lines the like of clic, clint, plic */
+ return 0;
+}
+
+/* CPU driver !!! */
+
+unsigned long long __metal_driver_cpu_mcycle_get(struct metal_cpu *cpu)
+{
+ unsigned long long val = 0;
+
+#if __riscv_xlen == 32
+ unsigned long hi, hi1, lo;
+
+ __asm__ volatile ("csrr %0, mcycleh" : "=r"(hi));
+ __asm__ volatile ("csrr %0, mcycle" : "=r"(lo));
+ __asm__ volatile ("csrr %0, mcycleh" : "=r"(hi1));
+ if (hi == hi1) {
+ val = ((unsigned long long)hi << 32) | lo;
+ }
+#else
+ __asm__ volatile ("csrr %0, mcycle" : "=r"(val));
+#endif
+
+ return val;
+}
+
+unsigned long long __metal_driver_cpu_timebase_get(struct metal_cpu *cpu)
+{
+ int timebase;
+ if (!cpu) {
+ return 0;
+ }
+
+ timebase = __metal_driver_cpu_timebase((struct metal_cpu *)cpu);
+ return timebase;
+}
+
+unsigned long long __metal_driver_cpu_mtime_get (struct metal_cpu *cpu)
+{
+ unsigned long long time = 0;
+ struct metal_interrupt *tmr_intc;
+ struct __metal_driver_riscv_cpu_intc *intc =
+ (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
+
+ if (intc) {
+ tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int;
+ if (tmr_intc) {
+ tmr_intc->vtable->command_request(tmr_intc,
+ METAL_TIMER_MTIME_GET, &time);
+ }
+ }
+ return time;
+}
+
+int __metal_driver_cpu_mtimecmp_set (struct metal_cpu *cpu, unsigned long long time)
+{
+ int rc = -1;
+ struct metal_interrupt *tmr_intc;
+ struct __metal_driver_riscv_cpu_intc *intc =
+ (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
+
+ if (intc) {
+ tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int;
+ if (tmr_intc) {
+ rc = tmr_intc->vtable->mtimecmp_set(tmr_intc,
+ __metal_driver_cpu_hartid(cpu),
+ time);
+ }
+ }
+ return rc;
+}
+
+struct metal_interrupt *
+__metal_driver_cpu_timer_controller_interrupt(struct metal_cpu *cpu)
+{
+#ifdef __METAL_DT_RISCV_CLINT0_HANDLE
+ return __METAL_DT_RISCV_CLINT0_HANDLE;
+#else
+#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
+ return __METAL_DT_SIFIVE_CLIC0_HANDLE;
+#else
+#pragma message("There is no interrupt controller for Timer interrupt")
+ return NULL;
+#endif
+#endif
+}
+
+int __metal_driver_cpu_get_timer_interrupt_id(struct metal_cpu *cpu)
+{
+ return METAL_INTERRUPT_ID_TMR;
+}
+
+struct metal_interrupt *
+__metal_driver_cpu_sw_controller_interrupt(struct metal_cpu *cpu)
+{
+#ifdef __METAL_DT_RISCV_CLINT0_HANDLE
+ return __METAL_DT_RISCV_CLINT0_HANDLE;
+#else
+#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
+ return __METAL_DT_SIFIVE_CLIC0_HANDLE;
+#else
+#pragma message("There is no interrupt controller for Software interrupt")
+ return NULL;
+#endif
+#endif
+}
+
+int __metal_driver_cpu_get_sw_interrupt_id(struct metal_cpu *cpu)
+{
+ return METAL_INTERRUPT_ID_SW;
+}
+
+int __metal_driver_cpu_set_sw_ipi (struct metal_cpu *cpu, int hartid)
+{
+ int rc = -1;
+ struct metal_interrupt *sw_intc;
+ struct __metal_driver_riscv_cpu_intc *intc =
+ (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
+
+ if (intc) {
+ sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
+ if (sw_intc) {
+ rc = sw_intc->vtable->command_request(sw_intc,
+ METAL_SOFTWARE_IPI_SET, &hartid);
+ }
+ }
+ return rc;
+}
+
+int __metal_driver_cpu_clear_sw_ipi (struct metal_cpu *cpu, int hartid)
+{
+ int rc = -1;
+ struct metal_interrupt *sw_intc;
+ struct __metal_driver_riscv_cpu_intc *intc =
+ (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
+
+ if (intc) {
+ sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
+ if (sw_intc) {
+ rc = sw_intc->vtable->command_request(sw_intc,
+ METAL_SOFTWARE_IPI_CLEAR, &hartid);
+ }
+ }
+ return rc;
+}
+
+int __metal_driver_cpu_get_msip (struct metal_cpu *cpu, int hartid)
+{
+ int rc = 0;
+ struct metal_interrupt *sw_intc;
+ struct __metal_driver_riscv_cpu_intc *intc =
+ (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
+
+ if (intc) {
+ sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
+ if (sw_intc) {
+ rc = sw_intc->vtable->command_request(sw_intc,
+ METAL_SOFTWARE_MSIP_GET, &hartid);
+ }
+ }
+ return rc;
+}
+
+struct metal_interrupt *
+__metal_driver_cpu_controller_interrupt(struct metal_cpu *cpu)
+{
+ return __metal_driver_cpu_interrupt_controller(cpu);
+}
+
+int __metal_driver_cpu_enable_interrupt(struct metal_cpu *cpu, void *priv)
+{
+ if ( __metal_driver_cpu_interrupt_controller(cpu) ) {
+ /* Only support machine mode for now */
+ __metal_interrupt_global_enable();
+ return 0;
+ }
+ return -1;
+}
+
+int __metal_driver_cpu_disable_interrupt(struct metal_cpu *cpu, void *priv)
+{
+ if ( __metal_driver_cpu_interrupt_controller(cpu) ) {
+ /* Only support machine mode for now */
+ __metal_interrupt_global_disable();
+ return 0;
+ }
+ return -1;
+}
+
+int __metal_driver_cpu_exception_register(struct metal_cpu *cpu, int ecode,
+ metal_exception_handler_t isr)
+{
+ struct __metal_driver_riscv_cpu_intc *intc =
+ (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
+
+ if (intc) {
+ return __metal_exception_register((struct metal_interrupt *)intc, ecode, isr);
+ }
+ return -1;
+}
+
+int __metal_driver_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
+{
+ /**
+ * Per ISA compressed instruction has last two bits of opcode set.
+ * The encoding '00' '01' '10' are used for compressed instruction.
+ * Only enconding '11' isn't regarded as compressed instruction (>16b).
+ */
+ return ((*(unsigned short*)epc & METAL_INSN_LENGTH_MASK)
+ == METAL_INSN_NOT_COMPRESSED) ? 4 : 2;
+}
+
+uintptr_t __metal_driver_cpu_get_exception_pc(struct metal_cpu *cpu)
+{
+ uintptr_t mepc;
+ __asm__ volatile ("csrr %0, mepc" : "=r"(mepc));
+ return mepc;
+}
+
+int __metal_driver_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t mepc)
+{
+ __asm__ volatile ("csrw mepc, %0" :: "r"(mepc));
+ return 0;
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_cpu_intc) = {
+ .controller_vtable.interrupt_init = __metal_driver_riscv_cpu_controller_interrupt_init,
+ .controller_vtable.interrupt_register = __metal_driver_riscv_cpu_controller_interrupt_register,
+ .controller_vtable.interrupt_enable = __metal_driver_riscv_cpu_controller_interrupt_enable,
+ .controller_vtable.interrupt_disable = __metal_driver_riscv_cpu_controller_interrupt_disable,
+ .controller_vtable.interrupt_get_vector_mode = __metal_driver_riscv_cpu_controller_get_vector_mode,
+ .controller_vtable.interrupt_set_vector_mode = __metal_driver_riscv_cpu_controller_set_vector_mode,
+ .controller_vtable.command_request = __metal_driver_riscv_cpu_controller_command_request,
+};
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_cpu) = {
+ .cpu_vtable.mcycle_get = __metal_driver_cpu_mcycle_get,
+ .cpu_vtable.timebase_get = __metal_driver_cpu_timebase_get,
+ .cpu_vtable.mtime_get = __metal_driver_cpu_mtime_get,
+ .cpu_vtable.mtimecmp_set = __metal_driver_cpu_mtimecmp_set,
+ .cpu_vtable.tmr_controller_interrupt = __metal_driver_cpu_timer_controller_interrupt,
+ .cpu_vtable.get_tmr_interrupt_id = __metal_driver_cpu_get_timer_interrupt_id,
+ .cpu_vtable.sw_controller_interrupt = __metal_driver_cpu_sw_controller_interrupt,
+ .cpu_vtable.get_sw_interrupt_id = __metal_driver_cpu_get_sw_interrupt_id,
+ .cpu_vtable.set_sw_ipi = __metal_driver_cpu_set_sw_ipi,
+ .cpu_vtable.clear_sw_ipi = __metal_driver_cpu_clear_sw_ipi,
+ .cpu_vtable.get_msip = __metal_driver_cpu_get_msip,
+ .cpu_vtable.controller_interrupt = __metal_driver_cpu_controller_interrupt,
+ .cpu_vtable.exception_register = __metal_driver_cpu_exception_register,
+ .cpu_vtable.get_ilen = __metal_driver_cpu_get_instruction_length,
+ .cpu_vtable.get_epc = __metal_driver_cpu_get_exception_pc,
+ .cpu_vtable.set_epc = __metal_driver_cpu_set_exception_pc,
+};
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_RISCV_PLIC0
+
+#include <metal/io.h>
+#include <metal/shutdown.h>
+#include <metal/drivers/riscv_plic0.h>
+#include <metal/machine.h>
+
+unsigned int __metal_plic0_claim_interrupt (struct __metal_driver_riscv_plic0 *plic)
+{
+ unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
+ return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ METAL_RISCV_PLIC0_CLAIM));
+}
+
+void __metal_plic0_complete_interrupt(struct __metal_driver_riscv_plic0 *plic,
+ unsigned int id)
+{
+ unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ METAL_RISCV_PLIC0_CLAIM)) = id;
+}
+
+int __metal_plic0_set_threshold(struct metal_interrupt *controller, unsigned int threshold)
+{
+ unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller);
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ METAL_RISCV_PLIC0_THRESHOLD)) = threshold;
+ return 0;
+}
+
+unsigned int __metal_plic0_get_threshold(struct metal_interrupt *controller)
+{
+ unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller);
+
+ return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ METAL_RISCV_PLIC0_THRESHOLD));
+}
+
+int __metal_plic0_set_priority(struct metal_interrupt *controller, int id, unsigned int priority)
+{
+ unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)controller);
+ unsigned int max_priority = __metal_driver_sifive_plic0_max_priority((struct metal_interrupt *)controller);
+ if ( (max_priority) && (priority < max_priority) ) {
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ METAL_RISCV_PLIC0_PRIORITY_BASE +
+ (id << METAL_PLIC_SOURCE_PRIORITY_SHIFT))) = priority;
+ return 0;
+ }
+ return -1;
+}
+
+unsigned int __metal_plic0_get_priority(struct metal_interrupt *controller, int id)
+{
+ unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller);
+
+ return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ METAL_RISCV_PLIC0_PRIORITY_BASE +
+ (id << METAL_PLIC_SOURCE_PRIORITY_SHIFT)));
+}
+
+void __metal_plic0_enable(struct __metal_driver_riscv_plic0 *plic, int id, int enable)
+{
+ unsigned int current;
+ unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
+
+ current = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ METAL_RISCV_PLIC0_ENABLE_BASE +
+ (id >> METAL_PLIC_SOURCE_SHIFT) * 4));
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ METAL_RISCV_PLIC0_ENABLE_BASE +
+ ((id >> METAL_PLIC_SOURCE_SHIFT) * 4))) =
+ enable ? (current | (1 << (id & METAL_PLIC_SOURCE_MASK)))
+ : (current & ~(1 << (id & METAL_PLIC_SOURCE_MASK)));
+}
+
+void __metal_plic0_default_handler (int id, void *priv) {
+ metal_shutdown(300);
+}
+
+void __metal_plic0_handler (int id, void *priv)
+{
+ struct __metal_driver_riscv_plic0 *plic = priv;
+ unsigned int idx = __metal_plic0_claim_interrupt(plic);
+ unsigned int num_interrupts = __metal_driver_sifive_plic0_num_interrupts((struct metal_interrupt *)plic);
+
+ if ( (idx < num_interrupts) && (plic->metal_exint_table[idx]) ) {
+ plic->metal_exint_table[idx](idx,
+ plic->metal_exdata_table[idx].exint_data);
+ }
+
+ __metal_plic0_complete_interrupt(plic, idx);
+}
+
+void __metal_driver_riscv_plic0_init (struct metal_interrupt *controller)
+{
+ struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
+
+ if ( !plic->init_done ) {
+ int num_interrupts, line;
+ struct metal_interrupt *intc;
+
+ for(int parent = 0; parent < __METAL_PLIC_NUM_PARENTS; parent++) {
+ num_interrupts = __metal_driver_sifive_plic0_num_interrupts(controller);
+ intc = __metal_driver_sifive_plic0_interrupt_parents(controller, parent);
+ line = __metal_driver_sifive_plic0_interrupt_lines(controller, parent);
+
+ /* Initialize ist parent controller, aka cpu_intc. */
+ intc->vtable->interrupt_init(intc);
+
+ for (int i = 0; i < num_interrupts; i++) {
+ __metal_plic0_enable(plic, i, METAL_DISABLE);
+ __metal_plic0_set_priority(controller, i, 0);
+ plic->metal_exint_table[i] = NULL;
+ plic->metal_exdata_table[i].sub_int = NULL;
+ plic->metal_exdata_table[i].exint_data = NULL;
+ }
+
+ __metal_plic0_set_threshold(controller, 0);
+
+ /* Register plic (ext) interrupt with with parent controller */
+ intc->vtable->interrupt_register(intc, line, NULL, plic);
+ /* Register plic handler for dispatching its device interrupts */
+ intc->vtable->interrupt_register(intc, line, __metal_plic0_handler, plic);
+ /* Enable plic (ext) interrupt with with parent controller */
+ intc->vtable->interrupt_enable(intc, line);
+ }
+ plic->init_done = 1;
+ }
+}
+
+int __metal_driver_riscv_plic0_register (struct metal_interrupt *controller,
+ int id, metal_interrupt_handler_t isr,
+ void *priv)
+{
+ struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
+
+ if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
+ return -1;
+ }
+
+ if (isr) {
+ __metal_plic0_set_priority(controller, id, 2);
+ plic->metal_exint_table[id] = isr;
+ plic->metal_exdata_table[id].exint_data = priv;
+ } else {
+ __metal_plic0_set_priority(controller, id, 1);
+ plic->metal_exint_table[id] = __metal_plic0_default_handler;
+ plic->metal_exdata_table[id].sub_int = priv;
+ }
+
+ return 0;
+}
+
+int __metal_driver_riscv_plic0_enable (struct metal_interrupt *controller, int id)
+{
+ struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
+
+ if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
+ return -1;
+ }
+
+ __metal_plic0_enable(plic, id, METAL_ENABLE);
+ return 0;
+}
+
+int __metal_driver_riscv_plic0_disable (struct metal_interrupt *controller, int id)
+{
+ struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
+
+ if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
+ return -1;
+ }
+ __metal_plic0_enable(plic, id, METAL_DISABLE);
+ return 0;
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_plic0) = {
+ .plic_vtable.interrupt_init = __metal_driver_riscv_plic0_init,
+ .plic_vtable.interrupt_register = __metal_driver_riscv_plic0_register,
+ .plic_vtable.interrupt_enable = __metal_driver_riscv_plic0_enable,
+ .plic_vtable.interrupt_disable = __metal_driver_riscv_plic0_disable,
+ .plic_vtable.interrupt_get_threshold = __metal_plic0_get_threshold,
+ .plic_vtable.interrupt_set_threshold = __metal_plic0_set_threshold,
+ .plic_vtable.interrupt_get_priority = __metal_plic0_get_priority,
+ .plic_vtable.interrupt_set_priority = __metal_plic0_set_priority,
+};
+
+#endif /* METAL_RISCV_PLIC0 */
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_CCACHE0
+
+#include <stdint.h>
+#include <metal/io.h>
+#include <metal/drivers/sifive_ccache0.h>
+#include <metal/machine.h>
+
+#define L2_CONFIG_WAYS_SHIFT 8
+#define L2_CONFIG_WAYS_MASK (0xFF << L2_CONFIG_WAYS_SHIFT)
+
+void __metal_driver_sifive_ccache0_init(struct metal_cache *l2, int ways);
+
+static void metal_driver_sifive_ccache0_init(void) __attribute__((constructor));
+static void metal_driver_sifive_ccache0_init(void)
+{
+#ifdef __METAL_DT_SIFIVE_CCACHE0_HANDLE
+ /* Get the handle for the L2 cache controller */
+ struct metal_cache *l2 = __METAL_DT_SIFIVE_CCACHE0_HANDLE;
+ if(!l2) {
+ return;
+ }
+
+ /* Get the number of available ways per bank */
+ unsigned long control_base = __metal_driver_sifive_ccache0_control_base(l2);
+ uint32_t ways = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_CONFIG));
+ ways = ((ways & L2_CONFIG_WAYS_MASK) >> L2_CONFIG_WAYS_SHIFT);
+
+ /* Enable all the ways */
+ __metal_driver_sifive_ccache0_init(l2, ways);
+#endif
+}
+
+void __metal_driver_sifive_ccache0_init(struct metal_cache *l2, int ways)
+{
+ metal_cache_set_enabled_ways(l2, ways);
+}
+
+int __metal_driver_sifive_ccache0_get_enabled_ways(struct metal_cache *cache)
+{
+ unsigned long control_base = __metal_driver_sifive_ccache0_control_base(cache);
+
+ uint32_t way_enable = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_WAYENABLE));
+
+ /* The stored number is the index, so add one */
+ return (0xFF & way_enable) + 1;
+}
+
+int __metal_driver_sifive_ccache0_set_enabled_ways(struct metal_cache *cache, int ways)
+{
+ unsigned long control_base = __metal_driver_sifive_ccache0_control_base(cache);
+
+ /* We can't decrease the number of enabled ways */
+ if(metal_cache_get_enabled_ways(cache) > ways) {
+ return -2;
+ }
+
+ /* The stored value is the index, so subtract one */
+ uint32_t value = 0xFF & (ways - 1);
+
+ /* Set the number of enabled ways */
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_WAYENABLE)) = value;
+
+ /* Make sure the number of ways was set correctly */
+ if(metal_cache_get_enabled_ways(cache) != ways) {
+ return -3;
+ }
+
+ return 0;
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_ccache0) = {
+ .cache.init = __metal_driver_sifive_ccache0_init,
+ .cache.get_enabled_ways = __metal_driver_sifive_ccache0_get_enabled_ways,
+ .cache.set_enabled_ways = __metal_driver_sifive_ccache0_set_enabled_ways,
+};
+
+#endif
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_CLIC0
+
+#include <stdint.h>
+#include <metal/io.h>
+#include <metal/shutdown.h>
+#include <metal/drivers/sifive_clic0.h>
+#include <metal/machine.h>
+
+typedef enum metal_clic_vector_{
+ METAL_CLIC_NONVECTOR = 0,
+ METAL_CLIC_VECTORED = 1
+} metal_clic_vector;
+
+struct __metal_clic_cfg {
+ unsigned char : 1,
+ nmbits : 2,
+ nlbits : 4,
+ nvbit : 1;
+};
+
+const struct __metal_clic_cfg __metal_clic_defaultcfg = {
+ .nmbits = METAL_INTR_PRIV_M_MODE,
+ .nlbits = 0,
+ .nvbit = METAL_CLIC_NONVECTOR
+ };
+
+void __metal_clic0_handler(int id, void *priv) __attribute__((aligned(64)));
+
+void __metal_clic0_default_vector_handler (void) __attribute__((interrupt, aligned(64)));
+
+struct __metal_clic_cfg __metal_clic0_configuration (struct __metal_driver_sifive_clic0 *clic,
+ struct __metal_clic_cfg *cfg)
+{
+ volatile unsigned char val;
+ struct __metal_clic_cfg cliccfg;
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+
+ if ( cfg ) {
+ val = cfg->nmbits << 5 | cfg->nlbits << 1 | cfg->nvbit;
+ __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICCFG)) = val;
+ }
+ val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICCFG));
+ cliccfg.nmbits = (val & METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MASK) >> 5;
+ cliccfg.nlbits = (val & METAL_SIFIVE_CLIC0_CLICCFG_NLBITS_MASK) >> 1;
+ cliccfg.nvbit = val & METAL_SIFIVE_CLIC0_CLICCFG_NVBIT_MASK;
+ return cliccfg;
+}
+
+int __metal_clic0_interrupt_set_mode (struct __metal_driver_sifive_clic0 *clic, int id, int mode)
+{
+ uint8_t mask, val;
+ struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+
+ if (mode >= (cfg.nmbits << 1)) {
+ /* Do nothing, mode request same or exceed what configured in CLIC */
+ return 0;
+ }
+
+ /* Mask out nmbits and retain other values */
+ mask = ((uint8_t)(-1)) >> cfg.nmbits;
+ val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) & mask;
+ __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = val | (mode << (8 - cfg.nmbits));
+ return 0;
+}
+
+int __metal_clic0_interrupt_set_level (struct __metal_driver_sifive_clic0 *clic, int id, unsigned int level)
+{
+ uint8_t mask, nmmask, nlmask, val;
+ struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+
+ /* Drop the LSBs that don't fit in nlbits */
+ level = level >> (METAL_CLIC_MAX_NLBITS - cfg.nlbits);
+
+ nmmask = ~( ((uint8_t)(-1)) >> (cfg.nmbits) );
+ nlmask = ((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits);
+ mask = ~(nlmask | nmmask);
+
+ val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
+ __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, level);
+ return 0;
+}
+
+unsigned int __metal_clic0_interrupt_get_level (struct __metal_driver_sifive_clic0 *clic, int id)
+{
+ int level;
+ uint8_t mask, val, freebits, nlbits;
+ struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+ int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
+
+ if ((cfg.nmbits + cfg.nlbits) >= num_intbits) {
+ nlbits = num_intbits - cfg.nmbits;
+ } else {
+ nlbits = cfg.nlbits;
+ }
+
+ mask = ((1 << nlbits) - 1) << (8 - (cfg.nmbits + nlbits));
+ freebits = ((1 << METAL_CLIC_MAX_NLBITS) - 1) >> nlbits;
+
+ if (mask == 0) {
+ level = (1 << METAL_CLIC_MAX_NLBITS) - 1;
+ } else {
+ val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
+ val = __METAL_GET_FIELD(val, mask);
+ level = (val << (METAL_CLIC_MAX_NLBITS - nlbits)) | freebits;
+ }
+
+ return level;
+}
+
+int __metal_clic0_interrupt_set_priority (struct __metal_driver_sifive_clic0 *clic, int id, int priority)
+{
+ uint8_t mask, npmask, val, npbits;
+ struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+ int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
+
+ if ((cfg.nmbits + cfg.nlbits) < num_intbits) {
+ npbits = num_intbits - (cfg.nmbits + cfg.nlbits);
+ priority = priority >> (8 - npbits);
+
+ mask = ((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits + npbits);
+ npmask = ~(((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits));
+ mask = ~(mask | npmask);
+
+ val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
+ __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, priority);
+ }
+ return 0;
+}
+
+int __metal_clic0_interrupt_get_priority (struct __metal_driver_sifive_clic0 *clic, int id)
+{
+ int priority;
+ uint8_t mask, val, freebits, nlbits;
+ struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+ int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
+
+ if ((cfg.nmbits + cfg.nlbits) >= num_intbits) {
+ nlbits = num_intbits - cfg.nmbits;
+ } else {
+ nlbits = cfg.nlbits;
+ }
+
+ mask = ((1 << nlbits) - 1) << (8 - (cfg.nmbits + nlbits));
+ freebits = ((1 << METAL_CLIC_MAX_NLBITS) - 1) >> nlbits;
+
+ if (mask == 0) {
+ priority = (1 << METAL_CLIC_MAX_NLBITS) - 1;
+ } else {
+ val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
+ priority = __METAL_GET_FIELD(val, freebits);
+ }
+ return priority;
+}
+
+int __metal_clic0_interrupt_set_vector_mode (struct __metal_driver_sifive_clic0 *clic, int id, int enable)
+{
+ uint8_t mask, val;
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+ int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
+
+ mask = 1 << (8 - num_intbits);
+ val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
+ /* Ensure its value is 1 bit wide */
+ enable &= 0x1;
+ __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, enable);
+ return 0;
+}
+
+int __metal_clic0_interrupt_is_vectored (struct __metal_driver_sifive_clic0 *clic, int id)
+{
+ uint8_t mask, val;
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+ int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
+
+ mask = 1 << (8 - num_intbits);
+ val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
+ return __METAL_GET_FIELD(val, mask);
+}
+
+int __metal_clic0_interrupt_enable (struct __metal_driver_sifive_clic0 *clic, int id)
+{
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+ int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
+
+ if (id >= num_subinterrupts) {
+ return -1;
+ }
+ __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id)) = METAL_ENABLE;
+ return 0;
+}
+
+int __metal_clic0_interrupt_disable (struct __metal_driver_sifive_clic0 *clic, int id)
+{
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+ int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
+
+ if (id >= num_subinterrupts) {
+ return -1;
+ }
+ __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id)) = METAL_DISABLE;
+ return 0;
+}
+
+int __metal_clic0_interrupt_is_enabled (struct __metal_driver_sifive_clic0 *clic, int id)
+{
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+ int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
+
+ if (id >= num_subinterrupts) {
+ return 0;
+ }
+ return __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id));
+}
+
+int __metal_clic0_interrupt_is_pending (struct __metal_driver_sifive_clic0 *clic, int id)
+{
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+ int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
+
+ if (id >= num_subinterrupts) {
+ return 0;
+ }
+ return __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id));
+}
+
+int __metal_clic0_interrupt_set (struct __metal_driver_sifive_clic0 *clic, int id)
+{
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+ int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
+
+ if (id < num_subinterrupts) {
+ __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id)) = METAL_ENABLE;
+ return 0;
+ }
+ return -1;
+}
+
+int __metal_clic0_interrupt_clear (struct __metal_driver_sifive_clic0 *clic, int id)
+{
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+ int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
+
+ if (id < num_subinterrupts) {
+ __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id)) = METAL_DISABLE;
+ return 0;
+ }
+ return -1;
+}
+
+int __metal_clic0_configure_set_vector_mode (struct __metal_driver_sifive_clic0 *clic, metal_vector_mode mode)
+{
+ struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
+
+ switch (mode) {
+ case METAL_SELECTIVE_NONVECTOR_MODE:
+ cfg.nvbit = METAL_CLIC_NONVECTOR;
+ __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
+ break;
+ case METAL_SELECTIVE_VECTOR_MODE:
+ cfg.nvbit = METAL_CLIC_VECTORED;
+ __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
+ break;
+ case METAL_HARDWARE_VECTOR_MODE:
+ cfg.nvbit = METAL_CLIC_VECTORED;
+ __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
+ break;
+ default:
+ return -1;
+ }
+ __metal_clic0_configuration(clic, &cfg);
+ return 0;
+}
+
+metal_vector_mode __metal_clic0_configure_get_vector_mode (struct __metal_driver_sifive_clic0 *clic)
+{
+ struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
+ metal_vector_mode mode = __metal_controller_interrupt_vector_mode();
+
+ if (mode == METAL_SELECTIVE_VECTOR_MODE) {
+ if (cfg.nvbit) {
+ return METAL_SELECTIVE_VECTOR_MODE;
+ } else {
+ return METAL_SELECTIVE_NONVECTOR_MODE;
+ }
+ } else {
+ return mode;
+ }
+}
+
+int __metal_clic0_configure_set_privilege (struct __metal_driver_sifive_clic0 *clic, metal_intr_priv_mode priv)
+{
+ struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
+
+ cfg.nmbits = priv;
+ __metal_clic0_configuration(clic, &cfg);
+ return 0;
+}
+
+metal_intr_priv_mode __metal_clic0_configure_get_privilege (struct __metal_driver_sifive_clic0 *clic)
+{
+ struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
+
+ return cfg.nmbits;
+}
+
+int __metal_clic0_configure_set_level (struct __metal_driver_sifive_clic0 *clic, int level)
+{
+ struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
+
+ cfg.nlbits = level & 0xF;
+ __metal_clic0_configuration(clic, &cfg);
+ return 0;
+}
+
+int __metal_clic0_configure_get_level (struct __metal_driver_sifive_clic0 *clic)
+{
+ struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
+
+ return cfg.nlbits;
+}
+
+unsigned long long __metal_clic0_mtime_get (struct __metal_driver_sifive_clic0 *clic)
+{
+ __metal_io_u32 lo, hi;
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+
+ /* Guard against rollover when reading */
+ do {
+ hi = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME + 4));
+ lo = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME));
+ } while (__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME + 4)) != hi);
+
+ return (((unsigned long long)hi) << 32) | lo;
+}
+
+int __metal_driver_sifive_clic0_mtimecmp_set(struct metal_interrupt *controller,
+ int hartid,
+ unsigned long long time)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
+ /* Per spec, the RISC-V MTIME/MTIMECMP registers are 64 bit,
+ * and are NOT internally latched for multiword transfers.
+ * Need to be careful about sequencing to avoid triggering
+ * spurious interrupts: For that set the high word to a max
+ * value first.
+ */
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE + 4)) = 0xFFFFFFFF;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE)) = (__metal_io_u32)time;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE + 4)) = (__metal_io_u32)(time >> 32);
+ return 0;
+}
+
+void __metal_clic0_handler (int id, void *priv)
+{
+ struct __metal_driver_sifive_clic0 *clic = priv;
+ int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
+
+ if ( (id < num_subinterrupts) && (clic->metal_exint_table[id].handler) ) {
+ clic->metal_exint_table[id].handler(id, clic->metal_exint_table[id].exint_data);
+ }
+}
+
+void __metal_clic0_default_handler (int id, void *priv) {
+ metal_shutdown(300);
+}
+
+void __metal_clic0_default_vector_handler (void) {
+ metal_shutdown(400);
+}
+
+void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+
+ if ( !clic->init_done ) {
+ int level, max_levels, line, num_interrupts, num_subinterrupts;
+ struct __metal_clic_cfg cfg = __metal_clic_defaultcfg;
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_clic0_interrupt_parent(controller);
+
+ /* Initialize ist parent controller, aka cpu_intc. */
+ intc->vtable->interrupt_init(intc);
+ __metal_controller_interrupt_vector(METAL_SELECTIVE_NONVECTOR_MODE,
+ &clic->metal_mtvt_table);
+
+ /*
+ * Register its interrupts with with parent controller,
+ * aka sw, timer and ext to its default isr
+ */
+ num_interrupts = __metal_driver_sifive_clic0_num_interrupts(controller);
+ for (int i = 0; i < num_interrupts; i++) {
+ line = __metal_driver_sifive_clic0_interrupt_lines(controller, i);
+ intc->vtable->interrupt_register(intc, line, NULL, clic);
+ }
+
+ /* Default CLIC mode to per dts */
+ max_levels = __metal_driver_sifive_clic0_max_levels(controller);
+ cfg.nlbits = (max_levels > METAL_CLIC_MAX_NLBITS) ?
+ METAL_CLIC_MAX_NLBITS : max_levels;
+ __metal_clic0_configuration(clic, &cfg);
+
+ level = (1 << cfg.nlbits) - 1;
+ num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
+ clic->metal_mtvt_table[0] = &__metal_clic0_handler;
+ for (int i = 1; i < num_subinterrupts; i++) {
+ clic->metal_mtvt_table[i] = NULL;
+ clic->metal_exint_table[i].handler = NULL;
+ clic->metal_exint_table[i].sub_int = NULL;
+ clic->metal_exint_table[i].exint_data = NULL;
+ __metal_clic0_interrupt_disable(clic, i);
+ __metal_clic0_interrupt_set_level(clic, i, level);
+ }
+ clic->init_done = 1;
+ }
+}
+
+int __metal_driver_sifive_clic0_register (struct metal_interrupt *controller,
+ int id, metal_interrupt_handler_t isr,
+ void *priv)
+{
+ int rc = -1;
+ int num_subinterrupts;
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_clic0_interrupt_parent(controller);
+ metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic);
+
+ if ( ( (mode == METAL_SELECTIVE_VECTOR_MODE) &&
+ (__metal_clic0_interrupt_is_vectored(clic, id)) ) ||
+ (mode == METAL_HARDWARE_VECTOR_MODE) ||
+ (mode == METAL_VECTOR_MODE) ||
+ (mode == METAL_DIRECT_MODE) ) {
+ return rc;
+ }
+
+ /* Register its interrupts with parent controller */
+ if (id < METAL_INTERRUPT_ID_CSW) {
+ return intc->vtable->interrupt_register(intc, id, isr, priv);
+ }
+
+ /*
+ * CLIC (sub-interrupts) devices interrupts start at 16 but offset from 0
+ * Reset the IDs to reflects this.
+ */
+ num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
+ if (id < num_subinterrupts) {
+ if ( isr) {
+ clic->metal_exint_table[id].handler = isr;
+ clic->metal_exint_table[id].exint_data = priv;
+ } else {
+ clic->metal_exint_table[id].handler = __metal_clic0_default_handler;
+ clic->metal_exint_table[id].sub_int = priv;
+ }
+ rc = 0;
+ }
+ return rc;
+}
+
+int __metal_driver_sifive_clic0_vector_register (struct metal_interrupt *controller,
+ int id, metal_interrupt_vector_handler_t isr,
+ void *priv)
+{
+ int rc = -1;
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_clic0_interrupt_parent(controller);
+ int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
+ metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic);
+
+ if ((mode != METAL_SELECTIVE_VECTOR_MODE) && (mode != METAL_HARDWARE_VECTOR_MODE)) {
+ return rc;
+ }
+ if ((mode == METAL_SELECTIVE_VECTOR_MODE) &&
+ (__metal_clic0_interrupt_is_vectored(clic, id) == 0) ) {
+ return rc;
+ }
+ if (id < num_subinterrupts) {
+ if ( isr) {
+ clic->metal_mtvt_table[id] = isr;
+ clic->metal_exint_table[id].exint_data = priv;
+ } else {
+ clic->metal_mtvt_table[id] = __metal_clic0_default_vector_handler;
+ clic->metal_exint_table[id].sub_int = priv;
+ }
+ rc = 0;
+ }
+ return rc;
+}
+
+int __metal_driver_sifive_clic0_enable (struct metal_interrupt *controller, int id)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ return __metal_clic0_interrupt_enable(clic, id);
+}
+
+int __metal_driver_sifive_clic0_disable (struct metal_interrupt *controller, int id)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ return __metal_clic0_interrupt_disable(clic, id);
+}
+
+int __metal_driver_sifive_clic0_enable_interrupt_vector(struct metal_interrupt *controller, int id)
+{
+ int rc = -1;
+ int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic);
+
+ if ((mode != METAL_SELECTIVE_VECTOR_MODE) && (mode != METAL_HARDWARE_VECTOR_MODE)) {
+ return rc;
+ }
+ if (id < num_subinterrupts) {
+ __metal_clic0_interrupt_set_vector_mode(clic, id, METAL_ENABLE);
+ return 0;
+ }
+ return -1;
+}
+
+int __metal_driver_sifive_clic0_disable_interrupt_vector(struct metal_interrupt *controller, int id)
+{
+ int num_subinterrupts;
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+
+ num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
+ if (id < num_subinterrupts) {
+ __metal_clic0_interrupt_set_vector_mode(clic, id, METAL_DISABLE);
+ return 0;
+ }
+ return -1;
+}
+
+metal_vector_mode __metal_driver_sifive_clic0_get_vector_mode (struct metal_interrupt *controller)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ return __metal_clic0_configure_get_vector_mode(clic);
+}
+
+int __metal_driver_sifive_clic0_set_vector_mode (struct metal_interrupt *controller, metal_vector_mode mode)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ return __metal_clic0_configure_set_vector_mode(clic, mode);
+}
+
+metal_intr_priv_mode __metal_driver_sifive_clic0_get_privilege (struct metal_interrupt *controller)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ return __metal_clic0_configure_get_privilege(clic);
+}
+
+int __metal_driver_sifive_clic0_set_privilege (struct metal_interrupt *controller, metal_intr_priv_mode priv)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ return __metal_clic0_configure_set_privilege(clic, priv);
+}
+
+unsigned int __metal_driver_sifive_clic0_get_threshold (struct metal_interrupt *controller)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ return __metal_clic0_configure_get_level(clic);
+}
+
+int __metal_driver_sifive_clic0_set_threshold (struct metal_interrupt *controller, unsigned int level)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ return __metal_clic0_configure_set_level(clic, level);
+}
+
+unsigned int __metal_driver_sifive_clic0_get_priority (struct metal_interrupt *controller, int id)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ return __metal_clic0_interrupt_get_priority(clic, id);
+}
+
+int __metal_driver_sifive_clic0_set_priority (struct metal_interrupt *controller, int id, unsigned int priority)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ return __metal_clic0_interrupt_set_priority(clic, id, priority);
+}
+
+int __metal_driver_sifive_clic0_clear_interrupt (struct metal_interrupt *controller, int id)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ return __metal_clic0_interrupt_clear(clic, id);
+}
+
+int __metal_driver_sifive_clic0_set_interrupt (struct metal_interrupt *controller, int id)
+{
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ return __metal_clic0_interrupt_set(clic, id);
+}
+
+int __metal_driver_sifive_clic0_command_request (struct metal_interrupt *controller,
+ int command, void *data)
+{
+ int hartid;
+ int rc = -1;
+ struct __metal_driver_sifive_clic0 *clic =
+ (struct __metal_driver_sifive_clic0 *)(controller);
+ unsigned long control_base = __metal_driver_sifive_clic0_control_base(controller);
+
+ switch (command) {
+ case METAL_TIMER_MTIME_GET:
+ if (data) {
+ *(unsigned long long *)data = __metal_clic0_mtime_get(clic);
+ rc = 0;
+ }
+ break;
+ case METAL_SOFTWARE_IPI_CLEAR:
+ if (data) {
+ hartid = *(int *)data;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ (hartid * 4))) = METAL_DISABLE;
+ __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTIP_BASE)) = METAL_DISABLE;
+ rc = 0;
+ }
+ break;
+ case METAL_SOFTWARE_IPI_SET:
+ if (data) {
+ hartid = *(int *)data;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ (hartid * 4))) = METAL_ENABLE;
+ __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
+ METAL_SIFIVE_CLIC0_MMODE_APERTURE +
+ METAL_SIFIVE_CLIC0_CLICINTIP_BASE)) = METAL_ENABLE;
+ rc = 0;
+ }
+ break;
+ case METAL_SOFTWARE_MSIP_GET:
+ rc = 0;
+ if (data) {
+ hartid = *(int *)data;
+ rc = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
+ (hartid * 4)));
+ }
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_clic0) = {
+ .clic_vtable.interrupt_init = __metal_driver_sifive_clic0_init,
+ .clic_vtable.interrupt_register = __metal_driver_sifive_clic0_register,
+ .clic_vtable.interrupt_vector_register = __metal_driver_sifive_clic0_vector_register,
+ .clic_vtable.interrupt_enable = __metal_driver_sifive_clic0_enable,
+ .clic_vtable.interrupt_disable = __metal_driver_sifive_clic0_disable,
+ .clic_vtable.interrupt_vector_enable = __metal_driver_sifive_clic0_enable_interrupt_vector,
+ .clic_vtable.interrupt_vector_disable = __metal_driver_sifive_clic0_disable_interrupt_vector,
+ .clic_vtable.interrupt_get_vector_mode = __metal_driver_sifive_clic0_get_vector_mode,
+ .clic_vtable.interrupt_set_vector_mode = __metal_driver_sifive_clic0_set_vector_mode,
+ .clic_vtable.interrupt_get_privilege = __metal_driver_sifive_clic0_get_privilege,
+ .clic_vtable.interrupt_set_privilege = __metal_driver_sifive_clic0_set_privilege,
+ .clic_vtable.interrupt_get_threshold = __metal_driver_sifive_clic0_get_threshold,
+ .clic_vtable.interrupt_set_threshold = __metal_driver_sifive_clic0_set_threshold,
+ .clic_vtable.interrupt_get_priority = __metal_driver_sifive_clic0_get_priority,
+ .clic_vtable.interrupt_set_priority = __metal_driver_sifive_clic0_set_priority,
+ .clic_vtable.interrupt_clear = __metal_driver_sifive_clic0_clear_interrupt,
+ .clic_vtable.interrupt_set = __metal_driver_sifive_clic0_set_interrupt,
+ .clic_vtable.command_request = __metal_driver_sifive_clic0_command_request,
+ .clic_vtable.mtimecmp_set = __metal_driver_sifive_clic0_mtimecmp_set,
+};
+
+#endif /* METAL_SIFIVE_CLIC0 */
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_FE310_G000_HFROSC
+
+#include <metal/drivers/sifive_fe310-g000_hfrosc.h>
+#include <metal/machine.h>
+
+#define CONFIG_DIVIDER 0x0000003FUL
+#define CONFIG_TRIM 0x001F0000UL
+#define CONFIG_ENABLE 0x40000000UL
+#define CONFIG_READY 0x80000000UL
+
+long __metal_driver_sifive_fe310_g000_hfrosc_get_rate_hz(const struct metal_clock *clock)
+{
+ struct metal_clock *ref = __metal_driver_sifive_fe310_g000_hfrosc_ref(clock);
+ long config_offset = __metal_driver_sifive_fe310_g000_hfrosc_config_offset(clock);
+ struct __metal_driver_sifive_fe310_g000_prci *config_base =
+ __metal_driver_sifive_fe310_g000_hfrosc_config_base(clock);
+ const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable =
+ __metal_driver_sifive_fe310_g000_prci_vtable();
+ long cfg = vtable->get_reg(config_base, config_offset);
+
+ if ((cfg & CONFIG_ENABLE) == 0)
+ return -1;
+ if ((cfg & CONFIG_READY) == 0)
+ return -1;
+ return metal_clock_get_rate_hz(ref) / ((cfg & CONFIG_DIVIDER) + 1);
+}
+
+long __metal_driver_sifive_fe310_g000_hfrosc_set_rate_hz(struct metal_clock *clock, long rate)
+{
+ return __metal_driver_sifive_fe310_g000_hfrosc_get_rate_hz(clock);
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfrosc) = {
+ .clock.get_rate_hz = &__metal_driver_sifive_fe310_g000_hfrosc_get_rate_hz,
+ .clock.set_rate_hz = &__metal_driver_sifive_fe310_g000_hfrosc_set_rate_hz,
+};
+#endif /* METAL_SIFIVE_FE310_G000_HFROSC */
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_FE310_G000_HFXOSC
+
+#include <metal/drivers/sifive_fe310-g000_hfxosc.h>
+#include <metal/machine.h>
+
+#define CONFIG_ENABLE 0x40000000UL
+#define CONFIG_READY 0x80000000UL
+
+long __metal_driver_sifive_fe310_g000_hfxosc_get_rate_hz(const struct metal_clock *clock)
+{
+ struct metal_clock *ref = __metal_driver_sifive_fe310_g000_hfxosc_ref(clock);
+ long config_offset = __metal_driver_sifive_fe310_g000_hfxosc_config_offset(clock);
+ struct __metal_driver_sifive_fe310_g000_prci *config_base =
+ __metal_driver_sifive_fe310_g000_hfxosc_config_base(clock);
+ const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable =
+ __metal_driver_sifive_fe310_g000_prci_vtable();
+ long cfg = vtable->get_reg(config_base, config_offset);
+
+ if ((cfg & CONFIG_ENABLE) == 0)
+ return -1;
+ if ((cfg & CONFIG_READY) == 0)
+ return -1;
+ return metal_clock_get_rate_hz(ref);
+}
+
+long __metal_driver_sifive_fe310_g000_hfxosc_set_rate_hz(struct metal_clock *clock, long rate)
+{
+ return __metal_driver_sifive_fe310_g000_hfxosc_get_rate_hz(clock);
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfxosc) = {
+ .clock.get_rate_hz = __metal_driver_sifive_fe310_g000_hfxosc_get_rate_hz,
+ .clock.set_rate_hz = __metal_driver_sifive_fe310_g000_hfxosc_set_rate_hz,
+};
+
+#endif /* METAL_SIFIVE_FE310_G000_HFXOSC */
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_FE310_G000_LFROSC
+
+#include <metal/drivers/sifive_fe310-g000_lfrosc.h>
+#include <metal/machine.h>
+
+/* LFROSCCFG */
+#define METAL_LFROSCCFG_DIV_MASK 0x3F
+#define METAL_LFROSCCFG_TRIM_SHIFT 16
+#define METAL_LFROSCCFG_TRIM_MASK (0x1F << METAL_LFROSCCFG_TRIM_SHIFT)
+#define METAL_LFROSCCFG_EN (1 << 30)
+#define METAL_LFROSCCFG_RDY (1 << 31)
+
+/* LFCLKMUX */
+#define METAL_LFCLKMUX_SEL 1
+#define METAL_LFCLKMUX_EXT_MUX_STATUS (1 << 31)
+
+#define LFROSC_REGW(addr) (__METAL_ACCESS_ONCE((__metal_io_u32 *)addr))
+
+long __metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz(const struct metal_clock *clock)
+{
+ struct metal_clock *internal_ref = __metal_driver_sifive_fe310_g000_lfrosc_lfrosc(clock);
+ struct metal_clock *external_ref = __metal_driver_sifive_fe310_g000_lfrosc_psdlfaltclk(clock);
+
+ unsigned long int cfg_reg = __metal_driver_sifive_fe310_g000_lfrosc_config_reg(clock);
+ unsigned long int mux_reg = __metal_driver_sifive_fe310_g000_lfrosc_mux_reg(clock);
+
+ if(LFROSC_REGW(mux_reg) & METAL_LFCLKMUX_EXT_MUX_STATUS) {
+ return metal_clock_get_rate_hz(external_ref);
+ }
+
+ const unsigned long int div = (LFROSC_REGW(cfg_reg) & METAL_LFROSCCFG_DIV_MASK) + 1;
+
+ return metal_clock_get_rate_hz(internal_ref) / div;
+}
+
+long __metal_driver_sifive_fe310_g000_lfrosc_set_rate_hz(struct metal_clock *clock, long rate)
+{
+ return __metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz(clock);
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_lfrosc) = {
+ .clock.get_rate_hz = &__metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz,
+ .clock.set_rate_hz = &__metal_driver_sifive_fe310_g000_lfrosc_set_rate_hz,
+};
+#endif /* METAL_SIFIVE_FE310_G000_LFROSC */
+
+typedef int no_empty_translation_units;
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_FE310_G000_PLL
+
+#include <stdio.h>
+#include <limits.h>
+
+#include <metal/machine.h>
+#include <metal/drivers/sifive_fe310-g000_pll.h>
+#include <stdlib.h>
+
+#define PLL_R 0x00000007UL
+#define PLL_F 0x000003F0UL
+#define PLL_Q 0x00000C00UL
+#define PLL_SEL 0x00010000UL
+#define PLL_REFSEL 0x00020000UL
+#define PLL_BYPASS 0x00040000UL
+#define PLL_LOCK 0x80000000UL
+
+#define DIV_DIV 0x0000003FUL
+#define DIV_1 0x00000100UL
+
+#define PLL_R_SHIFT(r) ((r << 0) & PLL_R)
+#define PLL_F_SHIFT(f) ((f << 4) & PLL_F)
+#define PLL_Q_SHIFT(q) ((q << 10) & PLL_Q)
+#define PLL_DIV_SHIFT(d) ((d << 0) & DIV_DIV)
+
+struct pll_config_t {
+ unsigned long multiplier;
+ unsigned long divisor;
+ unsigned long min_input_rate;
+ unsigned long max_input_rate;
+ unsigned long r;
+ unsigned long f;
+ unsigned long q;
+ long d; /* < 0 if disabled */
+};
+
+static const struct pll_config_t pll_configs[] = {
+ /*
+ * multiplier
+ * ^ divisor
+ * | ^ min_input_rate
+ * | | ^ max_input_rate
+ * | | | ^ r
+ * | | | | ^ f
+ * | | | | | ^ q
+ * | | | | | | ^ d
+ * | | | | | | | ^
+ * | | | | | | | | */
+ { 1, 32, 12000000, 24000000, 1, 31, 3, 63},
+ { 1, 32, 24000000, 48000000, 3, 31, 2, 63},
+ { 1, 16, 6000000, 12000000, 0, 31, 3, 63},
+ { 1, 16, 12000000, 24000000, 1, 31, 2, 63},
+ { 1, 16, 24000000, 48000000, 3, 31, 2, 31},
+ { 1, 8, 6000000, 12000000, 0, 31, 3, 31},
+ { 1, 8, 12000000, 24000000, 1, 31, 2, 31},
+ { 1, 8, 24000000, 48000000, 3, 31, 2, 15},
+ { 1, 4, 6000000, 12000000, 0, 31, 3, 15},
+ { 1, 4, 12000000, 24000000, 1, 31, 2, 15},
+ { 1, 4, 24000000, 48000000, 3, 31, 2, 7},
+ { 1, 2, 6000000, 12000000, 0, 31, 2, 15},
+ { 1, 2, 12000000, 24000000, 1, 31, 1, 15},
+ { 1, 2, 24000000, 48000000, 3, 31, 1, 7},
+ { 2, 1, 6000000, 12000000, 0, 31, 1, 7},
+ { 2, 1, 12000000, 24000000, 1, 31, 1, 3},
+ { 2, 1, 24000000, 48000000, 3, 31, 3, -1},
+ { 4, 1, 6000000, 12000000, 0, 31, 3, 0},
+ { 4, 1, 12000000, 24000000, 1, 31, 3, -1},
+ { 4, 1, 24000000, 48000000, 3, 31, 2, -1},
+ { 6, 1, 6000000, 10666666, 0, 35, 1, 2},
+ { 6, 1, 10666666, 12000000, 0, 23, 3, -1},
+ { 6, 1, 12000000, 16000000, 1, 47, 3, -1},
+ { 6, 1, 16000000, 18000000, 1, 23, 2, -1},
+ { 6, 1, 18000000, 21333333, 2, 35, 2, -1},
+ { 8, 1, 6000000, 12000000, 0, 31, 3, -1},
+ { 8, 1, 12000000, 24000000, 1, 31, 2, -1},
+ { 8, 1, 24000000, 48000000, 3, 31, 1, -1},
+ {10, 1, 6000000, 9600000, 0, 39, 3, -1},
+ {10, 1, 9600000, 12000000, 0, 19, 2, -1},
+ {10, 1, 12000000, 19200000, 1, 39, 2, -1},
+ {10, 1, 19200000, 24000000, 1, 19, 1, -1},
+ {10, 1, 24000000, 38400000, 3, 39, 1, -1},
+ {12, 1, 6000000, 8000000, 0, 47, 3, -1},
+ {12, 1, 8000000, 12000000, 0, 23, 2, -1},
+ {12, 1, 12000000, 16000000, 1, 47, 2, -1},
+ {12, 1, 16000000, 24000000, 1, 23, 1, -1},
+ {12, 1, 24000000, 30000000, 3, 47, 1, -1},
+ {12, 1, 30000000, 32000000, 3, 47, 1, -1},
+ {14, 1, 6000000, 6857142, 0, 55, 3, -1},
+ {14, 1, 6857143, 12000000, 0, 27, 2, -1},
+ {14, 1, 12000000, 13714285, 1, 55, 2, -1},
+ {14, 1, 13714286, 24000000, 1, 27, 1, -1},
+ {14, 1, 24000000, 27428571, 3, 55, 1, -1},
+ {16, 1, 6000000, 12000000, 0, 31, 2, -1},
+ {16, 1, 12000000, 24000000, 1, 31, 1, -1},
+ {18, 1, 6000000, 10666666, 0, 35, 2, -1},
+ {18, 1, 10666667, 12000000, 0, 17, 1, -1},
+ {18, 1, 12000000, 21333333, 1, 35, 1, -1},
+ {20, 1, 6000000, 9600000, 0, 39, 2, -1},
+ {20, 1, 9600000, 12000000, 0, 19, 1, -1},
+ {20, 1, 12000000, 19200000, 1, 39, 1, -1},
+ {22, 1, 6000000, 8727272, 0, 43, 2, -1},
+ {22, 1, 8727273, 12000000, 0, 21, 1, -1},
+ {22, 1, 12000000, 17454545, 1, 43, 1, -1},
+ {24, 1, 6000000, 8000000, 0, 47, 2, -1},
+ {24, 1, 8000000, 12000000, 0, 23, 1, -1},
+ {24, 1, 12000000, 16000000, 1, 47, 1, -1},
+ {26, 1, 6000000, 7384615, 0, 51, 2, -1},
+ {26, 1, 7384616, 12000000, 0, 25, 1, -1},
+ {26, 1, 12000000, 14768230, 1, 51, 1, -1},
+ {28, 1, 6000000, 6857142, 0, 55, 2, -1},
+ {28, 1, 6857143, 12000000, 0, 27, 1, -1},
+ {28, 1, 12000000, 13714285, 1, 55, 1, -1},
+ {30, 1, 6000000, 6400000, 0, 59, 2, -1},
+ {30, 1, 6400000, 12000000, 0, 29, 1, -1},
+ {30, 1, 12000000, 12800000, 1, 59, 1, -1},
+ {32, 1, 6000000, 12000000, 0, 31, 1, -1}
+};
+
+#define PLL_CONFIG_NOT_VALID -1
+
+void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe310_g000_pll *pll);
+
+/* Given the rate of the PLL input frequency and a PLL configuration, what
+ * will the resulting PLL output frequency be?
+ * Arguments:
+ * - pll_input_rate the PLL input frequency in hertz
+ * - config the PLL configuration
+ * Returns:
+ * - PLL_CONFIG_NOT_VALID if the configuration is not valid for the input frequency
+ * - the output frequency, in hertz */
+static long get_pll_config_freq(unsigned long pll_input_rate, const struct pll_config_t *config)
+{
+ if(pll_input_rate < config->min_input_rate || pll_input_rate > config->max_input_rate)
+ return PLL_CONFIG_NOT_VALID;
+
+ return pll_input_rate * config->multiplier / config->divisor;
+}
+
+#ifdef __METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE
+
+static void metal_sifive_fe310_g000_pll_init(void) __attribute__((constructor));
+static void metal_sifive_fe310_g000_pll_init(void) {
+ long init_rate = __metal_driver_sifive_fe310_g000_pll_init_rate();
+ /* If the PLL init_rate is zero, don't initialize the PLL */
+ if(init_rate != 0)
+ __metal_driver_sifive_fe310_g000_pll_init(__METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE);
+}
+
+#endif /* __METAL_DT_SIFIVE_FE310_G000__PLL_HANDLE */
+
+void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe310_g000_pll *pll) {
+ struct metal_clock *pllref = __metal_driver_sifive_fe310_g000_pll_pllref(&(pll->clock));
+ long init_rate = __metal_driver_sifive_fe310_g000_pll_init_rate();
+ long config_offset = __metal_driver_sifive_fe310_g000_pll_config_offset();
+ long base = __metal_driver_sifive_fe310_g000_prci_base();
+
+ __metal_io_u32 *pllcfg = (__metal_io_u32 *) (base + config_offset);
+
+ /* If the PLL clock has had a _pre_rate_change_callback configured, call it */
+ _metal_clock_call_all_callbacks(pll->clock._pre_rate_change_callback);
+
+ /* If we're running off of the PLL, switch off before we start configuring it*/
+ if((__METAL_ACCESS_ONCE(pllcfg) & PLL_SEL) == 0)
+ __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_SEL);
+
+ /* Make sure we're running off of the external oscillator for stability */
+ if(pllref != NULL)
+ __METAL_ACCESS_ONCE(pllcfg) |= PLL_REFSEL;
+
+ /* Configure the PLL to run at the requested init frequency.
+ * Using the vtable instead of the user API because we want to control
+ * when the callbacks occur. */
+ pll->clock.vtable->set_rate_hz(&(pll->clock), init_rate);
+
+ /* If the PLL clock has had a rate_change_callback configured, call it */
+ _metal_clock_call_all_callbacks(pll->clock._post_rate_change_callback);
+}
+
+long __metal_driver_sifive_fe310_g000_pll_get_rate_hz(const struct metal_clock *clock)
+{
+ struct metal_clock *pllref = __metal_driver_sifive_fe310_g000_pll_pllref(clock);
+ struct metal_clock *pllsel0 = __metal_driver_sifive_fe310_g000_pll_pllsel0(clock);
+ long config_offset = __metal_driver_sifive_fe310_g000_pll_config_offset(clock);
+ struct __metal_driver_sifive_fe310_g000_prci *config_base =
+ __metal_driver_sifive_fe310_g000_pll_config_base(clock);
+ long divider_offset = __metal_driver_sifive_fe310_g000_pll_divider_offset(clock);
+ struct __metal_driver_sifive_fe310_g000_prci *divider_base =
+ __metal_driver_sifive_fe310_g000_pll_divider_base(clock);
+ const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable =
+ __metal_driver_sifive_fe310_g000_prci_vtable();
+
+ long cfg = vtable->get_reg(config_base, config_offset);
+ long div = vtable->get_reg(divider_base, divider_offset);
+
+ /* At the end of the PLL there's one big mux: it either selects the HFROSC
+ * (bypassing the PLL entirely) or uses the PLL. */
+ if (__METAL_GET_FIELD(cfg, PLL_SEL) == 0)
+ return metal_clock_get_rate_hz(pllsel0);
+
+ /* There's a clock mux before the PLL that selects between the HFROSC adn
+ * the HFXOSC as the PLL's input clock. */
+ long ref_hz = metal_clock_get_rate_hz(__METAL_GET_FIELD(cfg, PLL_REFSEL) ? pllref : pllsel0);
+
+ /* It's possible to bypass the PLL, which is an internal bpyass. This
+ * still obays the PLL's input clock mu. */
+ if (__METAL_GET_FIELD(cfg, PLL_BYPASS))
+ return ref_hz;
+
+ /* Logically the PLL is a three stage div-mul-div. */
+ long div_r = __METAL_GET_FIELD(cfg, PLL_R) + 1;
+ long mul_f = 2 * (__METAL_GET_FIELD(cfg, PLL_F) + 1);
+ if (__METAL_GET_FIELD(cfg, PLL_Q) == 0)
+ return -1;
+ long div_q = 1 << __METAL_GET_FIELD(cfg, PLL_Q);
+
+ /* In addition to the dividers inherent in the PLL, there's an additional
+ * clock divider that lives after the PLL and lets us pick a more
+ * interesting range of frequencies. */
+ long pllout = (((ref_hz / div_r) * mul_f) / div_q);
+ if (__METAL_GET_FIELD(div, DIV_1))
+ return pllout;
+
+ return pllout / (2 * (__METAL_GET_FIELD(div, DIV_DIV) + 1));
+}
+
+/* Find a valid configuration for the PLL which is closest to the desired
+ * output frequency.
+ * Arguments:
+ * - ref_hz PLL input frequency
+ * - rate desired PLL output frequency
+ * Returns:
+ * -1 if no valid configuration is available
+ * the index into pll_configs of a valid configuration */
+static int find_closest_config(long ref_hz, long rate)
+{
+ int closest_index = -1;
+ long closest_diff = LONG_MAX;
+
+ /* We're probably trying for a fast output frequency, so start from
+ * the high end of the configs. */
+ for(int i = (sizeof(pll_configs) / sizeof(pll_configs[0])) - 1; i >= 0; i--)
+ {
+ long config_freq = get_pll_config_freq(ref_hz, &(pll_configs[i]));
+ if(config_freq != PLL_CONFIG_NOT_VALID)
+ {
+ long freq_diff = abs(config_freq - rate);
+ if(freq_diff < closest_diff)
+ {
+ closest_index = i;
+ closest_diff = freq_diff;
+ }
+ }
+ }
+
+ return closest_index;
+}
+
+/* Configure the PLL and wait for it to lock */
+static void configure_pll(__metal_io_u32 *pllcfg, __metal_io_u32 *plloutdiv, const struct pll_config_t *config)
+{
+ __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_R);
+ __METAL_ACCESS_ONCE(pllcfg) |= PLL_R_SHIFT(config->r);
+
+ __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_F);
+ __METAL_ACCESS_ONCE(pllcfg) |= PLL_F_SHIFT(config->f);
+
+ __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_Q);
+ __METAL_ACCESS_ONCE(pllcfg) |= PLL_Q_SHIFT(config->q);
+
+ if(config->d < 0)
+ {
+ /* disable final divider */
+ __METAL_ACCESS_ONCE(plloutdiv) |= DIV_1;
+
+ __METAL_ACCESS_ONCE(plloutdiv) &= ~(DIV_DIV);
+ __METAL_ACCESS_ONCE(plloutdiv) |= PLL_DIV_SHIFT(1);
+ }
+ else
+ {
+ __METAL_ACCESS_ONCE(plloutdiv) &= ~(DIV_1);
+
+ __METAL_ACCESS_ONCE(plloutdiv) &= ~(DIV_DIV);
+ __METAL_ACCESS_ONCE(plloutdiv) |= PLL_DIV_SHIFT(config->d);
+ }
+
+ __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_BYPASS);
+
+ /* Wait for PLL to lock */
+ while((__METAL_ACCESS_ONCE(pllcfg) & PLL_LOCK) == 0) ;
+}
+
+long __metal_driver_sifive_fe310_g000_pll_set_rate_hz(struct metal_clock *clock, long rate)
+{
+ struct metal_clock *pllref = __metal_driver_sifive_fe310_g000_pll_pllref(clock);
+ struct metal_clock *pllsel0 = __metal_driver_sifive_fe310_g000_pll_pllsel0(clock);
+ long config_offset = __metal_driver_sifive_fe310_g000_pll_config_offset(clock);
+ long divider_offset = __metal_driver_sifive_fe310_g000_pll_divider_offset(clock);
+ long base = __metal_driver_sifive_fe310_g000_prci_base();
+
+ __metal_io_u32 *pllcfg = (__metal_io_u32 *) (base + config_offset);
+ __metal_io_u32 *plloutdiv = (__metal_io_u32 *) (base + divider_offset);
+
+ /* We can't modify the PLL if coreclk is driven by it, so switch it off */
+ if (__METAL_ACCESS_ONCE(pllcfg) & PLL_SEL)
+ __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_SEL);
+
+ /* There's a clock mux before the PLL that selects between the HFROSC and
+ * the HFXOSC as the PLL's input clock. */
+ long ref_hz = metal_clock_get_rate_hz(__METAL_ACCESS_ONCE(pllcfg) & PLL_REFSEL ? pllref : pllsel0);
+
+ /* if the desired rate is within 75%-125% of the input clock, bypass the PLL */
+ if((ref_hz * 3 / 4) <= rate && (ref_hz * 5 / 4) >= rate)
+ {
+ __METAL_ACCESS_ONCE(pllcfg) |= PLL_BYPASS;
+ }
+ else
+ {
+ int config_index = find_closest_config(ref_hz, rate);
+ if(config_index != -1)
+ {
+ configure_pll(pllcfg, plloutdiv, &(pll_configs[config_index]));
+ }
+ else
+ {
+ /* unable to find a valid configuration */
+ __METAL_ACCESS_ONCE(pllcfg) |= PLL_BYPASS;
+ }
+ }
+
+ /* Enable the PLL */
+ __METAL_ACCESS_ONCE(pllcfg) |= PLL_SEL;
+
+ return __metal_driver_sifive_fe310_g000_pll_get_rate_hz(clock);
+}
+
+#ifdef __METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE
+static void use_hfxosc(void) __attribute__((constructor));
+static void use_hfxosc(void)
+{
+ long init_rate = __metal_driver_sifive_fe310_g000_pll_init_rate();
+ metal_clock_set_rate_hz(
+ &__METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE->clock, init_rate
+ );
+}
+#endif
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_pll) = {
+ .init = __metal_driver_sifive_fe310_g000_pll_init,
+ .clock.get_rate_hz = __metal_driver_sifive_fe310_g000_pll_get_rate_hz,
+ .clock.set_rate_hz = __metal_driver_sifive_fe310_g000_pll_set_rate_hz,
+};
+
+#endif /* METAL_SIFIVE_FE310_G000_PLL */
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_FE310_G000_PRCI
+
+#include <metal/drivers/sifive_fe310-g000_prci.h>
+#include <metal/machine.h>
+
+long __metal_driver_sifive_fe310_g000_prci_get_reg(const struct __metal_driver_sifive_fe310_g000_prci *prci, long offset) {
+ unsigned long base = __metal_driver_sifive_fe310_g000_prci_base();
+ return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + offset));
+}
+
+long __metal_driver_sifive_fe310_g000_prci_set_reg(const struct __metal_driver_sifive_fe310_g000_prci *prci, long offset, long value) {
+ unsigned long base = __metal_driver_sifive_fe310_g000_prci_base();
+ return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + offset)) = value;
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci) = {
+ .get_reg = __metal_driver_sifive_fe310_g000_prci_get_reg,
+ .set_reg = __metal_driver_sifive_fe310_g000_prci_set_reg,
+};
+
+#endif /* METAL_SIFIVE_FE310_G000_PRCI */
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_FU540_C000_L2
+
+#include <stdint.h>
+#include <metal/io.h>
+#include <metal/drivers/sifive_fu540-c000_l2.h>
+#include <metal/machine.h>
+
+#define L2_CONFIG_WAYS_SHIFT 8
+#define L2_CONFIG_WAYS_MASK (0xFF << L2_CONFIG_WAYS_SHIFT)
+
+void __metal_driver_sifive_fu540_c000_l2_init(struct metal_cache *l2, int ways);
+
+static void metal_driver_sifive_fu540_c000_l2_init(void) __attribute__((constructor));
+static void metal_driver_sifive_fu540_c000_l2_init(void)
+{
+#ifdef __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE
+ /* Get the handle for the L2 cache controller */
+ struct metal_cache *l2 = __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE;
+ if(!l2) {
+ return;
+ }
+
+ /* Get the number of available ways per bank */
+ unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(l2);
+ uint32_t ways = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_CONFIG));
+ ways = ((ways & L2_CONFIG_WAYS_MASK) >> L2_CONFIG_WAYS_SHIFT);
+
+ /* Enable all the ways */
+ __metal_driver_sifive_fu540_c000_l2_init(l2, ways);
+#endif
+}
+
+void __metal_driver_sifive_fu540_c000_l2_init(struct metal_cache *l2, int ways)
+{
+ metal_cache_set_enabled_ways(l2, ways);
+}
+
+int __metal_driver_sifive_fu540_c000_l2_get_enabled_ways(struct metal_cache *cache)
+{
+ unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(cache);
+
+ uint32_t way_enable = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_WAYENABLE));
+
+ /* The stored number is the index, so add one */
+ return (0xFF & way_enable) + 1;
+}
+
+int __metal_driver_sifive_fu540_c000_l2_set_enabled_ways(struct metal_cache *cache, int ways)
+{
+ unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(cache);
+
+ /* We can't decrease the number of enabled ways */
+ if(metal_cache_get_enabled_ways(cache) > ways) {
+ return -2;
+ }
+
+ /* The stored value is the index, so subtract one */
+ uint32_t value = 0xFF & (ways - 1);
+
+ /* Set the number of enabled ways */
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_WAYENABLE)) = value;
+
+ /* Make sure the number of ways was set correctly */
+ if(metal_cache_get_enabled_ways(cache) != ways) {
+ return -3;
+ }
+
+ return 0;
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2) = {
+ .cache.init = __metal_driver_sifive_fu540_c000_l2_init,
+ .cache.get_enabled_ways = __metal_driver_sifive_fu540_c000_l2_get_enabled_ways,
+ .cache.set_enabled_ways = __metal_driver_sifive_fu540_c000_l2_set_enabled_ways,
+};
+
+#endif
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0
+
+#include <metal/io.h>
+#include <metal/shutdown.h>
+#include <metal/drivers/sifive_global-external-interrupts0.h>
+#include <metal/machine.h>
+
+void __metal_driver_sifive_global_external_interrupt_init(struct metal_interrupt *controller)
+{
+ struct __metal_driver_sifive_global_external_interrupts0 *global0;
+
+ global0 = (struct __metal_driver_sifive_global_external_interrupts0 *)(controller);
+ if ( !global0->init_done ) {
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
+
+ if (intc) {
+ intc->vtable->interrupt_init(intc);
+ /* Register its interrupts with with parent controller */
+ for (int i = 0;
+ i < __metal_driver_sifive_global_external_interrupts0_num_interrupts(controller);
+ i++) {
+ intc->vtable->interrupt_register(intc,
+ __metal_driver_sifive_global_external_interrupts0_interrupt_lines(controller, i),
+ NULL, controller);
+ }
+ global0->init_done = 1;
+ }
+ }
+}
+
+int __metal_driver_sifive_global_external_interrupt_register(struct metal_interrupt *controller,
+ int id, metal_interrupt_handler_t isr,
+ void *priv)
+{
+ int rc = -1;
+
+ if (id != 0) {
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
+
+ /* Enable its interrupts with parent controller */
+ if (intc) {
+ rc = intc->vtable->interrupt_register(intc, id, isr, priv);
+ }
+ }
+ return rc;
+}
+
+int __metal_driver_sifive_global_external_interrupt_enable(struct metal_interrupt *controller, int id)
+{
+ int rc = -1;
+
+ if (id != 0) {
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
+
+ /* Enable its interrupts with parent controller */
+ if (intc) {
+ rc = intc->vtable->interrupt_enable(intc, id);
+ }
+ }
+ return rc;
+}
+
+int __metal_driver_sifive_global_external_interrupt_disable(struct metal_interrupt *controller, int id)
+{
+ int rc = -1;
+
+ if (id != 0) {
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
+
+ /* Enable its interrupts with parent controller */
+ if (intc) {
+ rc = intc->vtable->interrupt_disable(intc, id);
+ }
+ }
+ return rc;
+}
+
+int __metal_driver_sifive_global_external_interrupt_set_threshold(struct metal_interrupt *controller,
+ unsigned int threshold)
+{
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
+ if (intc) {
+ return intc->vtable->interrupt_set_threshold(intc, threshold);
+ }
+ return -1;
+}
+
+unsigned int __metal_driver_sifive_global_external_interrupt_get_threshold(struct metal_interrupt *controller)
+{
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
+
+ if (intc) {
+ return intc->vtable->interrupt_get_threshold(intc);
+ }
+ return 0;
+}
+
+int __metal_driver_sifive_global_external_interrupt_set_priority(struct metal_interrupt *controller,
+ int id, unsigned int priority)
+{
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
+ if (intc) {
+ return intc->vtable->interrupt_set_priority(intc, id, priority);
+ }
+ return -1;
+}
+
+unsigned int __metal_driver_sifive_global_external_interrupt_get_priority(struct metal_interrupt *controller, int id)
+{
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
+
+ if (intc) {
+ return intc->vtable->interrupt_get_priority(intc, id);
+ }
+ return 0;
+}
+
+int __metal_driver_sifive_global_external_command_request (struct metal_interrupt *controller,
+ int command, void *data)
+{
+ int idx;
+ int rc = -1;
+
+ switch (command) {
+ case METAL_MAX_INTERRUPT_GET:
+ rc = __metal_driver_sifive_global_external_interrupts0_num_interrupts(controller);
+ break;
+ case METAL_INDEX_INTERRUPT_GET:
+ rc = 0;
+ if (data) {
+ idx = *(int *)data;
+ rc = __metal_driver_sifive_global_external_interrupts0_interrupt_lines(controller, idx);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_global_external_interrupts0) = {
+ .global0_vtable.interrupt_init = __metal_driver_sifive_global_external_interrupt_init,
+ .global0_vtable.interrupt_register = __metal_driver_sifive_global_external_interrupt_register,
+ .global0_vtable.interrupt_enable = __metal_driver_sifive_global_external_interrupt_enable,
+ .global0_vtable.interrupt_disable = __metal_driver_sifive_global_external_interrupt_disable,
+ .global0_vtable.interrupt_get_threshold = __metal_driver_sifive_global_external_interrupt_get_threshold,
+ .global0_vtable.interrupt_set_threshold = __metal_driver_sifive_global_external_interrupt_set_threshold,
+ .global0_vtable.interrupt_get_priority = __metal_driver_sifive_global_external_interrupt_get_priority,
+ .global0_vtable.interrupt_set_priority = __metal_driver_sifive_global_external_interrupt_set_priority,
+ .global0_vtable.command_request = __metal_driver_sifive_global_external_command_request,
+};
+
+#endif
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_GPIO_BUTTONS
+
+#include <string.h>
+#include <metal/drivers/riscv_cpu.h>
+#include <metal/drivers/sifive_gpio-buttons.h>
+#include <metal/machine.h>
+
+int __metal_driver_button_exist (struct metal_button *button, char *label)
+{
+ if (strcmp(__metal_driver_sifive_gpio_button_label(button), label) == 0) {
+ return 1;
+ }
+ return 0;
+}
+
+struct metal_interrupt *
+__metal_driver_button_interrupt_controller(struct metal_button *button)
+{
+ return __metal_driver_sifive_gpio_button_interrupt_controller(button);
+}
+
+int __metal_driver_button_get_interrupt_id(struct metal_button *button)
+{
+ int irq, max_irq;
+ struct metal_interrupt *irc;
+
+ irq = __metal_driver_sifive_gpio_button_interrupt_line(button);
+ irc = __metal_driver_sifive_gpio_button_interrupt_controller(button);
+
+ if (irc != NULL) {
+ max_irq = _metal_interrupt_command_request(irc,
+ METAL_MAX_INTERRUPT_GET,
+ NULL);
+
+ if (irq < max_irq) {
+ return _metal_interrupt_command_request(irc,
+ METAL_INDEX_INTERRUPT_GET,
+ (void *)&irq);
+ }
+ }
+ return METAL_INTERRUPT_ID_LCMX;
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_button) = {
+ .button_vtable.button_exist = __metal_driver_button_exist,
+ .button_vtable.interrupt_controller = __metal_driver_button_interrupt_controller,
+ .button_vtable.get_interrupt_id = __metal_driver_button_get_interrupt_id,
+};
+
+#endif
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_GPIO_LEDS
+
+#include <string.h>
+#include <metal/gpio.h>
+#include <metal/drivers/sifive_gpio-leds.h>
+#include <metal/machine.h>
+
+int __metal_driver_led_exist (struct metal_led *led, char *label)
+{
+ if (strcmp(__metal_driver_sifive_gpio_led_label(led), label) == 0) {
+ return 1;
+ }
+ return 0;
+}
+
+void __metal_driver_led_enable (struct metal_led *led)
+{
+ int pin;
+ struct metal_gpio *gpio;
+
+ pin = __metal_driver_sifive_gpio_led_pin(led);
+ gpio = __metal_driver_sifive_gpio_led_gpio(led);
+
+ if (gpio != NULL) {
+ /* Configure LED as output */
+ metal_gpio_disable_input((struct metal_gpio *) gpio, pin);
+ metal_gpio_enable_output((struct metal_gpio *) gpio, pin);
+ }
+}
+
+void __metal_driver_led_on (struct metal_led *led)
+{
+ int pin;
+ struct metal_gpio *gpio;
+
+ pin = __metal_driver_sifive_gpio_led_pin(led);
+ gpio = __metal_driver_sifive_gpio_led_gpio(led);
+
+ if (gpio != NULL) {
+ metal_gpio_set_pin((struct metal_gpio *) gpio, pin, 1);
+ }
+}
+
+void __metal_driver_led_off (struct metal_led *led)
+{
+ int pin;
+ struct metal_gpio *gpio;
+
+ pin = __metal_driver_sifive_gpio_led_pin(led);
+ gpio = __metal_driver_sifive_gpio_led_gpio(led);
+
+ if (gpio != NULL) {
+ metal_gpio_set_pin((struct metal_gpio *) gpio, pin, 0);
+ }
+}
+
+void __metal_driver_led_toggle (struct metal_led *led)
+{
+ int pin;
+ struct metal_gpio *gpio;
+
+ pin = __metal_driver_sifive_gpio_led_pin(led);
+ gpio = __metal_driver_sifive_gpio_led_gpio(led);
+
+ if (gpio != NULL) {
+ metal_gpio_toggle_pin((struct metal_gpio *) gpio, pin);
+ }
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_led) = {
+ .led_vtable.led_exist = __metal_driver_led_exist,
+ .led_vtable.led_enable = __metal_driver_led_enable,
+ .led_vtable.led_on = __metal_driver_led_on,
+ .led_vtable.led_off = __metal_driver_led_off,
+ .led_vtable.led_toggle = __metal_driver_led_toggle,
+};
+
+#endif
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_GPIO_SWITCHES
+
+#include <string.h>
+#include <metal/drivers/riscv_cpu.h>
+#include <metal/drivers/sifive_gpio-switches.h>
+#include <metal/machine.h>
+
+int __metal_driver_switch_exist (struct metal_switch *flip, char *label)
+{
+ if (strcmp(__metal_driver_sifive_gpio_switch_label(flip), label) == 0) {
+ return 1;
+ }
+ return 0;
+}
+
+struct metal_interrupt *
+__metal_driver_switch_interrupt_controller(struct metal_switch *flip)
+{
+ return __metal_driver_sifive_gpio_switch_interrupt_controller(flip);
+}
+
+int __metal_driver_switch_get_interrupt_id(struct metal_switch *flip)
+{
+ int irq, max_irq;
+ struct metal_interrupt *irc;
+
+ irq = __metal_driver_sifive_gpio_switch_interrupt_line(flip);
+ irc = __metal_driver_sifive_gpio_switch_interrupt_controller(flip);
+ if (irc != NULL) {
+ max_irq = _metal_interrupt_command_request(irc,
+ METAL_MAX_INTERRUPT_GET,
+ NULL);
+
+ if (irq < max_irq) {
+ return _metal_interrupt_command_request(irc,
+ METAL_INDEX_INTERRUPT_GET,
+ (void *)&irq);
+ }
+ }
+ return METAL_INTERRUPT_ID_LCMX;
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_switch) = {
+ .switch_vtable.switch_exist = __metal_driver_switch_exist,
+ .switch_vtable.interrupt_controller = __metal_driver_switch_interrupt_controller,
+ .switch_vtable.get_interrupt_id = __metal_driver_switch_get_interrupt_id,
+};
+
+#endif
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_GPIO0
+
+#include <metal/drivers/sifive_gpio0.h>
+#include <metal/io.h>
+#include <metal/machine.h>
+
+int __metal_driver_sifive_gpio0_enable_input(struct metal_gpio *ggpio, long source)
+{
+ long base = __metal_driver_sifive_gpio0_base(ggpio);
+
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_INPUT_EN)) |= source;
+
+ return 0;
+}
+
+int __metal_driver_sifive_gpio0_disable_input(struct metal_gpio *ggpio, long source)
+{
+ long base = __metal_driver_sifive_gpio0_base(ggpio);
+
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_INPUT_EN)) &= ~source;
+
+ return 0;
+}
+
+long __metal_driver_sifive_gpio0_input(struct metal_gpio *ggpio)
+{
+ long base = __metal_driver_sifive_gpio0_base(ggpio);
+
+ return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_VALUE));
+}
+
+long __metal_driver_sifive_gpio0_output(struct metal_gpio *ggpio)
+{
+ long base = __metal_driver_sifive_gpio0_base(ggpio);
+
+ return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT));
+}
+
+
+int __metal_driver_sifive_gpio0_disable_output(struct metal_gpio *ggpio, long source)
+{
+ long base = __metal_driver_sifive_gpio0_base(ggpio);
+
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_OUTPUT_EN)) &= ~source;
+
+ return 0;
+}
+
+int __metal_driver_sifive_gpio0_enable_output(struct metal_gpio *ggpio, long source)
+{
+ long base = __metal_driver_sifive_gpio0_base(ggpio);
+
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_OUTPUT_EN)) |= source;
+
+ return 0;
+}
+
+int __metal_driver_sifive_gpio0_output_set(struct metal_gpio *ggpio, long value)
+{
+ long base = __metal_driver_sifive_gpio0_base(ggpio);
+
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)) |= value;
+
+ return 0;
+}
+
+int __metal_driver_sifive_gpio0_output_clear(struct metal_gpio *ggpio, long value)
+{
+ long base = __metal_driver_sifive_gpio0_base(ggpio);
+
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)) &= ~value;
+
+ return 0;
+}
+
+int __metal_driver_sifive_gpio0_output_toggle(struct metal_gpio *ggpio, long value)
+{
+ long base = __metal_driver_sifive_gpio0_base(ggpio);
+
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)) =
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)) ^ value;
+
+ return 0;
+}
+
+int __metal_driver_sifive_gpio0_enable_io(struct metal_gpio *ggpio, long source, long dest)
+{
+ long base = __metal_driver_sifive_gpio0_base(ggpio);
+
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_SEL)) &= ~source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_EN)) |= dest;
+
+ return 0;
+}
+
+int __metal_driver_sifive_gpio0_disable_io(struct metal_gpio *ggpio, long source)
+{
+ long base = __metal_driver_sifive_gpio0_base(ggpio);
+
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_EN)) &= ~source;
+
+ return 0;
+}
+
+int __metal_driver_sifive_gpio0_config_int(struct metal_gpio *ggpio, long source, int intr_type)
+{
+ long base = __metal_driver_sifive_gpio0_base(ggpio);
+
+ switch (intr_type)
+ {
+ case METAL_GPIO_INT_DISABLE:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) &= ~source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) &= ~source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) &= ~source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) &= ~source;
+ break;
+ case METAL_GPIO_INT_RISING:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source;
+ break;
+ case METAL_GPIO_INT_FALLING:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source;
+ break;
+ case METAL_GPIO_INT_BOTH_EDGE:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source;
+ break;
+ case METAL_GPIO_INT_HIGH:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source;
+ break;
+ case METAL_GPIO_INT_LOW:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source;
+ break;
+ case METAL_GPIO_INT_BOTH_LEVEL:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source;
+ break;
+ case METAL_GPIO_INT_MAX:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source;
+ break;
+ }
+ return 0;
+}
+
+int __metal_driver_sifive_gpio0_clear_int(struct metal_gpio *ggpio, long source, int intr_type)
+{
+ long base = __metal_driver_sifive_gpio0_base(ggpio);
+
+ switch (intr_type)
+ {
+ case METAL_GPIO_INT_RISING:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source;
+ break;
+ case METAL_GPIO_INT_FALLING:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source;
+ break;
+ case METAL_GPIO_INT_BOTH_EDGE:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source;
+ break;
+ case METAL_GPIO_INT_HIGH:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source;
+ break;
+ case METAL_GPIO_INT_LOW:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source;
+ break;
+ case METAL_GPIO_INT_BOTH_LEVEL:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source;
+ break;
+ case METAL_GPIO_INT_MAX:
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source;
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source;
+ break;
+ }
+ return 0;
+}
+
+struct metal_interrupt *
+__metal_driver_gpio_interrupt_controller(struct metal_gpio *gpio)
+{
+ return __metal_driver_sifive_gpio0_interrupt_parent(gpio);
+}
+
+int __metal_driver_gpio_get_interrupt_id(struct metal_gpio *gpio, int pin)
+{
+ int irq;
+ irq = __metal_driver_sifive_gpio0_interrupt_lines(gpio, pin);
+ return irq;
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_gpio0) = {
+ .gpio.disable_input = __metal_driver_sifive_gpio0_disable_input,
+ .gpio.enable_input = __metal_driver_sifive_gpio0_enable_input,
+ .gpio.input = __metal_driver_sifive_gpio0_input,
+ .gpio.output = __metal_driver_sifive_gpio0_output,
+ .gpio.disable_output = __metal_driver_sifive_gpio0_disable_output,
+ .gpio.enable_output = __metal_driver_sifive_gpio0_enable_output,
+ .gpio.output_set = __metal_driver_sifive_gpio0_output_set,
+ .gpio.output_clear = __metal_driver_sifive_gpio0_output_clear,
+ .gpio.output_toggle = __metal_driver_sifive_gpio0_output_toggle,
+ .gpio.enable_io = __metal_driver_sifive_gpio0_enable_io,
+ .gpio.disable_io = __metal_driver_sifive_gpio0_disable_io,
+ .gpio.config_int = __metal_driver_sifive_gpio0_config_int,
+ .gpio.clear_int = __metal_driver_sifive_gpio0_clear_int,
+ .gpio.interrupt_controller = __metal_driver_gpio_interrupt_controller,
+ .gpio.get_interrupt_id = __metal_driver_gpio_get_interrupt_id,
+};
+
+#endif /* METAL_SIFIVE_GPIO0 */
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_LOCAL_EXTERNAL_INTERRUPTS0
+
+#include <metal/io.h>
+#include <metal/drivers/sifive_local-external-interrupts0.h>
+#include <metal/machine.h>
+
+void __metal_driver_sifive_local_external_interrupt_init(struct metal_interrupt *controller)
+{
+ struct __metal_driver_sifive_local_external_interrupts0 *local0;
+
+ local0 = (struct __metal_driver_sifive_local_external_interrupts0 *)(controller);
+ if ( !local0->init_done ) {
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_local_external_interrupts0_interrupt_parent(controller);
+
+ if (intc) {
+ /* Register its interruptswith with parent controller, aka all external to default isr */
+ for (int i = 0;
+ i < __metal_driver_sifive_local_external_interrupts0_num_interrupts(controller);
+ i++) {
+ intc->vtable->interrupt_register(intc,
+ __metal_driver_sifive_local_external_interrupts0_interrupt_lines(controller, i),
+ NULL, controller);
+ }
+ local0->init_done = 1;
+ }
+ }
+}
+
+int __metal_driver_sifive_local_external_interrupt_register(struct metal_interrupt *controller,
+ int id, metal_interrupt_handler_t isr,
+ void *priv)
+{
+ int rc = -1;
+
+ if (id != 0) {
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_local_external_interrupts0_interrupt_parent(controller);
+
+ /* Enable its interrupts with parent controller */
+ if (intc) {
+ rc = intc->vtable->interrupt_register(intc, id, isr, priv);
+ }
+ }
+ return rc;
+}
+
+int __metal_driver_sifive_local_external_interrupt_enable(struct metal_interrupt *controller, int id)
+{
+ int rc = -1;
+
+ if (id != 0) {
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_local_external_interrupts0_interrupt_parent(controller);
+
+ /* Enable its interrupts with parent controller */
+ if (intc) {
+ rc = intc->vtable->interrupt_enable(intc, id);
+ }
+ }
+ return rc;
+}
+
+int __metal_driver_sifive_local_external_interrupt_disable(struct metal_interrupt *controller, int id)
+{
+ int rc = -1;
+
+ if (id != 0) {
+ struct metal_interrupt *intc =
+ __metal_driver_sifive_local_external_interrupts0_interrupt_parent(controller);
+
+ /* Enable its interrupts with parent controller */
+ if (intc) {
+ rc = intc->vtable->interrupt_disable(intc, id);
+ }
+ }
+ return rc;
+}
+
+int __metal_driver_sifive_local_external_interrupt_set_threshold(struct metal_interrupt *controller,
+ unsigned int threshold)
+{
+ /* Core controller does not support threshold configuration */
+ return -1;
+}
+
+unsigned int __metal_driver_sifive_local_external_interrupt_get_threshold(struct metal_interrupt *controller)
+{
+ /* Core controller does not support threshold configuration */
+ return 0;
+}
+
+
+int __metal_driver_sifive_local_external_interrupt_set_priority(struct metal_interrupt *controller,
+ int id, unsigned int priority)
+{
+ /* Core controller does not support priority configuration */
+ return -1;
+}
+
+unsigned int __metal_driver_sifive_local_external_interrupt_get_priority(struct metal_interrupt *controller, int id)
+{
+ /* Core controller does not support priority configuration */
+ return 0;
+}
+
+int __metal_driver_sifive_local_external_command_request (struct metal_interrupt *controller,
+ int command, void *data)
+{
+ int idx;
+ int rc = -1;
+
+ switch (command) {
+ case METAL_MAX_INTERRUPT_GET:
+ rc = __metal_driver_sifive_local_external_interrupts0_num_interrupts(controller);
+ break;
+ case METAL_INDEX_INTERRUPT_GET:
+ rc = 0;
+ if (data) {
+ idx = *(int *)data;
+ rc = __metal_driver_sifive_local_external_interrupts0_interrupt_lines(controller, idx);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_local_external_interrupts0) = {
+ .local0_vtable.interrupt_init = __metal_driver_sifive_local_external_interrupt_init,
+ .local0_vtable.interrupt_register = __metal_driver_sifive_local_external_interrupt_register,
+ .local0_vtable.interrupt_enable = __metal_driver_sifive_local_external_interrupt_enable,
+ .local0_vtable.interrupt_disable = __metal_driver_sifive_local_external_interrupt_disable,
+ .local0_vtable.interrupt_get_threshold = __metal_driver_sifive_local_external_interrupt_get_threshold,
+ .local0_vtable.interrupt_set_threshold = __metal_driver_sifive_local_external_interrupt_set_threshold,
+ .local0_vtable.interrupt_get_priority = __metal_driver_sifive_local_external_interrupt_get_priority,
+ .local0_vtable.interrupt_set_priority = __metal_driver_sifive_local_external_interrupt_set_priority,
+ .local0_vtable.command_request = __metal_driver_sifive_local_external_command_request,
+};
+
+#endif
+
+typedef int no_empty_translation_units;
+
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_RTC0
+
+#include <metal/drivers/sifive_rtc0.h>
+#include <metal/machine.h>
+
+#include <limits.h>
+
+/* RTCCFG */
+#define METAL_RTCCFG_RTCSCALE_MASK 0xF
+#define METAL_RTCCFG_ENALWAYS (1 << 12)
+#define METAL_RTCCFG_IP0 (1 << 28)
+
+/* RTCCMP0 */
+#define METAL_RTCCMP0_MAX UINT32_MAX
+
+#define RTC_REG(base, offset) (((unsigned long)base + offset))
+#define RTC_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)RTC_REG(base, offset)))
+
+uint64_t __metal_driver_sifive_rtc0_get_rate(const struct metal_rtc *const rtc) {
+ const struct metal_clock *const clock = __metal_driver_sifive_rtc0_clock(rtc);
+ return metal_clock_get_rate_hz(clock);
+}
+
+uint64_t __metal_driver_sifive_rtc0_set_rate(const struct metal_rtc *const rtc, const uint64_t rate) {
+ const struct metal_clock *const clock = __metal_driver_sifive_rtc0_clock(rtc);
+ return metal_clock_get_rate_hz(clock);
+}
+
+uint64_t __metal_driver_sifive_rtc0_get_compare(const struct metal_rtc *const rtc) {
+ const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
+
+ const uint32_t shift = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) & METAL_RTCCFG_RTCSCALE_MASK;
+
+ return ((uint64_t)RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) << shift);
+}
+
+uint64_t __metal_driver_sifive_rtc0_set_compare(const struct metal_rtc *const rtc, const uint64_t compare) {
+ const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
+
+ /* Determine the bit shift and shifted value to store in rtccmp0/rtccfg.scale */
+ uint32_t shift = 0;
+ uint64_t comp_shifted = compare;
+ while (comp_shifted > METAL_RTCCMP0_MAX) {
+ shift += 1;
+ comp_shifted = comp_shifted >> shift;
+ }
+
+ /* Set the value of rtccfg.scale */
+ uint32_t cfg = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG);
+ cfg &= ~(METAL_RTCCFG_RTCSCALE_MASK);
+ cfg |= (METAL_RTCCFG_RTCSCALE_MASK & shift);
+ RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) = cfg;
+
+ /* Set the value of rtccmp0 */
+ RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) = (uint32_t) comp_shifted;
+
+ return __metal_driver_sifive_rtc0_get_compare(rtc);
+}
+
+uint64_t __metal_driver_sifive_rtc0_get_count(const struct metal_rtc *const rtc) {
+ const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
+
+ uint64_t count = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI);
+ count <<= 32;
+ count |= RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO);
+
+ return count;
+}
+
+uint64_t __metal_driver_sifive_rtc0_set_count(const struct metal_rtc *const rtc, const uint64_t count) {
+ const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
+
+ RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI) = (UINT_MAX & (count >> 32));
+ RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO) = (UINT_MAX & count);
+
+ return __metal_driver_sifive_rtc0_get_count(rtc);
+}
+
+int __metal_driver_sifive_rtc0_run(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option) {
+ const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
+
+ switch (option) {
+ default:
+ case METAL_RTC_STOP:
+ RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) &= ~(METAL_RTCCFG_ENALWAYS);
+ break;
+ case METAL_RTC_RUN:
+ RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) |= METAL_RTCCFG_ENALWAYS;
+ break;
+ }
+
+ return 0;
+}
+
+struct metal_interrupt *__metal_driver_sifive_rtc0_get_interrupt(const struct metal_rtc *const rtc) {
+ return __metal_driver_sifive_rtc0_interrupt_parent(rtc);
+}
+
+int __metal_driver_sifive_rtc0_get_interrupt_id(const struct metal_rtc *const rtc) {
+ return __metal_driver_sifive_rtc0_interrupt_line(rtc);
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_rtc0) = {
+ .rtc.get_rate = __metal_driver_sifive_rtc0_get_rate,
+ .rtc.set_rate = __metal_driver_sifive_rtc0_set_rate,
+ .rtc.get_compare = __metal_driver_sifive_rtc0_get_compare,
+ .rtc.set_compare = __metal_driver_sifive_rtc0_set_compare,
+ .rtc.get_count = __metal_driver_sifive_rtc0_get_count,
+ .rtc.set_count = __metal_driver_sifive_rtc0_set_count,
+ .rtc.run = __metal_driver_sifive_rtc0_run,
+ .rtc.get_interrupt = __metal_driver_sifive_rtc0_get_interrupt,
+ .rtc.get_interrupt_id = __metal_driver_sifive_rtc0_get_interrupt_id,
+};
+
+#endif
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_SPI0
+#include <metal/drivers/sifive_spi0.h>
+#include <metal/io.h>
+#include <metal/machine.h>
+#include <metal/time.h>
+#include <time.h>
+
+/* Register fields */
+#define METAL_SPI_SCKDIV_MASK 0xFFF
+
+#define METAL_SPI_SCKMODE_PHA_SHIFT 0
+#define METAL_SPI_SCKMODE_POL_SHIFT 1
+
+#define METAL_SPI_CSMODE_MASK 3
+#define METAL_SPI_CSMODE_AUTO 0
+#define METAL_SPI_CSMODE_HOLD 2
+#define METAL_SPI_CSMODE_OFF 3
+
+#define METAL_SPI_PROTO_MASK 3
+#define METAL_SPI_PROTO_SINGLE 0
+#define METAL_SPI_PROTO_DUAL 1
+#define METAL_SPI_PROTO_QUAD 2
+
+#define METAL_SPI_ENDIAN_LSB 4
+
+#define METAL_SPI_DISABLE_RX 8
+
+#define METAL_SPI_FRAME_LEN_SHIFT 16
+#define METAL_SPI_FRAME_LEN_MASK (0xF << METAL_SPI_FRAME_LEN_SHIFT)
+
+#define METAL_SPI_TXDATA_FULL (1 << 31)
+#define METAL_SPI_RXDATA_EMPTY (1 << 31)
+#define METAL_SPI_TXMARK_MASK 7
+#define METAL_SPI_TXWM 1
+#define METAL_SPI_TXRXDATA_MASK (0xFF)
+
+#define METAL_SPI_INTERVAL_SHIFT 16
+
+#define METAL_SPI_CONTROL_IO 0
+#define METAL_SPI_CONTROL_MAPPED 1
+
+#define METAL_SPI_REG(offset) (((unsigned long)control_base + offset))
+#define METAL_SPI_REGB(offset) (__METAL_ACCESS_ONCE((__metal_io_u8 *)METAL_SPI_REG(offset)))
+#define METAL_SPI_REGW(offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)METAL_SPI_REG(offset)))
+
+#define METAL_SPI_RXDATA_TIMEOUT 1
+
+static int configure_spi(struct __metal_driver_sifive_spi0 *spi, struct metal_spi_config *config)
+{
+ long control_base = __metal_driver_sifive_spi0_control_base((struct metal_spi *)spi);
+ /* Set protocol */
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_PROTO_MASK);
+ switch (config->protocol) {
+ case METAL_SPI_SINGLE:
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE;
+ break;
+ case METAL_SPI_DUAL:
+ if (config->multi_wire == MULTI_WIRE_ALL)
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_DUAL;
+ else
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE;
+ break;
+ case METAL_SPI_QUAD:
+ if (config->multi_wire == MULTI_WIRE_ALL)
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_QUAD;
+ else
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE;
+ break;
+ default:
+ /* Unsupported value */
+ return -1;
+ }
+
+ /* Set Polarity */
+ if(config->polarity) {
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKMODE) |= (1 << METAL_SPI_SCKMODE_PHA_SHIFT);
+ } else {
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKMODE) &= ~(1 << METAL_SPI_SCKMODE_PHA_SHIFT);
+ }
+
+ /* Set Phase */
+ if(config->phase) {
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKMODE) |= (1 << METAL_SPI_SCKMODE_POL_SHIFT);
+ } else {
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKMODE) &= ~(1 << METAL_SPI_SCKMODE_POL_SHIFT);
+ }
+
+ /* Set Endianness */
+ if(config->little_endian) {
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_ENDIAN_LSB;
+ } else {
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_ENDIAN_LSB);
+ }
+
+ /* Always populate receive FIFO */
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_DISABLE_RX);
+
+ /* Set CS Active */
+ if(config->cs_active_high) {
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSDEF) = 0;
+ } else {
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSDEF) = 1;
+ }
+
+ /* Set frame length */
+ if((METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) & METAL_SPI_FRAME_LEN_MASK) != (8 << METAL_SPI_FRAME_LEN_SHIFT)) {
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_FRAME_LEN_MASK);
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= (8 << METAL_SPI_FRAME_LEN_SHIFT);
+ }
+
+ /* Set CS line */
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSID) = 1 << (config->csid);
+
+ /* Toggle off memory-mapped SPI flash mode, toggle on programmable IO mode
+ * It seems that with this line uncommented, the debugger cannot have access
+ * to the chip at all because it assumes the chip is in memory-mapped mode.
+ * I have to compile the code with this line commented and launch gdb,
+ * reset cores, reset $pc, set *((int *) 0x20004060) = 0, (set the flash
+ * interface control register to programmable I/O mode) and then continue
+ * Alternative, comment out the "flash" line in openocd.cfg */
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FCTRL) = METAL_SPI_CONTROL_IO;
+
+ return 0;
+}
+
+static void spi_mode_switch(struct __metal_driver_sifive_spi0 *spi,
+ struct metal_spi_config *config,
+ unsigned int trans_stage) {
+ long control_base =
+ __metal_driver_sifive_spi0_control_base((struct metal_spi *)spi);
+
+ if (config->multi_wire == trans_stage) {
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_PROTO_MASK);
+ switch (config->protocol) {
+ case METAL_SPI_DUAL:
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_DUAL;
+ break;
+ case METAL_SPI_QUAD:
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_QUAD;
+ break;
+ default:
+ /* Unsupported value */
+ return;
+ }
+ }
+}
+
+int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi,
+ struct metal_spi_config *config,
+ size_t len,
+ char *tx_buf,
+ char *rx_buf)
+{
+ struct __metal_driver_sifive_spi0 *spi = (void *)gspi;
+ long control_base = __metal_driver_sifive_spi0_control_base(gspi);
+ int rc = 0;
+ size_t i = 0;
+
+ rc = configure_spi(spi, config);
+ if(rc != 0) {
+ return rc;
+ }
+
+ /* Hold the chip select line for all len transferred */
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= ~(METAL_SPI_CSMODE_MASK);
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) |= METAL_SPI_CSMODE_HOLD;
+
+ unsigned long rxdata;
+
+ /* Declare time_t variables to break out of infinite while loop */
+ time_t endwait;
+
+ for (i = 0; i < config->cmd_num; i++) {
+
+ while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL)
+ ;
+
+ if (tx_buf) {
+ METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i];
+ } else {
+ METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0;
+ }
+
+ endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT;
+
+ while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) &
+ METAL_SPI_RXDATA_EMPTY) {
+ if (metal_time() > endwait) {
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &=
+ ~(METAL_SPI_CSMODE_MASK);
+
+ return 1;
+ }
+ }
+
+ if (rx_buf) {
+ rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK);
+ }
+ }
+
+ /* switch to Dual/Quad mode */
+ spi_mode_switch(spi, config, MULTI_WIRE_ADDR_DATA);
+
+ /* Send Addr data */
+ for (; i < (config->cmd_num + config->addr_num); i++) {
+
+ while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL)
+ ;
+
+ if (tx_buf) {
+ METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i];
+ } else {
+ METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0;
+ }
+
+ endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT;
+
+ while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) &
+ METAL_SPI_RXDATA_EMPTY) {
+ if (metal_time() > endwait) {
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &=
+ ~(METAL_SPI_CSMODE_MASK);
+
+ return 1;
+ }
+ }
+
+ if (rx_buf) {
+ rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK);
+ }
+ }
+
+ /* Send Dummy data */
+ for (; i < (config->cmd_num + config->addr_num + config->dummy_num); i++) {
+
+ while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL)
+ ;
+
+ if (tx_buf) {
+ METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i];
+ } else {
+ METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0;
+ }
+
+ endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT;
+
+ while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) &
+ METAL_SPI_RXDATA_EMPTY) {
+ if (metal_time() > endwait) {
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &=
+ ~(METAL_SPI_CSMODE_MASK);
+ return 1;
+ }
+ }
+ if (rx_buf) {
+ rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK);
+ }
+ }
+
+ /* switch to Dual/Quad mode */
+ spi_mode_switch(spi, config, MULTI_WIRE_DATA_ONLY);
+
+ for (; i < len; i++) {
+ /* Master send bytes to the slave */
+
+ /* Wait for TXFIFO to not be full */
+ while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL);
+
+ /* Transfer byte by modifying the least significant byte in the TXDATA register */
+ if (tx_buf) {
+ METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i];
+ } else {
+ /* Transfer a 0 byte if the sending buffer is NULL */
+ METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0;
+ }
+
+ /* Master receives bytes from the RX FIFO */
+
+ /* Wait for RXFIFO to not be empty, but break the nested loops if timeout
+ * this timeout method needs refining, preferably taking into account
+ * the device specs */
+ endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT;
+
+ while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) & METAL_SPI_RXDATA_EMPTY) {
+ if (metal_time() > endwait) {
+ /* If timeout, deassert the CS */
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= ~(METAL_SPI_CSMODE_MASK);
+
+ /* If timeout, return error code 1 immediately */
+ return 1;
+ }
+ }
+
+ /* Only store the dequeued byte if the receive_buffer is not NULL */
+ if (rx_buf) {
+ rx_buf[i] = (char) (rxdata & METAL_SPI_TXRXDATA_MASK);
+ }
+ }
+
+ /* On the last byte, set CSMODE to auto so that the chip select transitions back to high
+ * The reason that CS pin is not deasserted after transmitting out the byte buffer is timing.
+ * The code on the host side likely executes faster than the ability of FIFO to send out bytes.
+ * After the host iterates through the array, fifo is likely not cleared yet. If host deasserts
+ * the CS pin immediately, the following bytes in the output FIFO will not be sent consecutively.
+ * There needs to be a better way to handle this. */
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= ~(METAL_SPI_CSMODE_MASK);
+
+ return 0;
+}
+
+int __metal_driver_sifive_spi0_get_baud_rate(struct metal_spi *gspi)
+{
+ struct __metal_driver_sifive_spi0 *spi = (void *)gspi;
+ return spi->baud_rate;
+}
+
+int __metal_driver_sifive_spi0_set_baud_rate(struct metal_spi *gspi, int baud_rate)
+{
+ long control_base = __metal_driver_sifive_spi0_control_base(gspi);
+ struct metal_clock *clock = __metal_driver_sifive_spi0_clock(gspi);
+ struct __metal_driver_sifive_spi0 *spi = (void *)gspi;
+
+ spi->baud_rate = baud_rate;
+
+ if (clock != NULL) {
+ long clock_rate = clock->vtable->get_rate_hz(clock);
+
+ /* Calculate divider */
+ long div = (clock_rate / (2 * baud_rate)) - 1;
+
+ if(div > METAL_SPI_SCKDIV_MASK) {
+ /* The requested baud rate is lower than we can support at
+ * the current clock rate */
+ return -1;
+ }
+
+ /* Set divider */
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKDIV) &= ~METAL_SPI_SCKDIV_MASK;
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKDIV) |= (div & METAL_SPI_SCKDIV_MASK);
+ }
+
+ return 0;
+}
+
+static void pre_rate_change_callback_func(void *priv)
+{
+ long control_base = __metal_driver_sifive_spi0_control_base((struct metal_spi *)priv);
+
+ /* Detect when the TXDATA is empty by setting the transmit watermark count
+ * to one and waiting until an interrupt is pending (indicating an empty TXFIFO) */
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXMARK) &= ~(METAL_SPI_TXMARK_MASK);
+ METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXMARK) |= (METAL_SPI_TXMARK_MASK & 1);
+
+ while((METAL_SPI_REGW(METAL_SIFIVE_SPI0_IP) & METAL_SPI_TXWM) == 0) ;
+}
+
+static void post_rate_change_callback_func(void *priv)
+{
+ struct __metal_driver_sifive_spi0 *spi = priv;
+ metal_spi_set_baud_rate(&spi->spi, spi->baud_rate);
+}
+
+void __metal_driver_sifive_spi0_init(struct metal_spi *gspi, int baud_rate)
+{
+ struct __metal_driver_sifive_spi0 *spi = (void *)(gspi);
+ struct metal_clock *clock = __metal_driver_sifive_spi0_clock(gspi);
+ struct __metal_driver_sifive_gpio0 *pinmux = __metal_driver_sifive_spi0_pinmux(gspi);
+
+ if(clock != NULL) {
+ spi->pre_rate_change_callback.callback = &pre_rate_change_callback_func;
+ spi->pre_rate_change_callback.priv = spi;
+ metal_clock_register_pre_rate_change_callback(clock, &(spi->pre_rate_change_callback));
+
+ spi->post_rate_change_callback.callback = &post_rate_change_callback_func;
+ spi->post_rate_change_callback.priv = spi;
+ metal_clock_register_post_rate_change_callback(clock, &(spi->post_rate_change_callback));
+ }
+
+ metal_spi_set_baud_rate(&(spi->spi), baud_rate);
+
+ if (pinmux != NULL) {
+ long pinmux_output_selector = __metal_driver_sifive_spi0_pinmux_output_selector(gspi);
+ long pinmux_source_selector = __metal_driver_sifive_spi0_pinmux_source_selector(gspi);
+ pinmux->gpio.vtable->enable_io(
+ (struct metal_gpio *) pinmux,
+ pinmux_output_selector,
+ pinmux_source_selector
+ );
+ }
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_spi0) = {
+ .spi.init = __metal_driver_sifive_spi0_init,
+ .spi.transfer = __metal_driver_sifive_spi0_transfer,
+ .spi.get_baud_rate = __metal_driver_sifive_spi0_get_baud_rate,
+ .spi.set_baud_rate = __metal_driver_sifive_spi0_set_baud_rate,
+};
+#endif /* METAL_SIFIVE_SPI0 */
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_TEST0
+
+#include <metal/machine.h>
+
+#include <stdint.h>
+
+#include <metal/drivers/sifive_test0.h>
+#include <metal/io.h>
+
+void __metal_driver_sifive_test0_exit(const struct __metal_shutdown *sd, int code) __attribute__((noreturn));
+void __metal_driver_sifive_test0_exit(const struct __metal_shutdown *sd, int code)
+{
+ long base = __metal_driver_sifive_test0_base(sd);
+ uint32_t out = (code << 16) + (code == 0 ? 0x5555 : 0x3333);
+ while (1) {
+ __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_TEST0_FINISHER_OFFSET)) = out;
+ }
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_test0) = {
+ .shutdown.exit = &__metal_driver_sifive_test0_exit,
+};
+#endif /* METAL_SIFIVE_TEST0 */
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_TRACE
+
+#include <metal/drivers/sifive_trace.h>
+#include <metal/machine.h>
+
+#define TRACE_REG(offset) (((unsigned long)base + (offset)))
+#define TRACE_REG8(offset) \
+ (__METAL_ACCESS_ONCE((__metal_io_u8 *)TRACE_REG(offset)))
+#define TRACE_REG16(offset) \
+ (__METAL_ACCESS_ONCE((__metal_io_u16 *)TRACE_REG(offset)))
+#define TRACE_REG32(offset) \
+ (__METAL_ACCESS_ONCE((__metal_io_u32 *)TRACE_REG(offset)))
+
+static void write_itc_uint32(struct metal_uart *trace, uint32_t data) {
+ long base = __metal_driver_sifive_trace_base(trace);
+
+ TRACE_REG32(METAL_SIFIVE_TRACE_ITCSTIMULUS) = data;
+}
+
+static void write_itc_uint16(struct metal_uart *trace, uint16_t data) {
+ long base = __metal_driver_sifive_trace_base(trace);
+
+ TRACE_REG16(METAL_SIFIVE_TRACE_ITCSTIMULUS + 2) = data;
+}
+
+static void write_itc_uint8(struct metal_uart *trace, uint8_t data) {
+ long base = __metal_driver_sifive_trace_base(trace);
+
+ TRACE_REG8(METAL_SIFIVE_TRACE_ITCSTIMULUS + 3) = data;
+}
+
+int __metal_driver_sifive_trace_putc(struct metal_uart *trace,
+ unsigned char c) {
+ static uint32_t buffer = 0;
+ static int bytes_in_buffer = 0;
+
+ buffer |= (((uint32_t)c) << (bytes_in_buffer * 8));
+
+ bytes_in_buffer += 1;
+
+ if (bytes_in_buffer >= 4) {
+ write_itc_uint32(trace, buffer);
+
+ buffer = 0;
+ bytes_in_buffer = 0;
+ } else if ((c == '\n') || (c == '\r')) { // partial write
+ switch (bytes_in_buffer) {
+ case 3: // do a full word write
+ write_itc_uint16(trace, (uint16_t)(buffer));
+ write_itc_uint8(trace, (uint8_t)(buffer >> 16));
+ break;
+ case 2: // do a 16 bit write
+ write_itc_uint16(trace, (uint16_t)buffer);
+ break;
+ case 1: // do a 1 byte write
+ write_itc_uint8(trace, (uint8_t)buffer);
+ break;
+ }
+
+ buffer = 0;
+ bytes_in_buffer = 0;
+ }
+
+ return (int)c;
+}
+
+void __metal_driver_sifive_trace_init(struct metal_uart *trace, int baud_rate) {
+ // The only init we do here is to make sure ITC 0 is enabled. It is up to
+ // Freedom Studio or other mechanisms to make sure tracing is enabled. If we
+ // try to enable tracing here, it will likely conflict with Freedom Studio,
+ // and they will just fight with each other.
+
+ long base = __metal_driver_sifive_trace_base(trace);
+
+ TRACE_REG32(METAL_SIFIVE_TRACE_ITCTRACEENABLE) |= 0x00000001;
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_trace) = {
+ .uart.init = __metal_driver_sifive_trace_init,
+ .uart.putc = __metal_driver_sifive_trace_putc,
+ .uart.getc = NULL,
+
+ .uart.get_baud_rate = NULL,
+ .uart.set_baud_rate = NULL,
+
+ .uart.controller_interrupt = NULL,
+ .uart.get_interrupt_id = NULL,
+};
+
+#endif /* METAL_SIFIVE_TRACE */
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_UART0
+
+#include <metal/drivers/sifive_uart0.h>
+#include <metal/machine.h>
+
+/* TXDATA Fields */
+#define UART_TXEN (1 << 0)
+#define UART_TXFULL (1 << 31)
+
+/* RXDATA Fields */
+#define UART_RXEN (1 << 0)
+#define UART_RXEMPTY (1 << 31)
+
+/* TXCTRL Fields */
+#define UART_NSTOP (1 << 1)
+#define UART_TXCNT(count) ((0x7 & count) << 16)
+
+/* IP Fields */
+#define UART_TXWM (1 << 0)
+
+#define UART_REG(offset) (((unsigned long)control_base + offset))
+#define UART_REGB(offset) (__METAL_ACCESS_ONCE((__metal_io_u8 *)UART_REG(offset)))
+#define UART_REGW(offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)UART_REG(offset)))
+
+struct metal_interrupt *
+__metal_driver_sifive_uart0_interrupt_controller(struct metal_uart *uart)
+{
+ return __metal_driver_sifive_uart0_interrupt_parent(uart);
+}
+
+int __metal_driver_sifive_uart0_get_interrupt_id(struct metal_uart *uart)
+{
+ return (__metal_driver_sifive_uart0_interrupt_line(uart) + METAL_INTERRUPT_ID_GL0);
+}
+
+
+int __metal_driver_sifive_uart0_txready(struct metal_uart *uart)
+{
+ long control_base = __metal_driver_sifive_uart0_control_base(uart);
+
+ return !((UART_REGW(METAL_SIFIVE_UART0_TXDATA) & UART_TXFULL));
+}
+
+
+int __metal_driver_sifive_uart0_putc(struct metal_uart *uart, int c)
+{
+ long control_base = __metal_driver_sifive_uart0_control_base(uart);
+
+ while (!__metal_driver_sifive_uart0_txready(uart)) {
+ /* wait */
+ }
+ UART_REGW(METAL_SIFIVE_UART0_TXDATA) = c;
+ return 0;
+}
+
+
+int __metal_driver_sifive_uart0_getc(struct metal_uart *uart, int *c)
+{
+ uint32_t ch;
+ long control_base = __metal_driver_sifive_uart0_control_base(uart);
+ /* No seperate status register, we get status and the byte at same time */
+ ch = UART_REGW(METAL_SIFIVE_UART0_RXDATA);;
+ if( ch & UART_RXEMPTY ){
+ *c = -1; /* aka: EOF in most of the world */
+ } else {
+ *c = ch & 0x0ff;
+ }
+ return 0;
+}
+
+
+int __metal_driver_sifive_uart0_get_baud_rate(struct metal_uart *guart)
+{
+ struct __metal_driver_sifive_uart0 *uart = (void *)guart;
+ return uart->baud_rate;
+}
+
+int __metal_driver_sifive_uart0_set_baud_rate(struct metal_uart *guart, int baud_rate)
+{
+ struct __metal_driver_sifive_uart0 *uart = (void *)guart;
+ long control_base = __metal_driver_sifive_uart0_control_base(guart);
+ struct metal_clock *clock = __metal_driver_sifive_uart0_clock(guart);
+
+ uart->baud_rate = baud_rate;
+
+ if (clock != NULL) {
+ long clock_rate = clock->vtable->get_rate_hz(clock);
+ UART_REGW(METAL_SIFIVE_UART0_DIV) = clock_rate / baud_rate - 1;
+ UART_REGW(METAL_SIFIVE_UART0_TXCTRL) |= UART_TXEN;
+ UART_REGW(METAL_SIFIVE_UART0_RXCTRL) |= UART_RXEN;
+ }
+ return 0;
+}
+
+static void pre_rate_change_callback_func(void *priv)
+{
+ struct __metal_driver_sifive_uart0 *uart = priv;
+ long control_base = __metal_driver_sifive_uart0_control_base((struct metal_uart *)priv);
+ struct metal_clock *clock = __metal_driver_sifive_uart0_clock((struct metal_uart *)priv);
+
+ /* Detect when the TXDATA is empty by setting the transmit watermark count
+ * to one and waiting until an interrupt is pending */
+
+ UART_REGW(METAL_SIFIVE_UART0_TXCTRL) &= ~(UART_TXCNT(0x7));
+ UART_REGW(METAL_SIFIVE_UART0_TXCTRL) |= UART_TXCNT(1);
+
+ while((UART_REGW(METAL_SIFIVE_UART0_IP) & UART_TXWM) == 0) ;
+
+ /* When the TXDATA clears, the UART is still shifting out the last byte.
+ * Calculate the time we must drain to finish transmitting and then wait
+ * that long. */
+
+ long bits_per_symbol = (UART_REGW(METAL_SIFIVE_UART0_TXCTRL) & (1 << 1)) ? 9 : 10;
+ long clk_freq = clock->vtable->get_rate_hz(clock);
+ long cycles_to_wait = bits_per_symbol * clk_freq / uart->baud_rate;
+
+ for(volatile long x = 0; x < cycles_to_wait; x++)
+ __asm__("nop");
+}
+
+static void post_rate_change_callback_func(void *priv)
+{
+ struct __metal_driver_sifive_uart0 *uart = priv;
+ metal_uart_set_baud_rate(&uart->uart, uart->baud_rate);
+}
+
+void __metal_driver_sifive_uart0_init(struct metal_uart *guart, int baud_rate)
+{
+ struct __metal_driver_sifive_uart0 *uart = (void *)(guart);
+ struct metal_clock *clock = __metal_driver_sifive_uart0_clock(guart);
+ struct __metal_driver_sifive_gpio0 *pinmux = __metal_driver_sifive_uart0_pinmux(guart);
+
+ if(clock != NULL) {
+ uart->pre_rate_change_callback.callback = &pre_rate_change_callback_func;
+ uart->pre_rate_change_callback.priv = guart;
+ metal_clock_register_pre_rate_change_callback(clock, &(uart->pre_rate_change_callback));
+
+ uart->post_rate_change_callback.callback = &post_rate_change_callback_func;
+ uart->post_rate_change_callback.priv = guart;
+ metal_clock_register_post_rate_change_callback(clock, &(uart->post_rate_change_callback));
+ }
+
+ metal_uart_set_baud_rate(&(uart->uart), baud_rate);
+
+ if (pinmux != NULL) {
+ long pinmux_output_selector = __metal_driver_sifive_uart0_pinmux_output_selector(guart);
+ long pinmux_source_selector = __metal_driver_sifive_uart0_pinmux_source_selector(guart);
+ pinmux->gpio.vtable->enable_io(
+ (struct metal_gpio *) pinmux,
+ pinmux_output_selector,
+ pinmux_source_selector
+ );
+ }
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_uart0) = {
+ .uart.init = __metal_driver_sifive_uart0_init,
+ .uart.putc = __metal_driver_sifive_uart0_putc,
+ .uart.getc = __metal_driver_sifive_uart0_getc,
+ .uart.get_baud_rate = __metal_driver_sifive_uart0_get_baud_rate,
+ .uart.set_baud_rate = __metal_driver_sifive_uart0_set_baud_rate,
+ .uart.controller_interrupt = __metal_driver_sifive_uart0_interrupt_controller,
+ .uart.get_interrupt_id = __metal_driver_sifive_uart0_get_interrupt_id,
+};
+
+#endif /* METAL_SIFIVE_UART0 */
+
+typedef int no_empty_translation_units;
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_WDOG0
+
+#include <metal/drivers/sifive_uart0.h>
+#include <metal/machine.h>
+
+#include <limits.h>
+
+/* WDOGCFG */
+#define METAL_WDOGCFG_SCALE_MASK 7
+#define METAL_WDOGCFG_RSTEN (1 << 8)
+#define METAL_WDOGCFG_ZEROCMP (1 << 9)
+#define METAL_WDOGCFG_ENALWAYS (1 << 12)
+#define METAL_WDOGCFG_COREAWAKE (1 << 13)
+#define METAL_WDOGCFG_IP (1 << 28)
+
+/* WDOGCMP */
+#define METAL_WDOGCMP_MASK 0xFFFF
+
+#define WDOG_REG(base, offset) (((unsigned long)base + offset))
+#define WDOG_REGB(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u8 *)WDOG_REG(base, offset)))
+#define WDOG_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)WDOG_REG(base, offset)))
+
+/* All writes to watchdog registers must be precedded by a write of
+ * a magic number to WDOGKEY */
+#define WDOG_UNLOCK(base) (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGKEY) = METAL_SIFIVE_WDOG0_MAGIC_KEY)
+
+/* Unlock the watchdog and then perform a register access */
+#define WDOG_UNLOCK_REGW(base, offset) \
+ WDOG_UNLOCK(base);\
+ WDOG_REGW(base, offset)
+
+int __metal_driver_sifive_wdog0_feed(const struct metal_watchdog *const wdog)
+{
+ const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
+
+ WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGFEED) = METAL_SIFIVE_WDOG0_MAGIC_FOOD;
+
+ return 0;
+}
+
+long int __metal_driver_sifive_wdog0_get_rate(const struct metal_watchdog *const wdog)
+{
+ const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
+ const struct metal_clock *const clock = __metal_driver_sifive_wdog0_clock(wdog);
+
+ const long int clock_rate = metal_clock_get_rate_hz(clock);
+
+ if (clock_rate == 0)
+ return -1;
+
+ const unsigned int scale = (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) & METAL_WDOGCFG_SCALE_MASK);
+
+ return clock_rate / (1 << scale);
+}
+
+long int __metal_driver_sifive_wdog0_set_rate(const struct metal_watchdog *const wdog, const long int rate)
+{
+ const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
+ const struct metal_clock *const clock = __metal_driver_sifive_wdog0_clock(wdog);
+
+ const long int clock_rate = metal_clock_get_rate_hz(clock);
+
+ if (rate >= clock_rate) {
+ /* We can't scale the rate above the driving clock. Clear the scale
+ * field and return the driving clock rate */
+ WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_SCALE_MASK);
+ return clock_rate;
+ }
+
+ /* Look for the closest scale value */
+ long min_diff = LONG_MAX;
+ unsigned int min_scale = 0;
+ for (int i = 0; i < METAL_WDOGCFG_SCALE_MASK; i++) {
+ const long int new_rate = clock_rate / (1 << i);
+
+ long int diff = rate - new_rate;
+ if (diff < 0)
+ diff *= -1;
+
+ if (diff < min_diff) {
+ min_diff = diff;
+ min_scale = i;
+ }
+ }
+
+ WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_SCALE_MASK);
+ WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= (METAL_WDOGCFG_SCALE_MASK & min_scale);
+
+ return clock_rate / (1 << min_scale);
+}
+
+long int __metal_driver_sifive_wdog0_get_timeout(const struct metal_watchdog *const wdog)
+{
+ const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
+
+ return (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP) & METAL_WDOGCMP_MASK);
+}
+
+long int __metal_driver_sifive_wdog0_set_timeout(const struct metal_watchdog *const wdog, const long int timeout)
+{
+ const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
+
+ /* Cap the timeout at the max value */
+ const long int set_timeout = timeout > METAL_WDOGCMP_MASK ? METAL_WDOGCMP_MASK : timeout;
+
+ /* If we edit the timeout value in-place by masking the compare value to 0 and
+ * then writing it, we cause a spurious interrupt because the compare value
+ * is temporarily 0. Instead, read the value into a local variable, modify it
+ * there, and then write the whole register back */
+ uint32_t wdogcmp = WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP);
+
+ wdogcmp &= ~(METAL_WDOGCMP_MASK);
+ wdogcmp |= set_timeout;
+
+ WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP) = wdogcmp;
+
+ return set_timeout;
+}
+
+int __metal_driver_sifive_wdog0_set_result(const struct metal_watchdog *const wdog,
+ const enum metal_watchdog_result result)
+{
+ const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
+
+ /* Turn off reset enable and counter reset */
+ WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_RSTEN | METAL_WDOGCFG_ZEROCMP);
+
+ switch (result) {
+ default:
+ case METAL_WATCHDOG_NO_RESULT:
+ break;
+ case METAL_WATCHDOG_INTERRUPT:
+ /* Reset counter to zero after match */
+ WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_ZEROCMP;
+ break;
+ case METAL_WATCHDOG_FULL_RESET:
+ WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_RSTEN;
+ break;
+ }
+
+ return 0;
+}
+
+int __metal_driver_sifive_wdog0_run(const struct metal_watchdog *const wdog,
+ const enum metal_watchdog_run_option option)
+{
+ const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
+
+ WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_ENALWAYS | METAL_WDOGCFG_COREAWAKE);
+
+ switch (option) {
+ default:
+ case METAL_WATCHDOG_STOP:
+ break;
+ case METAL_WATCHDOG_RUN_ALWAYS:
+ /* Feed the watchdog before starting to reset counter */
+ __metal_driver_sifive_wdog0_feed(wdog);
+
+ WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_ENALWAYS;
+ break;
+ case METAL_WATCHDOG_RUN_AWAKE:
+ /* Feed the watchdog before starting to reset counter */
+ __metal_driver_sifive_wdog0_feed(wdog);
+
+ WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_COREAWAKE;
+ break;
+ }
+
+ return 0;
+}
+
+struct metal_interrupt *__metal_driver_sifive_wdog0_get_interrupt(const struct metal_watchdog *const wdog)
+{
+ return __metal_driver_sifive_wdog0_interrupt_parent(wdog);
+}
+
+int __metal_driver_sifive_wdog0_get_interrupt_id(const struct metal_watchdog *const wdog)
+{
+ return __metal_driver_sifive_wdog0_interrupt_line(wdog);
+}
+
+int __metal_driver_sifive_wdog0_clear_interrupt(const struct metal_watchdog *const wdog)
+{
+ const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
+
+ /* Clear the interrupt pending bit */
+ WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_IP);
+
+ return 0;
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_wdog0) = {
+ .watchdog.feed = __metal_driver_sifive_wdog0_feed,
+ .watchdog.get_rate = __metal_driver_sifive_wdog0_get_rate,
+ .watchdog.set_rate = __metal_driver_sifive_wdog0_set_rate,
+ .watchdog.get_timeout = __metal_driver_sifive_wdog0_get_timeout,
+ .watchdog.set_timeout = __metal_driver_sifive_wdog0_set_timeout,
+ .watchdog.set_result = __metal_driver_sifive_wdog0_set_result,
+ .watchdog.run = __metal_driver_sifive_wdog0_run,
+ .watchdog.get_interrupt = __metal_driver_sifive_wdog0_get_interrupt,
+ .watchdog.get_interrupt_id = __metal_driver_sifive_wdog0_get_interrupt_id,
+ .watchdog.clear_interrupt = __metal_driver_sifive_wdog0_clear_interrupt,
+};
+
+#endif /* METAL_SIFIVE_WDOG0 */
+
+typedef int no_empty_translation_units;
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+/* This code executes before _start, which is contained inside the C library.
+ * In embedded systems we want to ensure that _enter, which contains the first
+ * code to be executed, can be loaded at a specific address. To enable this
+ * feature we provide the '.text.metal.init.enter' section, which is
+ * defined to have the first address being where execution should start. */
+.section .text.metal.init.enter
+.global _enter
+_enter:
+ .cfi_startproc
+
+ /* Inform the debugger that there is nowhere to backtrace past _enter. */
+ .cfi_undefined ra
+
+ /* The absolute first thing that must happen is configuring the global
+ * pointer register, which must be done with relaxation disabled because
+ * it's not valid to obtain the address of any symbol without GP
+ * configured. The C environment might go ahead and do this again, but
+ * that's safe as it's a fixed register. */
+.option push
+.option norelax
+ la gp, __global_pointer$
+.option pop
+
+ /* Set up a simple trap vector to catch anything that goes wrong early in
+ * the boot process. */
+ la t0, early_trap_vector
+ csrw mtvec, t0
+ /* enable chicken bit if core is bullet series*/
+ la t0, __metal_chicken_bit
+ beqz t0, 1f
+ csrwi 0x7C1, 0
+1:
+
+ /* There may be pre-initialization routines inside the MBI code that run in
+ * C, so here we set up a C environment. First we set up a stack pointer,
+ * which is left as a weak reference in order to allow initialization
+ * routines that do not need a stack to be set up to transparently be
+ * called. */
+ .weak __metal_stack_pointer
+ la sp, __metal_stack_pointer
+
+ /* Check for an initialization routine and call it if one exists, otherwise
+ * just skip over the call entirely. Note that __metal_initialize isn't
+ * actually a full C function, as it doesn't end up with the .bss or .data
+ * segments having been initialized. This is done to avoid putting a
+ * burden on systems that can be initialized without having a C environment
+ * set up. */
+ .weak __metal_before_start
+ la ra, __metal_before_start
+ beqz ra, 1f
+ jalr ra
+1:
+
+ /* At this point we can enter the C runtime's startup file. The arguments
+ * to this function are designed to match those provided to the SEE, just
+ * so we don't have to write another ABI. */
+ csrr a0, mhartid
+ li a1, 0
+ li a2, 0
+ call _start
+
+ /* If we've made it back here then there's probably something wrong. We
+ * allow the METAL to register a handler here. */
+ .weak __metal_after_main
+ la ra, __metal_after_main
+ beqz ra, 1f
+ jalr ra
+1:
+
+ /* If that handler returns then there's not a whole lot we can do. Just
+ * try to make some noise. */
+ la t0, 1f
+ csrw mtvec, t0
+1:
+ lw t1, 0(x0)
+ j 1b
+
+ .cfi_endproc
+
+/* For sanity's sake we set up an early trap vector that just does nothing. If
+ * you end up here then there's a bug in the early boot code somewhere. */
+.section .text.metal.init.trapvec
+.align 2
+early_trap_vector:
+ .cfi_startproc
+ csrr t0, mcause
+ csrr t1, mepc
+ csrr t2, mtval
+ j early_trap_vector
+ .cfi_endproc
+
+/* The GCC port might not emit a __register_frame_info symbol, which eventually
+ * results in a weak undefined reference that eventually causes crash when it
+ * is dereference early in boot. We really shouldn't need to put this here,
+ * but to deal with what I think is probably a bug in the linker script I'm
+ * going to leave this in for now. At least it's fairly cheap :) */
+.weak __register_frame_info
+.global __register_frame_info
+.section .text.metal.init.__register_frame_info
+__register_frame_info:
+ .cfi_startproc
+ ret
+ .cfi_endproc
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine.h>
+#include <metal/gpio.h>
+
+extern __inline__ int metal_gpio_disable_input(struct metal_gpio *gpio, int pin);
+extern __inline__ int metal_gpio_enable_input(struct metal_gpio *gpio, int pin);
+extern __inline__ int metal_gpio_enable_output(struct metal_gpio *gpio, int pin);
+extern __inline__ int metal_gpio_disable_output(struct metal_gpio *gpio, int pin);
+extern __inline__ int metal_gpio_get_output_pin(struct metal_gpio *gpio, int pin);
+extern __inline__ int metal_gpio_get_input_pin(struct metal_gpio *gpio, int pin);
+extern __inline__ int metal_gpio_set_pin(struct metal_gpio *, int pin, int value);
+extern __inline__ int metal_gpio_clear_pin(struct metal_gpio *, int pin);
+extern __inline__ int metal_gpio_toggle_pin(struct metal_gpio *, int pin);
+extern __inline__ int metal_gpio_enable_pinmux(struct metal_gpio *, int pin, int io_function);
+extern __inline__ int metal_gpio_disable_pinmux(struct metal_gpio *, int pin);
+extern __inline__ struct metal_interrupt* metal_gpio_interrupt_controller(struct metal_gpio *gpio);
+extern __inline__ int metal_gpio_get_interrupt_id(struct metal_gpio *gpio, int pin);
+extern __inline__ int metal_gpio_config_interrupt(struct metal_gpio *gpio, int pin, int intr_type);
+extern __inline__ int metal_gpio_clear_interrupt(struct metal_gpio *gpio, int pin, int intr_type);
+
+struct metal_gpio *metal_gpio_get_device(unsigned int device_num)
+{
+ if(device_num > __MEE_DT_MAX_GPIOS) {
+ return NULL;
+ }
+
+ return (struct metal_gpio *) __metal_gpio_table[device_num];
+}
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <string.h>
+#include <metal/interrupt.h>
+#include <metal/machine.h>
+
+struct metal_interrupt* metal_interrupt_get_controller (metal_intr_cntrl_type cntrl,
+ int id)
+{
+ switch (cntrl) {
+ case METAL_CPU_CONTROLLER:
+ break;
+ case METAL_CLINT_CONTROLLER:
+#ifdef __METAL_DT_RISCV_CLINT0_HANDLE
+ return __METAL_DT_RISCV_CLINT0_HANDLE;
+#endif
+ break;
+ case METAL_CLIC_CONTROLLER:
+#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
+ return __METAL_DT_SIFIVE_CLIC0_HANDLE;
+#endif
+ break;
+ case METAL_PLIC_CONTROLLER:
+#ifdef __METAL_DT_RISCV_PLIC0_HANDLE
+ return __METAL_DT_RISCV_PLIC0_HANDLE;
+#endif
+ break;
+ }
+ return NULL;
+}
+
+extern __inline__ void metal_interrupt_init(struct metal_interrupt *controller);
+
+extern __inline__ int metal_interrupt_set_vector_mode(struct metal_interrupt *controller,
+ metal_vector_mode mode);
+extern __inline__ metal_vector_mode metal_interrupt_get_vector_mode(struct metal_interrupt *controller);
+
+extern __inline__ int metal_interrupt_set_privilege(struct metal_interrupt *controller,
+ metal_intr_priv_mode mode);
+extern __inline__ metal_intr_priv_mode metal_interrupt_get_privilege(struct metal_interrupt *controller);
+
+extern __inline__ int metal_interrupt_set_threshold(struct metal_interrupt *controller,
+ unsigned int level);
+extern __inline__ unsigned int metal_interrupt_get_threshold(struct metal_interrupt *controller);
+
+extern __inline__ unsigned int metal_interrupt_get_priority(struct metal_interrupt *controller, int id);
+
+extern __inline__ int metal_interrupt_set_priority(struct metal_interrupt *controller, int id, unsigned int priority);
+
+extern __inline__ int metal_interrupt_clear(struct metal_interrupt *controller, int id);
+
+extern __inline__ int metal_interrupt_set(struct metal_interrupt *controller, int id);
+
+extern __inline__ int metal_interrupt_register_handler(struct metal_interrupt *controller,
+ int id,
+ metal_interrupt_handler_t handler,
+ void *priv);
+
+extern __inline__ int metal_interrupt_register_vector_handler(struct metal_interrupt *controller,
+ int id,
+ metal_interrupt_vector_handler_t handler,
+ void *priv_data);
+
+extern __inline__ int metal_interrupt_enable(struct metal_interrupt *controller, int id);
+
+extern __inline__ int metal_interrupt_disable(struct metal_interrupt *controller, int id);
+
+extern __inline__ unsigned int metal_interrupt_get_threshold(struct metal_interrupt *controller);
+
+extern __inline__ int metal_interrupt_set_threshold(struct metal_interrupt *controller, unsigned int threshold);
+
+extern __inline__ unsigned int metal_interrupt_get_priority(struct metal_interrupt *controller, int id);
+
+extern __inline__ int metal_interrupt_set_priority(struct metal_interrupt *controller, int id, unsigned int priority);
+
+extern __inline__ int metal_interrupt_vector_enable(struct metal_interrupt *controller, int id);
+
+extern __inline__ int metal_interrupt_vector_disable(struct metal_interrupt *controller, int id);
+
+extern __inline__ int _metal_interrupt_command_request(struct metal_interrupt *controller,
+ int cmd, void *data);
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <string.h>
+#include <metal/led.h>
+#include <metal/machine.h>
+
+struct metal_led* metal_led_get_rgb (char *label, char *color)
+{
+ int i;
+ struct metal_led *led;
+ char led_label[100];
+
+ if ((__METAL_DT_MAX_LEDS == 0) ||
+ (label == NULL) || (color == NULL)) {
+ return NULL;
+ }
+
+ strcpy(led_label, label);
+ strcat(led_label, color);
+ for (i = 0; i < __METAL_DT_MAX_LEDS; i++) {
+ led = (struct metal_led*)__metal_led_table[i];
+ if (led->vtable->led_exist(led, led_label)) {
+ return led;
+ }
+ }
+ return NULL;
+}
+
+struct metal_led* metal_led_get (char *label)
+{
+ return metal_led_get_rgb(label, "");
+}
+
+extern __inline__ void metal_led_enable(struct metal_led *led);
+extern __inline__ void metal_led_on(struct metal_led *led);
+extern __inline__ void metal_led_off(struct metal_led *led);
+extern __inline__ void metal_led_toggle(struct metal_led *led);
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/lock.h>
+
+extern __inline__ int metal_lock_init(struct metal_lock *lock);
+extern __inline__ int metal_lock_take(struct metal_lock *lock);
+extern __inline__ int metal_lock_give(struct metal_lock *lock);
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine.h>
+#include <metal/memory.h>
+
+struct metal_memory *metal_get_memory_from_address(const uintptr_t address) {
+ for(int i = 0; i < __METAL_DT_MAX_MEMORIES; i++) {
+ struct metal_memory *mem = __metal_memory_table[i];
+
+ uintptr_t lower_bound = metal_memory_get_base_address(mem);
+ uintptr_t upper_bound = lower_bound + metal_memory_get_size(mem);
+
+ if((address >= lower_bound) && (address < upper_bound)) {
+ return mem;
+ }
+ }
+
+ return NULL;
+}
+
+extern __inline__ uintptr_t metal_memory_get_base_address(const struct metal_memory *memory);
+extern __inline__ size_t metal_memory_get_size(const struct metal_memory *memory);
+extern __inline__ int metal_memory_supports_atomics(const struct metal_memory *memory);
+extern __inline__ int metal_memory_is_cachable(const struct metal_memory *memory);
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine.h>
+#include <metal/pmp.h>
+#include <metal/cpu.h>
+
+#define CONFIG_TO_INT(_config) (*((char *) &(_config)))
+#define INT_TO_CONFIG(_int) (*((struct metal_pmp_config *)(char *) &(_int)))
+
+struct metal_pmp *metal_pmp_get_device(void)
+{
+#ifdef __METAL_DT_PMP_HANDLE
+ return __METAL_DT_PMP_HANDLE;
+#else
+ return NULL;
+#endif
+}
+
+/* This function calculates the minimum granularity from the address
+ * that pmpaddr takes on after writing all ones to pmpaddr when pmpcfg = 0.
+ *
+ * Detect the address granularity based on the position of the
+ * least-significant 1 set in the address.
+ *
+ * For example, if the value read from pmpaddr is 0x3ffffc00, the
+ * least-significant set bit is in bit 10 (counting from 0), resulting
+ * in a detected granularity of 2^(10 + 2) = 4096.
+ */
+static uintptr_t _get_detected_granularity(uintptr_t address) {
+ if(address == 0) {
+ return (uintptr_t) -1;
+ }
+
+ /* Get the index of the least significant set bit */
+ int index = 0;
+ while(((address >> index) & 0x1) == 0) {
+ index += 1;
+ }
+
+ /* The granularity is equal to 2^(index + 2) bytes */
+ return (1 << (index + 2));
+}
+
+/* This function calculates the granularity requested by the user's provided
+ * value for pmpaddr.
+ *
+ * Calculate the requested granularity based on the position of the
+ * least-significant unset bit.
+ *
+ * For example, if the requested address is 0x20009ff, the least-significant
+ * unset bit is at index 9 (counting from 0), resulting in a requested
+ * granularity of 2^(9 + 3) = 4096.
+ */
+static uintptr_t _get_pmpaddr_granularity(uintptr_t address) {
+ /* Get the index of the least significant unset bit */
+ int index = 0;
+ while(((address >> index) & 0x1) == 1) {
+ index += 1;
+ }
+
+ /* The granularity is equal to 2^(index + 3) bytes */
+ return (1 << (index + 3));
+}
+
+/* Get the number of pmp regions for the given hart */
+int metal_pmp_num_regions(int hartid)
+{
+ struct metal_cpu *cpu = metal_cpu_get(hartid);
+
+ return __metal_driver_cpu_num_pmp_regions(cpu);
+}
+
+/* Get the number of pmp regions for the current hart */
+static unsigned int _pmp_regions() {
+ return metal_pmp_num_regions(metal_cpu_get_current_hartid());
+}
+
+void metal_pmp_init(struct metal_pmp *pmp) {
+ if(!pmp) {
+ return;
+ }
+
+ struct metal_pmp_config init_config = {
+ .L = METAL_PMP_UNLOCKED,
+ .A = METAL_PMP_OFF,
+ .X = 0,
+ .W = 0,
+ .R = 0,
+ };
+
+ for(unsigned int i = 0; i < _pmp_regions(); i++) {
+ metal_pmp_set_region(pmp, i, init_config, 0);
+ }
+
+ /* Detect the region granularity by writing all 1s to pmpaddr0 while
+ * pmpcfg0 = 0. */
+ if(metal_pmp_set_address(pmp, 0, -1) != 0) {
+ /* Failed to detect granularity */
+ return;
+ }
+
+ /* Calculate the granularity based on the value that pmpaddr0 takes on */
+ pmp->_granularity[metal_cpu_get_current_hartid()] = _get_detected_granularity(metal_pmp_get_address(pmp, 0));
+
+ /* Clear pmpaddr0 */
+ metal_pmp_set_address(pmp, 0, 0);
+}
+
+int metal_pmp_set_region(struct metal_pmp *pmp,
+ unsigned int region,
+ struct metal_pmp_config config,
+ size_t address)
+{
+ struct metal_pmp_config old_config;
+ size_t old_address;
+ size_t cfgmask;
+ size_t pmpcfg;
+ int rc = 0;
+
+ if(!pmp) {
+ /* Device handle cannot be NULL */
+ return 1;
+ }
+
+ if(region > _pmp_regions()) {
+ /* Region outside of supported range */
+ return 2;
+ }
+
+ if(config.A == METAL_PMP_NA4 && pmp->_granularity[metal_cpu_get_current_hartid()] > 4) {
+ /* The requested granularity is too small */
+ return 3;
+ }
+
+ if(config.A == METAL_PMP_NAPOT &&
+ pmp->_granularity[metal_cpu_get_current_hartid()] > _get_pmpaddr_granularity(address))
+ {
+ /* The requested granularity is too small */
+ return 3;
+ }
+
+ rc = metal_pmp_get_region(pmp, region, &old_config, &old_address);
+ if(rc) {
+ /* Error reading region */
+ return rc;
+ }
+
+ if(old_config.L == METAL_PMP_LOCKED) {
+ /* Cannot modify locked region */
+ return 4;
+ }
+
+ /* Update the address first, because if the region is being locked we won't
+ * be able to modify it after we set the config */
+ if(old_address != address) {
+ switch(region) {
+ case 0:
+ __asm__("csrw pmpaddr0, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 1:
+ __asm__("csrw pmpaddr1, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 2:
+ __asm__("csrw pmpaddr2, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 3:
+ __asm__("csrw pmpaddr3, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 4:
+ __asm__("csrw pmpaddr4, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 5:
+ __asm__("csrw pmpaddr5, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 6:
+ __asm__("csrw pmpaddr6, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 7:
+ __asm__("csrw pmpaddr7, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 8:
+ __asm__("csrw pmpaddr8, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 9:
+ __asm__("csrw pmpaddr9, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 10:
+ __asm__("csrw pmpaddr10, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 11:
+ __asm__("csrw pmpaddr11, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 12:
+ __asm__("csrw pmpaddr12, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 13:
+ __asm__("csrw pmpaddr13, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 14:
+ __asm__("csrw pmpaddr14, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ case 15:
+ __asm__("csrw pmpaddr15, %[addr]"
+ :: [addr] "r" (address) :);
+ break;
+ }
+ }
+
+#if __riscv_xlen==32
+ if(CONFIG_TO_INT(old_config) != CONFIG_TO_INT(config)) {
+ /* Mask to clear old pmpcfg */
+ cfgmask = (0xFF << (8 * (region % 4)) );
+ pmpcfg = (CONFIG_TO_INT(config) << (8 * (region % 4)) );
+
+ switch(region / 4) {
+ case 0:
+ __asm__("csrc pmpcfg0, %[mask]"
+ :: [mask] "r" (cfgmask) :);
+
+ __asm__("csrs pmpcfg0, %[cfg]"
+ :: [cfg] "r" (pmpcfg) :);
+ break;
+ case 1:
+ __asm__("csrc pmpcfg1, %[mask]"
+ :: [mask] "r" (cfgmask) :);
+
+ __asm__("csrs pmpcfg1, %[cfg]"
+ :: [cfg] "r" (pmpcfg) :);
+ break;
+ case 2:
+ __asm__("csrc pmpcfg2, %[mask]"
+ :: [mask] "r" (cfgmask) :);
+
+ __asm__("csrs pmpcfg2, %[cfg]"
+ :: [cfg] "r" (pmpcfg) :);
+ break;
+ case 3:
+ __asm__("csrc pmpcfg3, %[mask]"
+ :: [mask] "r" (cfgmask) :);
+
+ __asm__("csrs pmpcfg3, %[cfg]"
+ :: [cfg] "r" (pmpcfg) :);
+ break;
+ }
+ }
+#elif __riscv_xlen==64
+ if(CONFIG_TO_INT(old_config) != CONFIG_TO_INT(config)) {
+ /* Mask to clear old pmpcfg */
+ cfgmask = (0xFF << (8 * (region % 8)) );
+ pmpcfg = (CONFIG_TO_INT(config) << (8 * (region % 8)) );
+
+ switch(region / 8) {
+ case 0:
+ __asm__("csrc pmpcfg0, %[mask]"
+ :: [mask] "r" (cfgmask) :);
+
+ __asm__("csrs pmpcfg0, %[cfg]"
+ :: [cfg] "r" (pmpcfg) :);
+ break;
+ case 1:
+ __asm__("csrc pmpcfg2, %[mask]"
+ :: [mask] "r" (cfgmask) :);
+
+ __asm__("csrs pmpcfg2, %[cfg]"
+ :: [cfg] "r" (pmpcfg) :);
+ break;
+ }
+ }
+#else
+#error XLEN is not set to supported value for PMP driver
+#endif
+
+ return 0;
+}
+
+int metal_pmp_get_region(struct metal_pmp *pmp,
+ unsigned int region,
+ struct metal_pmp_config *config,
+ size_t *address)
+{
+ size_t pmpcfg = 0;
+ char *pmpcfg_convert = (char *)&pmpcfg;
+
+ if(!pmp || !config || !address) {
+ /* NULL pointers are invalid arguments */
+ return 1;
+ }
+
+ if(region > _pmp_regions()) {
+ /* Region outside of supported range */
+ return 2;
+ }
+
+#if __riscv_xlen==32
+ switch(region / 4) {
+ case 0:
+ __asm__("csrr %[cfg], pmpcfg0"
+ : [cfg] "=r" (pmpcfg) ::);
+ break;
+ case 1:
+ __asm__("csrr %[cfg], pmpcfg1"
+ : [cfg] "=r" (pmpcfg) ::);
+ break;
+ case 2:
+ __asm__("csrr %[cfg], pmpcfg2"
+ : [cfg] "=r" (pmpcfg) ::);
+ break;
+ case 3:
+ __asm__("csrr %[cfg], pmpcfg3"
+ : [cfg] "=r" (pmpcfg) ::);
+ break;
+ }
+
+ pmpcfg = (0xFF & (pmpcfg >> (8 * (region % 4)) ) );
+
+#elif __riscv_xlen==64
+ switch(region / 8) {
+ case 0:
+ __asm__("csrr %[cfg], pmpcfg0"
+ : [cfg] "=r" (pmpcfg) ::);
+ break;
+ case 1:
+ __asm__("csrr %[cfg], pmpcfg2"
+ : [cfg] "=r" (pmpcfg) ::);
+ break;
+ }
+
+ pmpcfg = (0xFF & (pmpcfg >> (8 * (region % 8)) ) );
+
+#else
+#error XLEN is not set to supported value for PMP driver
+#endif
+
+ *config = INT_TO_CONFIG(*pmpcfg_convert);
+
+ switch(region) {
+ case 0:
+ __asm__("csrr %[addr], pmpaddr0"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 1:
+ __asm__("csrr %[addr], pmpaddr1"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 2:
+ __asm__("csrr %[addr], pmpaddr2"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 3:
+ __asm__("csrr %[addr], pmpaddr3"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 4:
+ __asm__("csrr %[addr], pmpaddr4"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 5:
+ __asm__("csrr %[addr], pmpaddr5"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 6:
+ __asm__("csrr %[addr], pmpaddr6"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 7:
+ __asm__("csrr %[addr], pmpaddr7"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 8:
+ __asm__("csrr %[addr], pmpaddr8"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 9:
+ __asm__("csrr %[addr], pmpaddr9"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 10:
+ __asm__("csrr %[addr], pmpaddr10"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 11:
+ __asm__("csrr %[addr], pmpaddr11"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 12:
+ __asm__("csrr %[addr], pmpaddr12"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 13:
+ __asm__("csrr %[addr], pmpaddr13"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 14:
+ __asm__("csrr %[addr], pmpaddr14"
+ : [addr] "=r" (*address) ::);
+ break;
+ case 15:
+ __asm__("csrr %[addr], pmpaddr15"
+ : [addr] "=r" (*address) ::);
+ break;
+ }
+
+ return 0;
+}
+
+int metal_pmp_lock(struct metal_pmp *pmp, unsigned int region)
+{
+ struct metal_pmp_config config;
+ size_t address;
+ int rc = 0;
+
+ rc = metal_pmp_get_region(pmp, region, &config, &address);
+ if(rc) {
+ return rc;
+ }
+
+ if(config.L == METAL_PMP_LOCKED) {
+ return 0;
+ }
+
+ config.L = METAL_PMP_LOCKED;
+
+ rc = metal_pmp_set_region(pmp, region, config, address);
+
+ return rc;
+}
+
+
+int metal_pmp_set_address(struct metal_pmp *pmp, unsigned int region, size_t address)
+{
+ struct metal_pmp_config config;
+ size_t old_address;
+ int rc = 0;
+
+ rc = metal_pmp_get_region(pmp, region, &config, &old_address);
+ if(rc) {
+ return rc;
+ }
+
+ rc = metal_pmp_set_region(pmp, region, config, address);
+
+ return rc;
+}
+
+size_t metal_pmp_get_address(struct metal_pmp *pmp, unsigned int region)
+{
+ struct metal_pmp_config config;
+ size_t address = 0;
+
+ metal_pmp_get_region(pmp, region, &config, &address);
+
+ return address;
+}
+
+
+int metal_pmp_set_address_mode(struct metal_pmp *pmp, unsigned int region, enum metal_pmp_address_mode mode)
+{
+ struct metal_pmp_config config;
+ size_t address;
+ int rc = 0;
+
+ rc = metal_pmp_get_region(pmp, region, &config, &address);
+ if(rc) {
+ return rc;
+ }
+
+ config.A = mode;
+
+ rc = metal_pmp_set_region(pmp, region, config, address);
+
+ return rc;
+}
+
+enum metal_pmp_address_mode metal_pmp_get_address_mode(struct metal_pmp *pmp, unsigned int region)
+{
+ struct metal_pmp_config config;
+ size_t address = 0;
+
+ metal_pmp_get_region(pmp, region, &config, &address);
+
+ return config.A;
+}
+
+
+int metal_pmp_set_executable(struct metal_pmp *pmp, unsigned int region, int X)
+{
+ struct metal_pmp_config config;
+ size_t address;
+ int rc = 0;
+
+ rc = metal_pmp_get_region(pmp, region, &config, &address);
+ if(rc) {
+ return rc;
+ }
+
+ config.X = X;
+
+ rc = metal_pmp_set_region(pmp, region, config, address);
+
+ return rc;
+}
+
+int metal_pmp_get_executable(struct metal_pmp *pmp, unsigned int region)
+{
+ struct metal_pmp_config config;
+ size_t address = 0;
+
+ metal_pmp_get_region(pmp, region, &config, &address);
+
+ return config.X;
+}
+
+
+int metal_pmp_set_writeable(struct metal_pmp *pmp, unsigned int region, int W)
+{
+ struct metal_pmp_config config;
+ size_t address;
+ int rc = 0;
+
+ rc = metal_pmp_get_region(pmp, region, &config, &address);
+ if(rc) {
+ return rc;
+ }
+
+ config.W = W;
+
+ rc = metal_pmp_set_region(pmp, region, config, address);
+
+ return rc;
+}
+
+int metal_pmp_get_writeable(struct metal_pmp *pmp, unsigned int region)
+{
+ struct metal_pmp_config config;
+ size_t address = 0;
+
+ metal_pmp_get_region(pmp, region, &config, &address);
+
+ return config.W;
+}
+
+
+int metal_pmp_set_readable(struct metal_pmp *pmp, unsigned int region, int R)
+{
+ struct metal_pmp_config config;
+ size_t address;
+ int rc = 0;
+
+ rc = metal_pmp_get_region(pmp, region, &config, &address);
+ if(rc) {
+ return rc;
+ }
+
+ config.R = R;
+
+ rc = metal_pmp_set_region(pmp, region, config, address);
+
+ return rc;
+}
+
+int metal_pmp_get_readable(struct metal_pmp *pmp, unsigned int region)
+{
+ struct metal_pmp_config config;
+ size_t address = 0;
+
+ metal_pmp_get_region(pmp, region, &config, &address);
+
+ return config.R;
+}
+
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <stddef.h>
+
+#include <metal/privilege.h>
+
+#define METAL_MSTATUS_MIE_OFFSET 3
+#define METAL_MSTATUS_MPIE_OFFSET 7
+#define METAL_MSTATUS_SIE_OFFSET 1
+#define METAL_MSTATUS_SPIE_OFFSET 5
+#define METAL_MSTATUS_UIE_OFFSET 0
+#define METAL_MSTATUS_UPIE_OFFSET 4
+
+#define METAL_MSTATUS_MPP_OFFSET 11
+#define METAL_MSTATUS_MPP_MASK 3
+
+void metal_privilege_drop_to_mode(enum metal_privilege_mode mode,
+ struct metal_register_file regfile,
+ metal_privilege_entry_point_t entry_point)
+{
+ uintptr_t mstatus;
+ __asm__ volatile("csrr %0, mstatus" : "=r" (mstatus));
+
+ /* Set xPIE bits based on current xIE bits */
+ if(mstatus && (1 << METAL_MSTATUS_MIE_OFFSET)) {
+ mstatus |= (1 << METAL_MSTATUS_MPIE_OFFSET);
+ } else {
+ mstatus &= ~(1 << METAL_MSTATUS_MPIE_OFFSET);
+ }
+ if(mstatus && (1 << METAL_MSTATUS_SIE_OFFSET)) {
+ mstatus |= (1 << METAL_MSTATUS_SPIE_OFFSET);
+ } else {
+ mstatus &= ~(1 << METAL_MSTATUS_SPIE_OFFSET);
+ }
+ if(mstatus && (1 << METAL_MSTATUS_UIE_OFFSET)) {
+ mstatus |= (1 << METAL_MSTATUS_UPIE_OFFSET);
+ } else {
+ mstatus &= ~(1 << METAL_MSTATUS_UPIE_OFFSET);
+ }
+
+ /* Set MPP to the requested privilege mode */
+ mstatus &= ~(METAL_MSTATUS_MPP_MASK << METAL_MSTATUS_MPP_OFFSET);
+ mstatus |= (mode << METAL_MSTATUS_MPP_OFFSET);
+
+ __asm__ volatile("csrw mstatus, %0" :: "r" (mstatus));
+
+ /* Set the entry point in MEPC */
+ __asm__ volatile("csrw mepc, %0" :: "r" (entry_point));
+
+ /* Set the register file */
+ __asm__ volatile("mv ra, %0" :: "r" (regfile.ra));
+ __asm__ volatile("mv sp, %0" :: "r" (regfile.sp));
+
+ __asm__ volatile("mret");
+}
+
--- /dev/null
+/* Copyright 2019 SiFive, Inc. */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine.h>
+#include <metal/rtc.h>
+
+#include <stddef.h>
+
+extern inline uint64_t metal_rtc_get_rate(const struct metal_rtc *const rtc);
+extern inline uint64_t metal_rtc_set_rate(const struct metal_rtc *const rtc, const uint64_t rate);
+extern inline uint64_t metal_rtc_get_compare(const struct metal_rtc *const rtc);
+extern inline uint64_t metal_rtc_set_compare(const struct metal_rtc *const rtc, const uint64_t compare);
+extern inline uint64_t metal_rtc_get_count(const struct metal_rtc *const rtc);
+extern inline uint64_t metal_rtc_set_count(const struct metal_rtc *const rtc, const uint64_t count);
+extern inline int metal_rtc_run(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option);
+extern inline struct metal_interrupt *metal_rtc_get_interrupt(const struct metal_rtc *const rtc);
+extern inline int metal_rtc_get_interrupt_id(const struct metal_rtc *const rtc);
+
+struct metal_rtc *metal_rtc_get_device(int index) {
+#ifdef __METAL_DT_MAX_RTCS
+ if (index < __METAL_DT_MAX_RTCS) {
+ return (struct metal_rtc *) __metal_rtc_table[index];
+ }
+#endif
+ return NULL;
+}
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine.h>
+#include <metal/shutdown.h>
+
+extern __inline__ void __metal_shutdown_exit(const struct __metal_shutdown *sd, int code);
+
+#if defined(__METAL_DT_SHUTDOWN_HANDLE)
+void metal_shutdown(int code)
+{
+ __metal_shutdown_exit(__METAL_DT_SHUTDOWN_HANDLE, code);
+}
+#else
+#pragma message("There is no defined shutdown mechanism, metal_shutdown() will spin.")
+void metal_shutdown(int code)
+{
+ while (1) {
+ __asm__ volatile ("nop");
+ }
+}
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine.h>
+#include <metal/spi.h>
+
+extern __inline__ void metal_spi_init(struct metal_spi *spi, int baud_rate);
+extern __inline__ int metal_spi_transfer(struct metal_spi *spi, struct metal_spi_config *config, size_t len, char *tx_buf, char *rx_buf);
+extern __inline__ int metal_spi_get_baud_rate(struct metal_spi *spi);
+extern __inline__ int metal_spi_set_baud_rate(struct metal_spi *spi, int baud_rate);
+
+struct metal_spi *metal_spi_get_device(unsigned int device_num)
+{
+#if __METAL_DT_MAX_SPIS > 0
+ if (device_num < __METAL_DT_MAX_SPIS) {
+ return (struct metal_spi *) __metal_spi_table[device_num];
+ }
+#endif
+
+ return NULL;
+}
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/switch.h>
+#include <metal/machine.h>
+
+struct metal_switch* metal_switch_get (char *label)
+{
+ int i;
+ struct metal_switch *flip;
+
+ if ((__METAL_DT_MAX_BUTTONS == 0) || (label == NULL)) {
+ return NULL;
+ }
+
+ for (i = 0; i < __METAL_DT_MAX_BUTTONS; i++) {
+ flip = (struct metal_switch*)__metal_switch_table[i];
+ if (flip->vtable->switch_exist(flip, label)) {
+ return flip;
+ }
+ }
+ return NULL;
+}
+
+extern __inline__ struct metal_interrupt*
+ metal_switch_interrupt_controller(struct metal_switch *flip);
+extern __inline__ int metal_switch_get_interrupt_id(struct metal_switch *flip);
--- /dev/null
+/* 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.
+ */
+__attribute__((section(".init")))
+void __metal_synchronize_harts() {
+#if __METAL_DT_MAX_HARTS > 1
+
+ int hart;
+ __asm__ volatile("csrr %0, mhartid" : "=r" (hart) ::);
+
+ 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
+#pragma message(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 */
+}
+
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/time.h>
+#include <metal/timer.h>
+
+int metal_gettimeofday(struct timeval *tp, void *tzp)
+{
+ int rv;
+ unsigned long long mcc, timebase;
+ if ((rv = metal_timer_get_cyclecount(0, &mcc))) {
+ return -1;
+ }
+ if ((rv = metal_timer_get_timebase_frequency(0, &timebase))) {
+ return -1;
+ }
+ tp->tv_sec = mcc / timebase;
+ tp->tv_usec = mcc % timebase * 1000000 / timebase;
+ return 0;
+}
+
+time_t metal_time (void)
+{
+ struct timeval now;
+
+ if (metal_gettimeofday(&now, NULL) < 0)
+ now.tv_sec = (time_t) -1;
+
+ return now.tv_sec;
+}
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <sys/time.h>
+#include <sys/times.h>
+#include <metal/cpu.h>
+#include <metal/timer.h>
+#include <metal/machine.h>
+
+#if defined(__METAL_DT_MAX_HARTS)
+/* This implementation serves as a small shim that interfaces with the first
+ * timer on a system. */
+int metal_timer_get_cyclecount(int hartid, unsigned long long *mcc)
+{
+ struct metal_cpu *cpu = metal_cpu_get(hartid);
+
+ if ( cpu ) {
+ *mcc = metal_cpu_get_timer(cpu);
+ return 0;
+ }
+ return -1;
+}
+
+int metal_timer_get_timebase_frequency(int hartid, unsigned long long *timebase)
+{
+ struct metal_cpu *cpu = metal_cpu_get(hartid);
+
+ if ( cpu ) {
+ *timebase = metal_cpu_get_timebase(cpu);
+ return 0;
+ }
+ return -1;
+}
+
+int metal_timer_get_machine_time(int hartid)
+{
+ struct metal_cpu *cpu = metal_cpu_get(hartid);
+
+ if ( cpu ) {
+ return metal_cpu_get_mtime(cpu);
+ }
+ return 0;
+}
+
+int metal_timer_set_machine_time(int hartid, unsigned long long time)
+{
+ struct metal_cpu *cpu = metal_cpu_get(hartid);
+
+ if ( cpu ) {
+ return metal_cpu_set_mtimecmp(cpu, time);
+ }
+ return -1;
+}
+
+#else
+
+/* This implementation of gettimeofday doesn't actually do anything, it's just there to
+ * provide a shim and return 0 so we can ensure that everything can link to _gettimeofday.
+ */
+int nop_cyclecount(int id, unsigned long long *c) __attribute__((section(".text.metal.nop.cyclecount")));
+int nop_cyclecount(int id, unsigned long long *c) { return -1; }
+int nop_timebase(unsigned long long *t) __attribute__((section(".text.metal.nop.timebase")));
+int nop_timebase(unsigned long long *t) { return -1; }
+int nop_tick(int second) __attribute__((section(".text.metal.nop.tick")));
+int nop_tick(int second) { return -1; }
+int metal_timer_get_cyclecount(int hartid, unsigned long long *c) __attribute__((weak, alias("nop_cyclecount")))
+{
+#pragma message("There is no default timer device, metal_timer_get_cyclecount() will always return cyclecount -1.")
+}
+int metal_timer_get_timebase_frequency(unsigned long long *t) __attribute__((weak, alias("nop_timebase")))
+{
+#pragma message("There is no default timer device, metal_timer_get_timebase_frequency() will always return timebase -1.")
+}
+int metal_timer_set_tick(int second) __attribute__((weak, alias("nop_tick")))
+{
+#pragma message("There is no default timer device, metal_timer_set_tick) will always return -1.")
+}
+
+#endif
+
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#define METAL_MSTATUS_MIE_SHIFT 8
+#define METAL_MSTATUS_MPP_M 3
+#define METAL_MSTATUS_MPP_SHIFT 11
+
+#define METAL_MTVEC_MODE_MASK 3
+
+/* void _metal_trap(int ecode)
+ *
+ * Trigger a machine-mode trap with exception code ecode
+ */
+.global _metal_trap
+.type _metal_trap, @function
+
+_metal_trap:
+
+ /* Store the instruction which called _metal_trap in mepc */
+ addi t0, ra, -1
+ csrw mepc, t0
+
+ /* Set mcause to the desired exception code */
+ csrw mcause, a0
+
+ /* Read mstatus */
+ csrr t0, mstatus
+
+ /* Set MIE=0 */
+ li t1, -1
+ xori t1, t1, METAL_MSTATUS_MIE_SHIFT
+ and t0, t0, t1
+
+ /* Set MPP=M */
+ li t1, METAL_MSTATUS_MPP_M
+ slli t1, t1, METAL_MSTATUS_MPP_SHIFT
+ or t0, t0, t1
+
+ /* Write mstatus */
+ csrw mstatus, t0
+
+ /* Read mtvec */
+ csrr t0, mtvec
+
+ /*
+ * Mask the mtvec MODE bits
+ * Exceptions always jump to mtvec.BASE regradless of the vectoring mode.
+ */
+ andi t0, t0, METAL_MTVEC_MODE_MASK
+
+ /* Jump to mtvec */
+ jr t0
+
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/uart.h>
+#include <metal/tty.h>
+#include <metal/machine.h>
+
+#if defined(__METAL_DT_STDOUT_UART_HANDLE)
+/* This implementation serves as a small shim that interfaces with the first
+ * UART on a system. */
+int metal_tty_putc(int c)
+{
+ if (c == '\n') {
+ metal_tty_putc_raw( '\r' );
+ }
+ return metal_tty_putc_raw( c );
+}
+
+int metal_tty_putc_raw(int c)
+{
+ return metal_uart_putc(__METAL_DT_STDOUT_UART_HANDLE, c);
+}
+
+int metal_tty_getc(int *c)
+{
+ do {
+ metal_uart_getc( __METAL_DT_STDOUT_UART_HANDLE, c );
+ /* -1 means no key pressed, getc waits */
+ } while( -1 == *c )
+ ;
+ return 0;
+}
+
+#ifndef __METAL_DT_STDOUT_UART_BAUD
+#define __METAL_DT_STDOUT_UART_BAUD 115200
+#endif
+
+static void metal_tty_init(void) __attribute__((constructor));
+static void metal_tty_init(void)
+{
+ metal_uart_init(__METAL_DT_STDOUT_UART_HANDLE, __METAL_DT_STDOUT_UART_BAUD);
+}
+#else
+/* This implementation of putc doesn't actually do anything, it's just there to
+ * provide a shim that eats all the characters so we can ensure that everything
+ * can link to metal_tty_putc. */
+int nop_putc(int c) __attribute__((section(".text.metal.nop.putc")));
+int nop_putc(int c) { return -1; }
+int metal_tty_putc(int c) __attribute__((weak, alias("nop_putc")));
+#pragma message("There is no default output device, metal_tty_putc() will throw away all input.")
+#endif
--- /dev/null
+/* Copyright 2018 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/uart.h>
+
+extern __inline__ void metal_uart_init(struct metal_uart *uart, int baud_rate);
+extern __inline__ int metal_uart_putc(struct metal_uart *uart, int c);
+extern __inline__ int metal_uart_txready(struct metal_uart *uart);
+extern __inline__ int metal_uart_getc(struct metal_uart *uart, int *c);
+extern __inline__ int metal_uart_get_baud_rate(struct metal_uart *uart);
+extern __inline__ int metal_uart_set_baud_rate(struct metal_uart *uart, int baud_rate);
--- /dev/null
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+/*
+ * Jump table for CLINT vectored mode
+ */
+.weak metal_interrupt_vector_handler
+.balign 4, 0
+.global metal_interrupt_vector_handler
+
+.weak metal_software_interrupt_vector_handler
+.balign 4, 0
+.global metal_software_interrupt_vector_handler
+
+.weak metal_timer_interrupt_vector_handler
+.balign 4, 0
+.global metal_timer_interrupt_vector_handler
+
+.weak metal_external_interrupt_vector_handler
+.balign 4, 0
+.global metal_external_interrupt_vector_handler
+
+.weak metal_lc0_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc0_interrupt_vector_handler
+
+.weak metal_lc1_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc1_interrupt_vector_handler
+
+.weak metal_lc2_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc2_interrupt_vector_handler
+
+.weak metal_lc3_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc3_interrupt_vector_handler
+
+.weak metal_lc4_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc4_interrupt_vector_handler
+
+.weak metal_lc5_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc5_interrupt_vector_handler
+
+.weak metal_lc6_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc6_interrupt_vector_handler
+
+.weak metal_lc7_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc7_interrupt_vector_handler
+
+.weak metal_lc8_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc8_interrupt_vector_handler
+
+.weak metal_lc9_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc9_interrupt_vector_handler
+
+.weak metal_lc10_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc10_interrupt_vector_handler
+
+.weak metal_lc11_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc11_interrupt_vector_handler
+
+.weak metal_lc12_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc12_interrupt_vector_handler
+
+.weak metal_lc13_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc13_interrupt_vector_handler
+
+.weak metal_lc14_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc14_interrupt_vector_handler
+
+.weak metal_lc15_interrupt_vector_handler
+.balign 4, 0
+.global metal_lc15_interrupt_vector_handler
+
+#if __riscv_xlen == 32
+.balign 128, 0
+#else
+.balign 256, 0
+#endif
+.option norvc
+.global __metal_vector_table
+__metal_vector_table:
+IRQ_0:
+ j metal_interrupt_vector_handler
+IRQ_1:
+ j metal_interrupt_vector_handler
+IRQ_2:
+ j metal_interrupt_vector_handler
+IRQ_3:
+ j metal_software_interrupt_vector_handler
+IRQ_4:
+ j metal_interrupt_vector_handler
+IRQ_5:
+ j metal_interrupt_vector_handler
+IRQ_6:
+ j metal_interrupt_vector_handler
+IRQ_7:
+ j metal_timer_interrupt_vector_handler
+IRQ_8:
+ j metal_interrupt_vector_handler
+IRQ_9:
+ j metal_interrupt_vector_handler
+IRQ_10:
+ j metal_interrupt_vector_handler
+IRQ_11:
+ j metal_interrupt_vector_handler
+IRQ_12:
+ j metal_interrupt_vector_handler
+IRQ_13:
+ j metal_interrupt_vector_handler
+IRQ_14:
+ j metal_interrupt_vector_handler
+IRQ_15:
+ j metal_interrupt_vector_handler
+IRQ_LC0:
+ j metal_lc0_interrupt_vector_handler
+IRQ_LC1:
+ j metal_lc1_interrupt_vector_handler
+IRQ_LC2:
+ j metal_lc2_interrupt_vector_handler
+IRQ_LC3:
+ j metal_lc3_interrupt_vector_handler
+IRQ_LC4:
+ j metal_lc4_interrupt_vector_handler
+IRQ_LC5:
+ j metal_lc5_interrupt_vector_handler
+IRQ_LC6:
+ j metal_lc6_interrupt_vector_handler
+IRQ_LC7:
+ j metal_lc7_interrupt_vector_handler
+IRQ_LC8:
+ j metal_lc8_interrupt_vector_handler
+IRQ_LC9:
+ j metal_lc9_interrupt_vector_handler
+IRQ_LC10:
+ j metal_lc10_interrupt_vector_handler
+IRQ_LC11:
+ j metal_lc11_interrupt_vector_handler
+IRQ_LC12:
+ j metal_lc12_interrupt_vector_handler
+IRQ_LC13:
+ j metal_lc13_interrupt_vector_handler
+IRQ_LC14:
+ j metal_lc14_interrupt_vector_handler
+IRQ_LC15:
+ j metal_lc15_interrupt_vector_handler
+
+
--- /dev/null
+/*\r
+ * FreeRTOS Kernel V10.2.1\r
+ * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * http://www.FreeRTOS.org\r
+ * http://aws.amazon.com/freertos\r
+ *\r
+ * 1 tab == 4 spaces!\r
+ */\r
+\r
+ .extern ulRegTest1LoopCounter\r
+ .extern ulRegTest2LoopCounter\r
+\r
+ .global vRegTest1Implementation\r
+ .global vRegTest2Implementation\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/*\r
+ * The register check tasks are described in the comments at the top of\r
+ * main_full.c.\r
+ */\r
+\r
+.align( 4 )\r
+vRegTest1Implementation:\r
+\r
+ /* Fill the core registers with known values. */\r
+ li x5, 0x5\r
+ li x6, 0x6\r
+ li x7, 0x7\r
+ li x8, 0x8\r
+ li x9, 0x9\r
+ li x10, 0xa\r
+ li x11, 0xb\r
+ li x12, 0xc\r
+ li x13, 0xd\r
+ li x14, 0xe\r
+ li x15, 0xf\r
+ li x16, 0x10\r
+ li x17, 0x11\r
+ li x18, 0x12\r
+ li x19, 0x13\r
+ li x20, 0x14\r
+ li x21, 0x15\r
+ li x22, 0x16\r
+ li x23, 0x17\r
+ li x24, 0x18\r
+ li x25, 0x19\r
+ li x26, 0x1a\r
+ li x27, 0x1b\r
+ li x28, 0x1c\r
+ li x29, 0x1d\r
+ li x30, 0x1e\r
+\r
+reg1_loop:\r
+\r
+ /* Check each register still contains the expected known value.\r
+ vRegTest1Implementation uses x31 as the temporary, vRegTest2Implementation\r
+ uses x5 as the temporary. */\r
+ li x31, 0x5\r
+ bne x31, x5, reg1_error_loop\r
+ li x31, 0x6\r
+ bne x31, x6, reg1_error_loop\r
+ li x31, 0x7\r
+ bne x31, x7, reg1_error_loop\r
+ li x31, 0x8\r
+ bne x31, x8, reg1_error_loop\r
+ li x31, 0x9\r
+ bne x31, x9, reg1_error_loop\r
+ li x31, 0xa\r
+ bne x31, x10, reg1_error_loop\r
+ li x31, 0xb\r
+ bne x31, x11, reg1_error_loop\r
+ li x31, 0xc\r
+ bne x31, x12, reg1_error_loop\r
+ li x31, 0xd\r
+ bne x31, x13, reg1_error_loop\r
+ li x31, 0xe\r
+ bne x31, x14, reg1_error_loop\r
+ li x31, 0xf\r
+ bne x31, x15, reg1_error_loop\r
+ li x31, 0x10\r
+ bne x31, x16, reg1_error_loop\r
+ li x31, 0x11\r
+ bne x31, x17, reg1_error_loop\r
+ li x31, 0x12\r
+ bne x31, x18, reg1_error_loop\r
+ li x31, 0x13\r
+ bne x31, x19, reg1_error_loop\r
+ li x31, 0x14\r
+ bne x31, x20, reg1_error_loop\r
+ li x31, 0x15\r
+ bne x31, x21, reg1_error_loop\r
+ li x31, 0x16\r
+ bne x31, x22, reg1_error_loop\r
+ li x31, 0x17\r
+ bne x31, x23, reg1_error_loop\r
+ li x31, 0x18\r
+ bne x31, x24, reg1_error_loop\r
+ li x31, 0x19\r
+ bne x31, x25, reg1_error_loop\r
+ li x31, 0x1a\r
+ bne x31, x26, reg1_error_loop\r
+ li x31, 0x1b\r
+ bne x31, x27, reg1_error_loop\r
+ li x31, 0x1c\r
+ bne x31, x28, reg1_error_loop\r
+ li x31, 0x1d\r
+ bne x31, x29, reg1_error_loop\r
+ li x31, 0x1e\r
+ bne x31, x30, reg1_error_loop\r
+\r
+ /* Everything passed, increment the loop counter. */\r
+ lw x31, ulRegTest1LoopCounterConst\r
+ lw x30, 0(x31)\r
+ addi x30, x30, 1\r
+ sw x30, 0(x31)\r
+\r
+ /* Restore clobbered register reading for next loop. */\r
+ li x30, 0x1e\r
+\r
+ /* Yield to increase code coverage. */\r
+ ecall\r
+\r
+ /* Start again. */\r
+ jal reg1_loop\r
+\r
+reg1_error_loop:\r
+ /* Jump here if a register contains an uxpected value. This stops the loop\r
+ counter being incremented so the check task knows an error was found. */\r
+ ebreak\r
+ jal reg1_error_loop\r
+\r
+.align( 4 )\r
+ulRegTest1LoopCounterConst: .word ulRegTest1LoopCounter\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+.align( 4 )\r
+vRegTest2Implementation:\r
+\r
+ /* Fill the core registers with known values. */\r
+ li x6, 0x61\r
+ li x7, 0x71\r
+ li x8, 0x81\r
+ li x9, 0x91\r
+ li x10, 0xa1\r
+ li x11, 0xb1\r
+ li x12, 0xc1\r
+ li x13, 0xd1\r
+ li x14, 0xe1\r
+ li x15, 0xf1\r
+ li x16, 0x20\r
+ li x17, 0x21\r
+ li x18, 0x22\r
+ li x19, 0x23\r
+ li x20, 0x24\r
+ li x21, 0x25\r
+ li x22, 0x26\r
+ li x23, 0x27\r
+ li x24, 0x28\r
+ li x25, 0x29\r
+ li x26, 0x2a\r
+ li x27, 0x2b\r
+ li x28, 0x2c\r
+ li x29, 0x2d\r
+ li x30, 0x2e\r
+ li x31, 0x2f\r
+\r
+Reg2_loop:\r
+\r
+ /* Check each register still contains the expected known value.\r
+ vRegTest2Implementation uses x5 as the temporary, vRegTest1Implementation\r
+ uses x31 as the temporary. */\r
+ li x5, 0x61\r
+ bne x5, x6, reg2_error_loop\r
+ li x5, 0x71\r
+ bne x5, x7, reg2_error_loop\r
+ li x5, 0x81\r
+ bne x5, x8, reg2_error_loop\r
+ li x5, 0x91\r
+ bne x5, x9, reg2_error_loop\r
+ li x5, 0xa1\r
+ bne x5, x10, reg2_error_loop\r
+ li x5, 0xb1\r
+ bne x5, x11, reg2_error_loop\r
+ li x5, 0xc1\r
+ bne x5, x12, reg2_error_loop\r
+ li x5, 0xd1\r
+ bne x5, x13, reg2_error_loop\r
+ li x5, 0xe1\r
+ bne x5, x14, reg2_error_loop\r
+ li x5, 0xf1\r
+ bne x5, x15, reg2_error_loop\r
+ li x5, 0x20\r
+ bne x5, x16, reg2_error_loop\r
+ li x5, 0x21\r
+ bne x5, x17, reg2_error_loop\r
+ li x5, 0x22\r
+ bne x5, x18, reg2_error_loop\r
+ li x5, 0x23\r
+ bne x5, x19, reg2_error_loop\r
+ li x5, 0x24\r
+ bne x5, x20, reg2_error_loop\r
+ li x5, 0x25\r
+ bne x5, x21, reg2_error_loop\r
+ li x5, 0x26\r
+ bne x5, x22, reg2_error_loop\r
+ li x5, 0x27\r
+ bne x5, x23, reg2_error_loop\r
+ li x5, 0x28\r
+ bne x5, x24, reg2_error_loop\r
+ li x5, 0x29\r
+ bne x5, x25, reg2_error_loop\r
+ li x5, 0x2a\r
+ bne x5, x26, reg2_error_loop\r
+ li x5, 0x2b\r
+ bne x5, x27, reg2_error_loop\r
+ li x5, 0x2c\r
+ bne x5, x28, reg2_error_loop\r
+ li x5, 0x2d\r
+ bne x5, x29, reg2_error_loop\r
+ li x5, 0x2e\r
+ bne x5, x30, reg2_error_loop\r
+ li x5, 0x2f\r
+ bne x5, x31, reg2_error_loop\r
+\r
+ /* Everything passed, increment the loop counter. */\r
+ lw x5, ulRegTest2LoopCounterConst\r
+ lw x6, 0(x5)\r
+ addi x6, x6, 1\r
+ sw x6, 0(x5)\r
+\r
+ /* Restore clobbered register reading for next loop. */\r
+ li x6, 0x61\r
+\r
+ /* Start again. */\r
+ jal Reg2_loop\r
+\r
+reg2_error_loop:\r
+ /* Jump here if a register contains an uxpected value. This stops the loop\r
+ counter being incremented so the check task knows an error was found. */\r
+ ebreak\r
+ jal reg2_error_loop\r
+\r
+.align( 4 )\r
+ulRegTest2LoopCounterConst: .word ulRegTest2LoopCounter\r
+\r
+\r
--- /dev/null
+/*\r
+ * FreeRTOS Kernel V10.2.1\r
+ * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * http://www.FreeRTOS.org\r
+ * http://aws.amazon.com/freertos\r
+ *\r
+ * 1 tab == 4 spaces!\r
+ */\r
+\r
+/******************************************************************************\r
+ * NOTE 1: This project provides two demo applications. A simple blinky style\r
+ * project, and a more comprehensive test and demo application. The\r
+ * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting in main.c is used to select\r
+ * between the two. See the notes on using mainCREATE_SIMPLE_BLINKY_DEMO_ONLY\r
+ * in main.c. This file implements the comprehensive test and demo version.\r
+ *\r
+ * NOTE 2: This file only contains the source code that is specific to the\r
+ * full demo. Generic functions, such FreeRTOS hook functions, and functions\r
+ * required to configure the hardware, are defined in main.c.\r
+ *\r
+ ******************************************************************************\r
+ *\r
+ * main_full() creates all the demo application tasks and software timers, then\r
+ * starts the scheduler. The web documentation provides more details of the\r
+ * standard demo application tasks, which provide no particular functionality,\r
+ * but do provide a good example of how to use the FreeRTOS API.\r
+ *\r
+ * In addition to the standard demo tasks, the following tasks and tests are\r
+ * defined and/or created within this file:\r
+ *\r
+ * "Reg test" tasks - These fill both the core registers with known values, then\r
+ * check that each register maintains its expected value for the lifetime of the\r
+ * task. Each task uses a different set of values. The reg test tasks execute\r
+ * with a very low priority, so get preempted very frequently. A register\r
+ * containing an unexpected value is indicative of an error in the context\r
+ * switching mechanism.\r
+ *\r
+ * "Check" task - The check executes every three seconds. It checks that all\r
+ * the standard demo tasks, and the register check tasks, are not only still\r
+ * executing, but are executing without reporting any errors. The check task\r
+ * toggles the LED every three seconds if all the standard demo tasks are\r
+ * executing as expected, or every 500ms if a potential error is discovered in\r
+ * any task.\r
+ */\r
+\r
+/* Standard includes. */\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <unistd.h>\r
+\r
+/* Kernel includes. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+#include "timers.h"\r
+#include "semphr.h"\r
+\r
+/* Standard demo application includes. */\r
+#include "dynamic.h"\r
+#include "blocktim.h"\r
+#include "TimerDemo.h"\r
+#include "TaskNotify.h"\r
+\r
+/* Priorities for the demo application tasks. */\r
+#define mainCHECK_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )\r
+\r
+/* The period of the check task, in ms, converted to ticks using the\r
+pdMS_TO_TICKS() macro. mainNO_ERROR_CHECK_TASK_PERIOD is used if no errors have\r
+been found, mainERROR_CHECK_TASK_PERIOD is used if an error has been found. */\r
+#define mainNO_ERROR_CHECK_TASK_PERIOD pdMS_TO_TICKS( 3000UL )\r
+#define mainERROR_CHECK_TASK_PERIOD pdMS_TO_TICKS( 500UL )\r
+\r
+/* Parameters that are passed into the register check tasks solely for the\r
+purpose of ensuring parameters are passed into tasks correctly. */\r
+#define mainREG_TEST_TASK_1_PARAMETER ( ( void * ) 0x12345678 )\r
+#define mainREG_TEST_TASK_2_PARAMETER ( ( void * ) 0x87654321 )\r
+\r
+/* The base period used by the timer test tasks. */\r
+#define mainTIMER_TEST_PERIOD ( 50 )\r
+\r
+/* The size of the stack allocated to the check task (as described in the\r
+comments at the top of this file. */\r
+#define mainCHECK_TASK_STACK_SIZE_WORDS 160\r
+\r
+/* Size of the stacks to allocated for the register check tasks. */\r
+#define mainREG_TEST_STACK_SIZE_WORDS 90\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/*\r
+ * Called by main() to run the full demo (as opposed to the blinky demo) when\r
+ * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set to 0.\r
+ */\r
+void main_full( void );\r
+\r
+/*\r
+ * The check task, as described at the top of this file.\r
+ */\r
+static void prvCheckTask( void *pvParameters );\r
+\r
+/*\r
+ * Register check tasks as described at the top of this file. The nature of\r
+ * these files necessitates that they are written in an assembly file, but the\r
+ * entry points are kept in the C file for the convenience of checking the task\r
+ * parameter.\r
+ */\r
+static void prvRegTestTaskEntry1( void *pvParameters );\r
+extern void vRegTest1Implementation( void );\r
+static void prvRegTestTaskEntry2( void *pvParameters );\r
+extern void vRegTest2Implementation( void );\r
+\r
+/*\r
+ * Tick hook used by the full demo, which includes code that interacts with\r
+ * some of the tests.\r
+ */\r
+void vFullDemoTickHook( void );\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/* The following two variables are used to communicate the status of the\r
+register check tasks to the check task. If the variables keep incrementing,\r
+then the register check tasks have not discovered any errors. If a variable\r
+stops incrementing, then an error has been found. */\r
+uint32_t ulRegTest1LoopCounter = 0UL, ulRegTest2LoopCounter = 0UL;\r
+volatile uint32_t *pulRegTest1LoopCounter = &ulRegTest1LoopCounter;\r
+volatile uint32_t *pulRegTest2LoopCounter = &ulRegTest2LoopCounter;\r
+/*-----------------------------------------------------------*/\r
+\r
+void main_full( void )\r
+{\r
+ /* Start all the other standard demo/test tasks. They have no particular\r
+ functionality, but do demonstrate how to use the FreeRTOS API and test the\r
+ kernel port. */\r
+ vCreateBlockTimeTasks();\r
+ vStartTimerDemoTask( mainTIMER_TEST_PERIOD );\r
+ vStartDynamicPriorityTasks();\r
+ vStartTaskNotifyTask();\r
+\r
+ /* Create the register check tasks, as described at the top of this file.\r
+ Use xTaskCreateStatic() to create a task using only statically allocated\r
+ memory. */\r
+ xTaskCreate( prvRegTestTaskEntry1, /* The function that implements the task. */\r
+ "Reg1", /* The name of the task. */\r
+ mainREG_TEST_STACK_SIZE_WORDS, /* Size of stack to allocate for the task - in words not bytes!. */\r
+ mainREG_TEST_TASK_1_PARAMETER, /* Parameter passed into the task. */\r
+ tskIDLE_PRIORITY, /* Priority of the task. */\r
+ NULL ); /* Can be used to pass out a handle to the created task. */\r
+ xTaskCreate( prvRegTestTaskEntry2, "Reg2", mainREG_TEST_STACK_SIZE_WORDS, mainREG_TEST_TASK_2_PARAMETER, tskIDLE_PRIORITY, NULL );\r
+\r
+ /* Create the task that performs the 'check' functionality, as described at\r
+ the top of this file. */\r
+ xTaskCreate( prvCheckTask, "Check", mainCHECK_TASK_STACK_SIZE_WORDS, NULL, mainCHECK_TASK_PRIORITY, NULL );\r
+\r
+ /* Start the scheduler. */\r
+ vTaskStartScheduler();\r
+\r
+ /* If all is well, the scheduler will now be running, and the following\r
+ line will never be reached. If the following line does execute, then\r
+ there was insufficient FreeRTOS heap memory available for the Idle and/or\r
+ timer tasks to be created. See the memory management section on the\r
+ FreeRTOS web site for more details on the FreeRTOS heap\r
+ http://www.freertos.org/a00111.html. */\r
+ for( ;; );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvCheckTask( void *pvParameters )\r
+{\r
+TickType_t xDelayPeriod = mainNO_ERROR_CHECK_TASK_PERIOD;\r
+TickType_t xLastExecutionTime;\r
+uint32_t ulLastRegTest1Value = 0, ulLastRegTest2Value = 0;\r
+char * const pcPassMessage = ".";\r
+char * pcStatusMessage = pcPassMessage;\r
+extern void vToggleLED( void );\r
+\r
+ /* Just to stop compiler warnings. */\r
+ ( void ) pvParameters;\r
+\r
+ /* Initialise xLastExecutionTime so the first call to vTaskDelayUntil()\r
+ works correctly. */\r
+ xLastExecutionTime = xTaskGetTickCount();\r
+\r
+ /* Cycle for ever, delaying then checking all the other tasks are still\r
+ operating without error. The onboard LED is toggled on each iteration.\r
+ If an error is detected then the delay period is decreased from\r
+ mainNO_ERROR_CHECK_TASK_PERIOD to mainERROR_CHECK_TASK_PERIOD. This has the\r
+ effect of increasing the rate at which the onboard LED toggles, and in so\r
+ doing gives visual feedback of the system status. */\r
+ for( ;; )\r
+ {\r
+ /* Delay until it is time to execute again. */\r
+ vTaskDelayUntil( &xLastExecutionTime, xDelayPeriod );\r
+\r
+ /* Check all the demo tasks (other than the flash tasks) to ensure\r
+ that they are all still running, and that none have detected an error. */\r
+ if( xAreDynamicPriorityTasksStillRunning() == pdFALSE )\r
+ {\r
+ pcStatusMessage = "ERROR: Dynamic priority demo/tests.\r\n";\r
+ }\r
+\r
+ if( xAreBlockTimeTestTasksStillRunning() == pdFALSE )\r
+ {\r
+ pcStatusMessage = "ERROR: Block time demo/tests.\r\n";\r
+ }\r
+\r
+ if( xAreTimerDemoTasksStillRunning( ( TickType_t ) xDelayPeriod ) == pdFALSE )\r
+ {\r
+ pcStatusMessage = "ERROR: Timer demo/tests.\r\n";\r
+ }\r
+\r
+ if( xAreTaskNotificationTasksStillRunning() == pdFALSE )\r
+ {\r
+ pcStatusMessage = "ERROR: Task notification demo/tests.\r\n";\r
+ }\r
+\r
+ /* Check that the register test 1 task is still running. */\r
+ if( ulLastRegTest1Value == ulRegTest1LoopCounter )\r
+ {\r
+ pcStatusMessage = "ERROR: Register test 1.\r\n";\r
+ }\r
+ ulLastRegTest1Value = ulRegTest1LoopCounter;\r
+\r
+ /* Check that the register test 2 task is still running. */\r
+ if( ulLastRegTest2Value == ulRegTest2LoopCounter )\r
+ {\r
+ pcStatusMessage = "ERROR: Register test 2.\r\n";\r
+ }\r
+ ulLastRegTest2Value = ulRegTest2LoopCounter;\r
+\r
+ /* Write the status message to the UART and toggle the LED to show the\r
+ system status if the UART is not connected. */\r
+ vToggleLED();\r
+\r
+ /* If an error has been found then increase the LED toggle rate by\r
+ increasing the cycle frequency. */\r
+ if( pcStatusMessage != pcPassMessage )\r
+ {\r
+ xDelayPeriod = mainERROR_CHECK_TASK_PERIOD;\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvRegTestTaskEntry1( void *pvParameters )\r
+{\r
+ /* Although the regtest task is written in assembler, its entry point is\r
+ written in C for convenience of checking the task parameter is being passed\r
+ in correctly. */\r
+ if( pvParameters == mainREG_TEST_TASK_1_PARAMETER )\r
+ {\r
+ /* Start the part of the test that is written in assembler. */\r
+ vRegTest1Implementation();\r
+ }\r
+\r
+ /* The following line will only execute if the task parameter is found to\r
+ be incorrect. The check task will detect that the regtest loop counter is\r
+ not being incremented and flag an error. */\r
+ vTaskDelete( NULL );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvRegTestTaskEntry2( void *pvParameters )\r
+{\r
+ /* Although the regtest task is written in assembler, its entry point is\r
+ written in C for convenience of checking the task parameter is being passed\r
+ in correctly. */\r
+ if( pvParameters == mainREG_TEST_TASK_2_PARAMETER )\r
+ {\r
+ /* Start the part of the test that is written in assembler. */\r
+ vRegTest2Implementation();\r
+ }\r
+\r
+ /* The following line will only execute if the task parameter is found to\r
+ be incorrect. The check task will detect that the regtest loop counter is\r
+ not being incremented and flag an error. */\r
+ vTaskDelete( NULL );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vFullDemoTickHook( void )\r
+{\r
+ /* Called from vApplicationTickHook() when the project is configured to\r
+ build the full test/demo applications. */\r
+\r
+ /* Use task notifications from an interrupt. */\r
+ xNotifyTaskFromISR();\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
--- /dev/null
+/*\r
+ * FreeRTOS Kernel V10.2.1\r
+ * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * http://www.FreeRTOS.org\r
+ * http://aws.amazon.com/freertos\r
+ *\r
+ * 1 tab == 4 spaces!\r
+ */\r
+\r
+/******************************************************************************\r
+ * This project provides two demo applications. A simple blinky style project,\r
+ * and a more comprehensive test and demo application. The\r
+ * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting (defined in this file) is used to\r
+ * select between the two. The simply blinky demo is implemented and described\r
+ * in main_blinky.c. The more comprehensive test and demo application is\r
+ * implemented and described in main_full.c.\r
+ *\r
+ * This file implements the code that is not demo specific, including the\r
+ * hardware setup and standard FreeRTOS hook functions.\r
+ *\r
+ * When running on the HiFive Rev B hardware:\r
+ * When executing correctly the blue LED will toggle every three seconds. If\r
+ * the blue LED toggles every 500ms then one of the self-monitoring test tasks\r
+ * discovered a potential issue. If the red led toggles rapidly then a hardware\r
+ * exception occurred.\r
+ *\r
+ * ENSURE TO READ THE DOCUMENTATION PAGE FOR THIS PORT AND DEMO APPLICATION ON\r
+ * THE http://www.FreeRTOS.org WEB SITE FOR FULL INFORMATION ON USING THIS DEMO\r
+ * APPLICATION, AND ITS ASSOCIATE FreeRTOS ARCHITECTURE PORT!\r
+ *\r
+ */\r
+\r
+/* FreeRTOS kernel includes. */\r
+#include <FreeRTOS.h>\r
+#include <task.h>\r
+\r
+/* Freedom metal driver includes. */\r
+#include <metal/cpu.h>\r
+#include <metal/led.h>\r
+\r
+/* Set mainCREATE_SIMPLE_BLINKY_DEMO_ONLY to one to run the simple blinky demo,\r
+or 0 to run the more comprehensive test and demo application. */\r
+#define mainCREATE_SIMPLE_BLINKY_DEMO_ONLY 0\r
+\r
+/* Index to first HART (there is only one). */\r
+#define mainHART_0 0\r
+\r
+/* Registers used to initialise the PLIC. */\r
+#define mainPLIC_PENDING_0 ( * ( ( volatile uint32_t * ) 0x0C001000UL ) )\r
+#define mainPLIC_PENDING_1 ( * ( ( volatile uint32_t * ) 0x0C001004UL ) )\r
+#define mainPLIC_ENABLE_0 ( * ( ( volatile uint32_t * ) 0x0C002000UL ) )\r
+#define mainPLIC_ENABLE_1 ( * ( ( volatile uint32_t * ) 0x0C002004UL ) )\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/*\r
+ * main_blinky() is used when mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set to 1.\r
+ * main_full() is used when mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set to 0.\r
+ */\r
+#if mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 1\r
+ extern void main_blinky( void );\r
+#else\r
+ extern void main_full( void );\r
+#endif /* #if mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 1 */\r
+\r
+/*\r
+ * Prototypes for the standard FreeRTOS callback/hook functions implemented\r
+ * within this file. See https://www.freertos.org/a00016.html\r
+ */\r
+void vApplicationMallocFailedHook( void );\r
+void vApplicationIdleHook( void );\r
+void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName );\r
+void vApplicationTickHook( void );\r
+\r
+/*\r
+ * Setup the hardware to run this demo.\r
+ */\r
+static void prvSetupHardware( void );\r
+\r
+/*\r
+ * Used by the Freedom Metal drivers.\r
+ */\r
+static struct metal_led *pxBlueLED = NULL;\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+int main( void )\r
+{\r
+ prvSetupHardware();\r
+\r
+ /* The mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting is described at the top\r
+ of this file. */\r
+ #if( mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 1 )\r
+ {\r
+ main_blinky();\r
+ }\r
+ #else\r
+ {\r
+ main_full();\r
+ }\r
+ #endif\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvSetupHardware( void )\r
+{\r
+struct metal_cpu *pxCPU;\r
+struct metal_interrupt *pxInterruptController;\r
+\r
+ /* Initialise the blue LED. */\r
+ pxBlueLED = metal_led_get_rgb( "LD0", "blue" );\r
+ configASSERT( pxBlueLED );\r
+ metal_led_enable( pxBlueLED );\r
+ metal_led_off( pxBlueLED );\r
+\r
+ /* Initialise the interrupt controller. */\r
+ pxCPU = metal_cpu_get( mainHART_0 );\r
+ configASSERT( pxCPU );\r
+ pxInterruptController = metal_cpu_interrupt_controller( pxCPU );\r
+ configASSERT( pxInterruptController );\r
+ metal_interrupt_init( pxInterruptController );\r
+\r
+ /* Set all interrupt enable bits to 0. */\r
+ mainPLIC_ENABLE_0 = 0UL;\r
+ mainPLIC_ENABLE_1 = 0UL;\r
+\r
+ /* Clear all pending interrupts. */\r
+ mainPLIC_PENDING_0 = 0UL;\r
+ mainPLIC_PENDING_1 = 0UL;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vApplicationMallocFailedHook( void )\r
+{\r
+ /* vApplicationMallocFailedHook() will only be called if\r
+ configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook\r
+ function that will get called if a call to pvPortMalloc() fails.\r
+ pvPortMalloc() is called internally by the kernel whenever a task, queue,\r
+ timer or semaphore is created. It is also called by various parts of the\r
+ demo application. If heap_1.c or heap_2.c are used, then the size of the\r
+ heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in\r
+ FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used\r
+ to query the size of free heap space that remains (although it does not\r
+ provide information on how the remaining heap might be fragmented). */\r
+ taskDISABLE_INTERRUPTS();\r
+ for( ;; );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vApplicationIdleHook( void )\r
+{\r
+ /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set\r
+ to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle\r
+ task. It is essential that code added to this hook function never attempts\r
+ to block in any way (for example, call xQueueReceive() with a block time\r
+ specified, or call vTaskDelay()). If the application makes use of the\r
+ vTaskDelete() API function (as this demo application does) then it is also\r
+ important that vApplicationIdleHook() is permitted to return to its calling\r
+ function, because it is the responsibility of the idle task to clean up\r
+ memory allocated by the kernel to any task that has since been deleted. */\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )\r
+{\r
+ ( void ) pcTaskName;\r
+ ( void ) pxTask;\r
+\r
+ /* Run time stack overflow checking is performed if\r
+ configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook\r
+ function is called if a stack overflow is detected. */\r
+ taskDISABLE_INTERRUPTS();\r
+ for( ;; );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vApplicationTickHook( void )\r
+{\r
+ /* The tests in the full demo expect some interaction with interrupts. */\r
+ #if( mainCREATE_SIMPLE_BLINKY_DEMO_ONLY != 1 )\r
+ {\r
+ extern void vFullDemoTickHook( void );\r
+ vFullDemoTickHook();\r
+ }\r
+ #endif\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vAssertCalled( void )\r
+{\r
+static struct metal_led *pxRedLED = NULL;\r
+volatile uint32_t ul;\r
+const uint32_t ulNullLoopDelay = 0x1ffffUL;\r
+\r
+ taskDISABLE_INTERRUPTS();\r
+\r
+ /* Initialise the red LED. */\r
+ pxRedLED = metal_led_get_rgb( "LD0", "red" );\r
+ configASSERT( pxRedLED );\r
+ metal_led_enable( pxRedLED );\r
+ metal_led_off( pxRedLED );\r
+\r
+ /* Flash the red LED to indicate that assert was hit - interrupts are off\r
+ here to prevent any further tick interrupts or context switches, so the\r
+ delay is implemented as a crude loop instead of a peripheral timer. */\r
+ for( ;; )\r
+ {\r
+ for( ul = 0; ul < ulNullLoopDelay; ul++ )\r
+ {\r
+ __asm volatile( "nop" );\r
+ }\r
+ metal_led_toggle( pxRedLED );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void handle_trap( void )\r
+{\r
+volatile uint32_t ulMEPC = 0UL, ulMCAUSE = 0UL, ulPLICPending0Register = 0UL, ulPLICPending1Register = 0UL;\r
+\r
+ /* Store a few register values that might be useful when determining why this\r
+ function was called. */\r
+ __asm volatile( "csrr %0, mepc" : "=r"( ulMEPC ) );\r
+ __asm volatile( "csrr %0, mcause" : "=r"( ulMCAUSE ) );\r
+ ulPLICPending0Register = mainPLIC_PENDING_0;\r
+ ulPLICPending1Register = mainPLIC_PENDING_1;\r
+\r
+ /* Prevent compiler warnings about unused variables. */\r
+ ( void ) ulPLICPending0Register;\r
+ ( void ) ulPLICPending1Register;\r
+\r
+ /* Force an assert as this function has not been implemented as the demo\r
+ does not use external interrupts. */\r
+ configASSERT( metal_cpu_get( mainHART_0 ) == 0x00 );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vToggleLED( void )\r
+{\r
+ metal_led_toggle( pxBlueLED );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void *malloc( size_t xSize )\r
+{\r
+ /* The linker script does not define a heap so artificially force an assert()\r
+ if something unexpectedly uses the C library heap. See\r
+ https://www.freertos.org/a00111.html for more information. */\r
+ configASSERT( metal_cpu_get( mainHART_0 ) == 0x00 );\r
+\r
+ /* Remove warnings about unused parameter. */\r
+ ( void ) xSize;\r
+ return NULL;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+\r
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>\r
-<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">\r
- \r
- <storageModule moduleId="org.eclipse.cdt.core.settings">\r
- \r
- <cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480">\r
- \r
- <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">\r
- \r
- <externalSettings/>\r
- \r
- <extensions>\r
- \r
- <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>\r
- \r
- <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>\r
- \r
- <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>\r
- \r
- <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>\r
- \r
- <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>\r
- \r
- <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>\r
- \r
- </extensions>\r
- \r
- </storageModule>\r
- \r
- <storageModule moduleId="cdtBuildSystem" version="4.0.0">\r
- \r
- <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">\r
- \r
- <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480." name="/" resourcePath="">\r
- \r
- <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.debug.1023181676" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.debug">\r
- \r
- <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"/>\r
- \r
- <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"/>\r
- \r
- <tool command="riscv64-unknown-elf-gcc.exe" id="cdt.managedbuild.tool.gnu.cross.c.compiler.1469975065" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler">\r
- \r
- <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"/>\r
- \r
- <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"/>\r
- \r
- <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"/>\r
- \r
- <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">\r
- \r
- <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/include}""/>\r
- \r
- <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/full_demo/Common_Demo_Tasks/include}""/>\r
- \r
- <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}}""/>\r
- \r
- <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/portable/GCC/RISC-V}""/>\r
- \r
- <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/include}""/>\r
- \r
- <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/freedom-metal}""/>\r
- \r
- <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/bsp/install/include}""/>\r
- \r
- </option>\r
- \r
- <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"/>\r
- \r
- <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"/>\r
- \r
- <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1079251302" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>\r
- \r
- </tool>\r
- \r
- <tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.420742449" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler">\r
- \r
- <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"/>\r
- \r
- <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"/>\r
- \r
- </tool>\r
- \r
- <tool command="riscv64-unknown-elf-gcc.exe" id="cdt.managedbuild.tool.gnu.cross.c.linker.558060359" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker">\r
- \r
- <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"/>\r
- \r
- <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"/>\r
- \r
- <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"/>\r
- \r
- <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"/>\r
- \r
- <inputType id="cdt.managedbuild.tool.gnu.c.linker.input.549526426" superClass="cdt.managedbuild.tool.gnu.c.linker.input">\r
- \r
- <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>\r
- \r
- <additionalInput kind="additionalinput" paths="$(LIBS)"/>\r
- \r
- </inputType>\r
- \r
- </tool>\r
- \r
- <tool id="cdt.managedbuild.tool.gnu.cross.cpp.linker.2105463183" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker"/>\r
- \r
- <tool id="cdt.managedbuild.tool.gnu.cross.archiver.424513814" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>\r
- \r
- <tool command="riscv64-unknown-elf-gcc.exe" id="cdt.managedbuild.tool.gnu.cross.assembler.825438707" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler">\r
- \r
- <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"/>\r
- \r
- <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">\r
- \r
- <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/portable/GCC/RISC-V/chip_specific_extensions/RV32I_CLINT_no_extensions}""/>\r
- \r
- </option>\r
- \r
- <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1723023894" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>\r
- \r
- </tool>\r
- \r
- </toolChain>\r
- \r
- </folderInfo>\r
- \r
- <sourceEntries>\r
- \r
- <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>\r
- \r
- </sourceEntries>\r
- \r
- </configuration>\r
- \r
- </storageModule>\r
- \r
- <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>\r
- \r
- </cconfiguration>\r
- \r
- </storageModule>\r
- \r
- <storageModule moduleId="cdtBuildSystem" version="4.0.0">\r
- \r
- <project id="RTOSDemo.cdt.managedbuild.target.gnu.cross.exe.1669036252" name="Executable" projectType="cdt.managedbuild.target.gnu.cross.exe"/>\r
- \r
- </storageModule>\r
- \r
- <storageModule moduleId="scannerConfiguration">\r
- \r
- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>\r
- \r
- <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">\r
- \r
- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>\r
- \r
- </scannerConfigBuildInfo>\r
- \r
- </storageModule>\r
- \r
- <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>\r
- \r
- <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>\r
- \r
- <storageModule moduleId="refreshScope" versionNumber="2">\r
- \r
- <configuration configurationName="Debug">\r
- \r
- <resource resourceType="PROJECT" workspacePath="/RTOSDemo"/>\r
- \r
- </configuration>\r
- \r
- </storageModule>\r
- \r
-</cproject>\r
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>\r
-<projectDescription>\r
- <name>RTOSDemo</name>\r
- <comment></comment>\r
- <projects>\r
- </projects>\r
- <buildSpec>\r
- <buildCommand>\r
- <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>\r
- <triggers>clean,full,incremental,</triggers>\r
- <arguments>\r
- </arguments>\r
- </buildCommand>\r
- <buildCommand>\r
- <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>\r
- <triggers>full,incremental,</triggers>\r
- <arguments>\r
- </arguments>\r
- </buildCommand>\r
- </buildSpec>\r
- <natures>\r
- <nature>org.eclipse.cdt.core.cnature</nature>\r
- <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>\r
- <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>\r
- </natures>\r
- <linkedResources>\r
- <link>\r
- <name>FreeRTOS_Source</name>\r
- <type>2</type>\r
- <locationURI>FREERTOS_ROOT/FreeRTOS/Source</locationURI>\r
- </link>\r
- <link>\r
- <name>full_demo/Common_Demo_Tasks</name>\r
- <type>2</type>\r
- <locationURI>FREERTOS_ROOT/FreeRTOS/Demo/Common/Minimal</locationURI>\r
- </link>\r
- <link>\r
- <name>full_demo/Common_Demo_Tasks/include</name>\r
- <type>2</type>\r
- <locationURI>FREERTOS_ROOT/FreeRTOS/Demo/Common/include</locationURI>\r
- </link>\r
- </linkedResources>\r
- <filteredResources>\r
- <filter>\r
- <id>1570727806810</id>\r
- <name>FreeRTOS_Source</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-event_groups.c</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727806825</id>\r
- <name>FreeRTOS_Source</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-list.c</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727806841</id>\r
- <name>FreeRTOS_Source</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-queue.c</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727806841</id>\r
- <name>FreeRTOS_Source</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-stream_buffer.c</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727806841</id>\r
- <name>FreeRTOS_Source</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-timers.c</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727806856</id>\r
- <name>FreeRTOS_Source</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-tasks.c</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727892841</id>\r
- <name>FreeRTOS_Source/include</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-event_groups.h</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727892856</id>\r
- <name>FreeRTOS_Source/include</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-FreeRTOS.h</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727892856</id>\r
- <name>FreeRTOS_Source/include</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-message_buffer.h</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727892856</id>\r
- <name>FreeRTOS_Source/include</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-queue.h</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727892872</id>\r
- <name>FreeRTOS_Source/include</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-semphr.h</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727892872</id>\r
- <name>FreeRTOS_Source/include</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-stream_buffer.h</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727892888</id>\r
- <name>FreeRTOS_Source/include</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-task.h</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727892888</id>\r
- <name>FreeRTOS_Source/include</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-timers.h</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727962643</id>\r
- <name>FreeRTOS_Source/portable</name>\r
- <type>9</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-MemMang</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727962643</id>\r
- <name>FreeRTOS_Source/portable</name>\r
- <type>9</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-GCC</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1571005814144</id>\r
- <name>full_demo/Common_Demo_Tasks</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-TimerDemo.c</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1571005814150</id>\r
- <name>full_demo/Common_Demo_Tasks</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-blocktim.c</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1571005814159</id>\r
- <name>full_demo/Common_Demo_Tasks</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-dynamic.c</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1571005814167</id>\r
- <name>full_demo/Common_Demo_Tasks</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-TaskNotify.c</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727992991</id>\r
- <name>FreeRTOS_Source/portable/GCC</name>\r
- <type>9</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-RISC-V</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570727979500</id>\r
- <name>FreeRTOS_Source/portable/MemMang</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-heap_4.c</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1571005832815</id>\r
- <name>full_demo/Common_Demo_Tasks/include</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-TimerDemo.h</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1571005832820</id>\r
- <name>full_demo/Common_Demo_Tasks/include</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-blocktim.h</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1571005832824</id>\r
- <name>full_demo/Common_Demo_Tasks/include</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-dynamic.h</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1571005832829</id>\r
- <name>full_demo/Common_Demo_Tasks/include</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-MessageBufferDemo.h</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1571005832835</id>\r
- <name>full_demo/Common_Demo_Tasks/include</name>\r
- <type>5</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-TaskNotify.h</arguments>\r
- </matcher>\r
- </filter>\r
- <filter>\r
- <id>1570728021983</id>\r
- <name>FreeRTOS_Source/portable/GCC/RISC-V/chip_specific_extensions</name>\r
- <type>9</type>\r
- <matcher>\r
- <id>org.eclipse.ui.ide.multiFilter</id>\r
- <arguments>1.0-name-matches-false-false-RV32I_CLINT_no_extensions</arguments>\r
- </matcher>\r
- </filter>\r
- </filteredResources>\r
- <variableList>\r
- <variable>\r
- <name>FREERTOS_ROOT</name>\r
- <value>$%7BPARENT-3-PROJECT_LOC%7D</value>\r
- </variable>\r
- </variableList>\r
-</projectDescription>\r
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>\r
-<project>\r
- \r
- <configuration id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" name="Debug">\r
- \r
- <extension point="org.eclipse.cdt.core.LanguageSettingsProvider">\r
- \r
- <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>\r
- \r
- <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>\r
- \r
- <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>\r
- \r
- <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-316647897902857" 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 "${INPUTS}"" prefer-non-shared="true">\r
- \r
- <language-scope id="org.eclipse.cdt.core.gcc"/>\r
- \r
- <language-scope id="org.eclipse.cdt.core.g++"/>\r
- \r
- </provider>\r
- \r
- </extension>\r
- \r
- </configuration>\r
- \r
-</project>\r
+++ /dev/null
-/*\r
- * FreeRTOS Kernel V10.2.1\r
- * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
- * this software and associated documentation files (the "Software"), to deal in\r
- * the Software without restriction, including without limitation the rights to\r
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
- * the Software, and to permit persons to whom the Software is furnished to do so,\r
- * subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in all\r
- * copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- *\r
- * http://www.FreeRTOS.org\r
- * http://aws.amazon.com/freertos\r
- *\r
- * 1 tab == 4 spaces!\r
- */\r
-\r
-#ifndef FREERTOS_CONFIG_H\r
-#define FREERTOS_CONFIG_H\r
-\r
-/*-----------------------------------------------------------\r
- * Application specific definitions.\r
- *\r
- * These definitions should be adjusted for your particular hardware and\r
- * application requirements.\r
- *\r
- * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE\r
- * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.\r
- *\r
- * See http://www.freertos.org/a00110.html.\r
- *----------------------------------------------------------*/\r
-#define CLINT_CTRL_ADDR ( 0x02000000UL )\r
-#define configCLINT_BASE_ADDRESS CLINT_CTRL_ADDR\r
-#define configUSE_PREEMPTION 1\r
-#define configUSE_IDLE_HOOK 0\r
-#define configUSE_TICK_HOOK 1\r
-#define configCPU_CLOCK_HZ ( 32768 )\r
-#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )\r
-#define configMAX_PRIORITIES ( 7 )\r
-#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 120 ) /* Only needs to be this high as some demo tasks also use this constant. In production only the idle task would use this. */\r
-#define configTOTAL_HEAP_SIZE ( ( size_t ) 10900 )\r
-#define configMAX_TASK_NAME_LEN ( 16 )\r
-#define configUSE_TRACE_FACILITY 0\r
-#define configUSE_16_BIT_TICKS 0\r
-#define configIDLE_SHOULD_YIELD 0\r
-#define configUSE_MUTEXES 1\r
-#define configQUEUE_REGISTRY_SIZE 8\r
-#define configCHECK_FOR_STACK_OVERFLOW 2\r
-#define configUSE_RECURSIVE_MUTEXES 1\r
-#define configUSE_MALLOC_FAILED_HOOK 1\r
-#define configUSE_APPLICATION_TASK_TAG 0\r
-#define configUSE_COUNTING_SEMAPHORES 1\r
-#define configGENERATE_RUN_TIME_STATS 0\r
-#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1\r
-\r
-/* Co-routine definitions. */\r
-#define configUSE_CO_ROUTINES 0\r
-#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )\r
-\r
-/* Software timer definitions. */\r
-#define configUSE_TIMERS 1\r
-#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )\r
-#define configTIMER_QUEUE_LENGTH 8\r
-#define configTIMER_TASK_STACK_DEPTH ( 160 )\r
-\r
-/* Task priorities. Allow these to be overridden. */\r
-#ifndef uartPRIMARY_PRIORITY\r
- #define uartPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )\r
-#endif\r
-\r
-/* Set the following definitions to 1 to include the API function, or zero\r
-to exclude the API function. */\r
-#define INCLUDE_vTaskPrioritySet 1\r
-#define INCLUDE_uxTaskPriorityGet 1\r
-#define INCLUDE_vTaskDelete 1\r
-#define INCLUDE_vTaskCleanUpResources 1\r
-#define INCLUDE_vTaskSuspend 1\r
-#define INCLUDE_vTaskDelayUntil 1\r
-#define INCLUDE_vTaskDelay 1\r
-#define INCLUDE_eTaskGetState 1\r
-#define INCLUDE_xTimerPendFunctionCall 1\r
-#define INCLUDE_xTaskAbortDelay 1\r
-#define INCLUDE_xTaskGetHandle 1\r
-#define INCLUDE_xSemaphoreGetMutexHolder 1\r
-\r
-/* Normal assert() semantics without relying on the provision of an assert.h\r
-header file. */\r
-void vAssertCalled( void );\r
-#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled()\r
-\r
-#endif /* FREERTOS_CONFIG_H */\r
+++ /dev/null
-/*\r
- * FreeRTOS Kernel V10.2.1\r
- * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
- * this software and associated documentation files (the "Software"), to deal in\r
- * the Software without restriction, including without limitation the rights to\r
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
- * the Software, and to permit persons to whom the Software is furnished to do so,\r
- * subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in all\r
- * copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- *\r
- * http://www.FreeRTOS.org\r
- * http://aws.amazon.com/freertos\r
- *\r
- * 1 tab == 4 spaces!\r
- */\r
-\r
-/******************************************************************************\r
- * NOTE 1: This project provides two demo applications. A simple blinky\r
- * style project, and a more comprehensive test and demo application. The\r
- * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting in main.c is used to select\r
- * between the two. See the notes on using mainCREATE_SIMPLE_BLINKY_DEMO_ONLY\r
- * in main.c. This file implements the simply blinky style version.\r
- *\r
- * NOTE 2: This file only contains the source code that is specific to the\r
- * blinky demo. Generic functions, such FreeRTOS hook functions, and functions\r
- * required to configure the hardware are defined in main.c.\r
- ******************************************************************************\r
- *\r
- * main_blinky() creates one queue, and two tasks. It then starts the\r
- * scheduler.\r
- *\r
- * The Queue Send Task:\r
- * The queue send task is implemented by the prvQueueSendTask() function in\r
- * this file. prvQueueSendTask() sits in a loop that causes it to repeatedly\r
- * block for 1000 milliseconds, before sending the value 100 to the queue that\r
- * was created within main_blinky(). Once the value is sent, the task loops\r
- * back around to block for another 1000 milliseconds...and so on.\r
- *\r
- * The Queue Receive Task:\r
- * The queue receive task is implemented by the prvQueueReceiveTask() function\r
- * in this file. prvQueueReceiveTask() sits in a loop where it repeatedly\r
- * blocks on attempts to read data from the queue that was created within\r
- * main_blinky(). When data is received, the task checks the value of the\r
- * data, and if the value equals the expected 100, toggles an LED. The 'block\r
- * time' parameter passed to the queue receive function specifies that the task\r
- * should be held in the Blocked state indefinitely to wait for data to be\r
- * available on the queue. The queue receive task will only leave the Blocked\r
- * state when the queue send task writes to the queue. As the queue send task\r
- * writes to the queue every 1000 milliseconds, the queue receive task leaves\r
- * the Blocked state every 1000 milliseconds, and therefore toggles the LED\r
- * every 200 milliseconds.\r
- */\r
-\r
-/* Standard includes. */\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <unistd.h>\r
-\r
-/* Kernel includes. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-\r
-/* Priorities used by the tasks. */\r
-#define mainQUEUE_RECEIVE_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
-#define mainQUEUE_SEND_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
-\r
-/* The rate at which data is sent to the queue. The 200ms value is converted\r
-to ticks using the pdMS_TO_TICKS() macro. */\r
-#define mainQUEUE_SEND_FREQUENCY_MS pdMS_TO_TICKS( 1000 )\r
-\r
-/* The maximum number items the queue can hold. The priority of the receiving\r
-task is above the priority of the sending task, so the receiving task will\r
-preempt the sending task and remove the queue items each time the sending task\r
-writes to the queue. Therefore the queue will never have more than one item in\r
-it at any time, and even with a queue length of 1, the sending task will never\r
-find the queue full. */\r
-#define mainQUEUE_LENGTH ( 1 )\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Called by main when mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set to 1 in\r
- * main.c.\r
- */\r
-void main_blinky( void );\r
-\r
-/*\r
- * The tasks as described in the comments at the top of this file.\r
- */\r
-static void prvQueueReceiveTask( void *pvParameters );\r
-static void prvQueueSendTask( void *pvParameters );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* The queue used by both tasks. */\r
-static QueueHandle_t xQueue = NULL;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void main_blinky( void )\r
-{\r
- /* Create the queue. */\r
- xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( uint32_t ) );\r
-\r
- if( xQueue != NULL )\r
- {\r
- /* Start the two tasks as described in the comments at the top of this\r
- file. */\r
- xTaskCreate( prvQueueReceiveTask, /* The function that implements the task. */\r
- "Rx", /* The text name assigned to the task - for debug only as it is not used by the kernel. */\r
- configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */\r
- NULL, /* The parameter passed to the task - not used in this case. */\r
- mainQUEUE_RECEIVE_TASK_PRIORITY, /* The priority assigned to the task. */\r
- NULL ); /* The task handle is not required, so NULL is passed. */\r
-\r
- xTaskCreate( prvQueueSendTask, "TX", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL );\r
-\r
- /* Start the tasks and timer running. */\r
- vTaskStartScheduler();\r
- }\r
-\r
- /* If all is well, the scheduler will now be running, and the following\r
- line will never be reached. If the following line does execute, then\r
- there was insufficient FreeRTOS heap memory available for the Idle and/or\r
- timer tasks to be created. See the memory management section on the\r
- FreeRTOS web site for more details on the FreeRTOS heap\r
- http://www.freertos.org/a00111.html. */\r
- for( ;; );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvQueueSendTask( void *pvParameters )\r
-{\r
-TickType_t xNextWakeTime;\r
-const unsigned long ulValueToSend = 100UL;\r
-BaseType_t xReturned;\r
-\r
- /* Remove compiler warning about unused parameter. */\r
- ( void ) pvParameters;\r
-\r
- /* Initialise xNextWakeTime - this only needs to be done once. */\r
- xNextWakeTime = xTaskGetTickCount();\r
-\r
- for( ;; )\r
- {\r
- /* Place this task in the blocked state until it is time to run again. */\r
- vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS );\r
-\r
- /* Send to the queue - causing the queue receive task to unblock and\r
- toggle the LED. 0 is used as the block time so the sending operation\r
- will not block - it shouldn't need to block as the queue should always\r
- be empty at this point in the code. */\r
- xReturned = xQueueSend( xQueue, &ulValueToSend, 0U );\r
- configASSERT( xReturned == pdPASS );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvQueueReceiveTask( void *pvParameters )\r
-{\r
-unsigned long ulReceivedValue;\r
-const unsigned long ulExpectedValue = 100UL;\r
-extern void vToggleLED( void );\r
-\r
- /* Remove compiler warning about unused parameter. */\r
- ( void ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /* Wait until something arrives in the queue - this task will block\r
- indefinitely provided INCLUDE_vTaskSuspend is set to 1 in\r
- FreeRTOSConfig.h. */\r
- xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY );\r
-\r
- /* To get here something must have been received from the queue, but\r
- is it the expected value? If it is, toggle the LED. */\r
- if( ulReceivedValue == ulExpectedValue )\r
- {\r
- vToggleLED();\r
- ulReceivedValue = 0U;\r
- }\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
+++ /dev/null
-/dts-v1/;
-
-/ {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "sifive,hifive1-revb";
- model = "sifive,hifive1-revb";
-
- chosen {
- 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";
- };
- };
-};
+++ /dev/null
-zero
-ra
-sp
-gp
-tp
-t0
-t1
-t2
-fp
-s1
-a0
-a1
-a2
-a3
-a4
-a5
-a6
-a7
-s2
-s3
-s4
-s5
-s6
-s7
-s8
-s9
-s10
-s11
-t3
-t4
-t5
-t6
-pc
-mstatus
-misa
-mie
-mtvec
-mscratch
-mepc
-mcause
-mtval
-mip
-mvendorid
-marchid
-mimpid
-mhartid
-tselect
-tdata1
-tdata2
-tdata3
-dcsr
-dpc
-dscratch
-priv
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__BUTTON_H
-#define METAL__BUTTON_H
-
-/*!
- * @file button.h
- * API for interfacing with physical buttons
- */
-
-#include <metal/interrupt.h>
-
-struct metal_button;
-
-struct metal_button_vtable {
- int (*button_exist)(struct metal_button *button, char *label);
- struct metal_interrupt* (*interrupt_controller)(struct metal_button *button);
- int (*get_interrupt_id)(struct metal_button *button);
-};
-
-/*!
- * @brief A button device handle
- *
- * A `struct metal_button` is an implementation-defined object which represents
- * a button on a development board.
- */
-struct metal_button {
- const struct metal_button_vtable *vtable;
-};
-
-/*!
- * @brief Get a reference to a button
- *
- * @param label The DeviceTree label for the button
- * @return A handle for the button
- */
-struct metal_button* metal_button_get(char *label);
-
-
-/*!
- * @brief Get the interrupt controller for a button
- *
- * @param button The handle for the button
- * @return A pointer to the interrupt controller responsible for handling
- * button interrupts.
- */
-inline struct metal_interrupt*
- metal_button_interrupt_controller(struct metal_button *button) { return button->vtable->interrupt_controller(button); }
-
-/*!
- * @brief Get the interrupt id for a button
- *
- * @param button The handle for the 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); }
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__CACHE_H
-#define METAL__CACHE_H
-
-/*!
- * @file cache.h
- *
- * @brief API for configuring caches
- */
-
-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
- */
-struct metal_cache {
- const struct __metal_cache_vtable *vtable;
-};
-
-/*!
- * @brief Initialize a cache
- * @param cache The handle for the cache to initialize
- * @param ways The number of ways to enable
- *
- * Initializes a cache with the requested number of ways enabled.
- */
-inline void metal_cache_init(struct metal_cache *cache, int ways) {
- return cache->vtable->init(cache, ways);
-}
-
-/*!
- * @brief Get the current number of enabled cache ways
- * @param cache The handle for the cache
- * @return The current number of enabled cache ways
- */
-inline int metal_cache_get_enabled_ways(struct metal_cache *cache) {
- return cache->vtable->get_enabled_ways(cache);
-}
-
-/*!
- * @brief Enable the requested number of cache ways
- * @param cache The handle for the cache
- * @param ways The number of ways to enabled
- * @return 0 if the ways are successfully enabled
- */
-inline int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways) {
- return cache->vtable->set_enabled_ways(cache, ways);
-}
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__CLOCK_H
-#define METAL__CLOCK_H
-
-/*!
- * @file clock.h
- * @brief API for manipulating clock sources
- *
- * The clock interface allows for controlling the rate of various clocks in the system.
- */
-
-struct metal_clock;
-
-#include <stddef.h>
-
-/* The generic interface to all clocks. */
-struct __metal_clock_vtable {
- long (*get_rate_hz)(const struct metal_clock *clk);
- long (*set_rate_hz)(struct metal_clock *clk, long hz);
-};
-
-/*!
- * @brief Function signature of clock pre-rate change callbacks
- */
-typedef void (*metal_clock_pre_rate_change_callback)(void *priv);
-
-/*!
- * @brief Function signature of clock post-rate change callbacks
- */
-typedef void (*metal_clock_post_rate_change_callback)(void *priv);
-
-/*!
- * @struct metal_clock
- * @brief The handle for a clock
- *
- * Clocks are defined as a pointer to a `struct metal_clock`, the contents of which
- * are implementation defined. Users of the clock interface must call 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
- * defined, making it impossible to call any of these functions without invoking
- * implementation-defined behavior.
- */
-struct metal_clock {
- const struct __metal_clock_vtable *vtable;
-
- /* Pre-rate change callback */
- metal_clock_pre_rate_change_callback _pre_rate_change_callback;
- void *_pre_rate_change_callback_priv;
-
- /* Post-rate change callback */
- metal_clock_post_rate_change_callback _post_rate_change_callback;
- void *_post_rate_change_callback_priv;
-};
-
-/*!
- * @brief Returns the current rate of the given clock
- *
- * @param clk The handle for the clock
- * @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); }
-
-/*!
- * @brief Set the current rate of a clock
- *
- * @param clk The handle for the clock
- * @param hz The desired rate in Hz
- * @return The new rate of the clock in Hz.
- *
- * Attempts to set the current rate of the given clock to as close as possible
- * to the given rate in Hz. Returns the actual value that's been selected, which
- * could be anything!
- *
- * Prior to and after the rate change of the clock, this will call the registered
- * pre- and post-rate change callbacks.
- */
-inline long metal_clock_set_rate_hz(struct metal_clock *clk, long hz)
-{
- 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);
-
- if (clk->_post_rate_change_callback != NULL)
- clk->_post_rate_change_callback(clk->_post_rate_change_callback_priv);
-
- return out;
-}
-
-/*!
- * @brief Register a callback that must be called before a rate change
- *
- * @param clk The handle for the clock
- * @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)
-{
- clk->_pre_rate_change_callback = cb;
- clk->_pre_rate_change_callback_priv = priv;
-}
-
-/*!
- * @brief Registers a callback that must be called after a rate change
- *
- * @param clk The handle for the clock
- * @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)
-{
- clk->_post_rate_change_callback = cb;
- clk->_post_rate_change_callback_priv = priv;
-}
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__COMPILER_H
-#define METAL__COMPILER_H
-
-#define __METAL_DECLARE_VTABLE(type) \
- extern const struct type type;
-
-#define __METAL_DEFINE_VTABLE(type) \
- const struct type type
-
-#define __METAL_GET_FIELD(reg, mask) \
- (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
-
-/* Set field with mask for a given value */
-#define __METAL_SET_FIELD(reg, mask, val) \
- (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
-
-void _metal_trap(int ecode);
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-
-/* SPDX-License-Identifier: Apache-2.0 */
-
-/*! @file cpu.h
- * @brief API for accessing CPU capabilities.
- */
-
-#ifndef METAL__CPU_H
-#define METAL__CPU_H
-
-#include <stdint.h>
-#include <metal/interrupt.h>
-
-struct metal_cpu;
-
-/*!
- * @brief Function signature for exception handlers
- */
-typedef void (*metal_exception_handler_t) (struct metal_cpu *cpu, int ecode);
-
-struct metal_cpu_vtable {
- unsigned long long (*timer_get)(struct metal_cpu *cpu);
- unsigned long long (*timebase_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);
- struct metal_interrupt* (*tmr_controller_interrupt)(struct metal_cpu *cpu);
- int (*get_tmr_interrupt_id)(struct metal_cpu *cpu);
- struct metal_interrupt* (*sw_controller_interrupt)(struct metal_cpu *cpu);
- int (*get_sw_interrupt_id)(struct metal_cpu *cpu);
- int (*set_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);
- struct metal_interrupt* (*controller_interrupt)(struct metal_cpu *cpu);
- int (*exception_register)(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler);
- int (*get_ilen)(struct metal_cpu *cpu, uintptr_t epc);
- uintptr_t (*get_epc)(struct metal_cpu *cpu);
- int (*set_epc)(struct metal_cpu *cpu, uintptr_t epc);
-};
-
-/*! @brief A device handle for a CPU hart
- */
-struct metal_cpu {
- const struct metal_cpu_vtable *vtable;
-};
-
-/*! @brief Get a reference to a CPU hart
- *
- * @param hartid The ID of the desired CPU hart
- * @return A pointer to the CPU device handle
- */
-struct metal_cpu* metal_cpu_get(int hartid);
-
-/*! @brief Get the hartid of the CPU hart executing this function
- *
- * @return The hartid of the current CPU hart */
-int metal_cpu_get_current_hartid();
-
-/*! @brief Get the number of CPU harts
- *
- * @return The number of CPU harts */
-int metal_cpu_get_num_harts();
-
-/*! @brief Get the CPU cycle count timer value
- *
- * Get the value of the cycle count timer for a given CPU
- *
- * @param cpu The CPU device handle
- * @return The value of the CPU cycle count timer
- */
-inline unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu)
-{ return cpu->vtable->timer_get(cpu); }
-
-/*! @brief Get the timebase of the CPU
- *
- * Get the value of the timebase of the cycle count timer
- *
- * @param cpu The CPU device handle
- * @return The value of the cycle count timer timebase
- */
-inline unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu)
-{ return cpu->vtable->timebase_get(cpu); }
-
-/*! @brief Get the value of the mtime RTC
- *
- * Get the value of the mtime real-time clock. The CPU interrupt controller
- * must be initialized before this function is called or the return value
- * will be 0.
- *
- * @param cpu The CPU device handle
- * @return The value of mtime, or 0 if failure
- */
-inline unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu)
-{ return cpu->vtable->mtime_get(cpu); }
-
-/*! @brief Set the value of the RTC mtimecmp RTC
- *
- * Set the value of the mtime real-time clock compare register. The CPU
- * interrupt controller must be initialized before this function is called
- * or the return value will be -1;
- *
- * @param cpu The CPU device handle
- * @param time The value to set the compare register to
- * @return The value of mtimecmp or -1 if error
- */
-inline int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time)
-{ return cpu->vtable->mtimecmp_set(cpu, time); }
-
-/*! @brief Get a reference to RTC timer interrupt controller
- *
- * Get a reference to the interrupt controller for the real-time clock interrupt.
- * The controller returned by this function must be initialized before any interrupts
- * are registered or enabled with it.
- *
- * @param cpu The CPU device handle
- * @return A pointer to the timer interrupt handle
- */
-inline struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu)
-{ return cpu->vtable->tmr_controller_interrupt(cpu); }
-
-/*! @brief Get the RTC timer interrupt id
- *
- * Get the interrupt ID of the real-time clock interrupt
- *
- * @param cpu The CPU device handle
- * @return The timer interrupt ID
- */
-inline int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu)
-{ return cpu->vtable->get_tmr_interrupt_id(cpu); }
-
-/*! @brief Get a reference to the software interrupt controller
- *
- * Get a reference to the interrupt controller for the software/inter-process
- * interrupt. The controller returned by this function must be initialized before
- * any interrupts are registered or enabled with it.
- *
- * @param cpu The CPU device handle
- * @return A pointer to the software interrupt handle
- */
-inline struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu)
-{ return cpu->vtable->sw_controller_interrupt(cpu); }
-
-/*! @brief Get the software interrupt id
- *
- * Get the interrupt ID for the software/inter-process interrupt
- *
- * @param cpu The CPU device handle
- * @return the software interrupt ID
- */
-inline int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu)
-{ return cpu->vtable->get_sw_interrupt_id(cpu); }
-
-/*!
- * @brief Set the inter-process interrupt for a hart
- *
- * Trigger a software/inter-process interrupt for a hart. The CPU interrupt
- * controller for the CPU handle passed to this function must be initialized
- * before this function is called.
- *
- * @param cpu The CPU device handle
- * @param hartid The CPU hart ID to be interrupted
- * @return 0 upon success
- */
-inline int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid)
-{ return cpu->vtable->set_sw_ipi(cpu, hartid); }
-
-/*!
- * @brief Clear the inter-process interrupt for a hart
- *
- * Clear the software/inter-process interrupt for a hart. The CPU interrupt
- * controller for the CPU handle passed to this function must be initialized
- * before this function is called.
- *
- * @param cpu The CPU device handle
- * @param hartid The CPU hart ID to clear
- * @return 0 upon success
- */
-inline int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid)
-{ return cpu->vtable->clear_sw_ipi(cpu, hartid); }
-
-/*!
- * @brief Get the value of MSIP for the given hart
- *
- * Get the value of the machine software interrupt pending bit for
- * the given hart. The CPU interrupt controller for the CPU handle passed
- * as argument to this function must be initialized before this function
- * is called.
- *
- * @param cpu the CPU device handle
- * @param hartid The CPU hart to read
- * @return 0 upon success
- */
-inline int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid)
-{ return cpu->vtable->get_msip(cpu, hartid); }
-
-/*!
- * @brief Get the interrupt controller for the CPU
- *
- * Get the CPU interrupt controller. The controller returned by this
- * function must be initialized before any interrupts are registered
- * or enabled and before any exception handlers are registered with
- * this CPU.
- *
- * @param cpu The CPU device handle
- * @return The handle for the CPU interrupt controller
- */
-inline struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu)
-{ return cpu->vtable->controller_interrupt(cpu); }
-
-/*!
- * @brief Register an exception handler
- *
- * Register an exception handler for the CPU. The CPU interrupt controller must be initialized
- * before this function is called.
- *
- * @param cpu The CPU device handle
- * @param ecode The exception code to register a handler for
- * @param handler Callback function for the exception handler
- * @return 0 upon success
- */
-inline int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler)
-{ return cpu->vtable->exception_register(cpu, ecode, handler); }
-
-/*!
- * @brief Get the length of an instruction in bytes
- *
- * Get the length of an instruction in bytes.
- *
- * On RISC-V platforms, this is useful for detecting whether an instruction is
- * compressed (2 bytes long) or uncompressed (4 bytes long).
- *
- * This function is useful in conjuction with `metal_cpu_get_exception_pc()`
- * and `metal_cpu_set_exception_pc()` in order to cause the exception handler to
- * return execution after the faulting instruction.
- *
- * @param cpu The CPU device handle
- * @param epc The address of the instruction to measure
- * @return the length of the instruction in bytes
- */
-inline int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
-{ return cpu->vtable->get_ilen(cpu, epc); }
-
-/*!
- * @brief Get the program counter of the current exception.
- *
- * This function must be called within an exception handler. The behavior is
- * undefined outside of an exception handler.
- *
- * @param cpu The CPU device handle
- * @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)
-{ return cpu->vtable->get_epc(cpu); }
-
-/*!
- * @brief Set the exception program counter
- *
- * This function must be called within an exception handler. The behavior
- * is undefined outside of an exception handler.
- *
- * This function can be used to cause an exception handler to return execution
- * to an address other than the one that caused the exception.
- *
- * @param cpu the CPU device handle
- * @param epc The address to set the exception program counter to
- * @return 0 upon success
- */
-inline int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc)
-{ return cpu->vtable->set_epc(cpu, epc); }
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__FIXED_CLOCK_H
-#define METAL__DRIVERS__FIXED_CLOCK_H
-
-struct __metal_driver_fixed_clock;
-
-#include <metal/compiler.h>
-#include <metal/clock.h>
-
-struct __metal_driver_vtable_fixed_clock {
- struct __metal_clock_vtable clock;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_fixed_clock)
-
-struct __metal_driver_fixed_clock {
- struct metal_clock clock;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__FIXED_FACTOR_CLOCK_H
-#define METAL__DRIVERS__FIXED_FACTOR_CLOCK_H
-
-struct __metal_driver_fixed_factor_clock;
-
-#include <metal/compiler.h>
-#include <metal/clock.h>
-
-struct __metal_driver_vtable_fixed_factor_clock {
- struct __metal_clock_vtable clock;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_fixed_factor_clock)
-
-struct __metal_driver_fixed_factor_clock {
- struct metal_clock clock;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__RISCV_CLINT0_H
-#define METAL__DRIVERS__RISCV_CLINT0_H
-
-#include <metal/compiler.h>
-#include <metal/drivers/riscv_cpu.h>
-
-struct __metal_driver_vtable_riscv_clint0 {
- struct metal_interrupt_vtable clint_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_clint0)
-
-#define __METAL_MACHINE_MACROS
-#include <metal/machine.h>
-struct __metal_driver_riscv_clint0 {
- struct metal_interrupt controller;
- int init_done;
-};
-#undef __METAL_MACHINE_MACROS
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__RISCV_CPU_H
-#define METAL__DRIVERS__RISCV_CPU_H
-
-#include <stdint.h>
-#include <metal/cpu.h>
-#include <metal/compiler.h>
-
-#define METAL_MAX_CORES 8
-#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_DEFAULT_RTC_FREQ 32768
-
-#define METAL_DISABLE 0
-#define METAL_ENABLE 1
-
-#define METAL_ISA_A_EXTENSIONS 0x0001
-#define METAL_ISA_C_EXTENSIONS 0x0004
-#define METAL_ISA_D_EXTENSIONS 0x0008
-#define METAL_ISA_E_EXTENSIONS 0x0010
-#define METAL_ISA_F_EXTENSIONS 0x0020
-#define METAL_ISA_G_EXTENSIONS 0x0040
-#define METAL_ISA_I_EXTENSIONS 0x0100
-#define METAL_ISA_M_EXTENSIONS 0x1000
-#define METAL_ISA_N_EXTENSIONS 0x2000
-#define METAL_ISA_Q_EXTENSIONS 0x10000
-#define METAL_ISA_S_EXTENSIONS 0x40000
-#define METAL_ISA_U_EXTENSIONS 0x100000
-#define METAL_ISA_V_EXTENSIONS 0x200000
-#define METAL_ISA_XL32_EXTENSIONS 0x40000000UL
-#define METAL_ISA_XL64_EXTENSIONS 0x8000000000000000UL
-#define METAL_ISA_XL128_EXTENSIONS 0xC000000000000000UL
-
-#define METAL_MTVEC_DIRECT 0x00
-#define METAL_MTVEC_VECTORED 0x01
-#define METAL_MTVEC_CLIC 0x02
-#define METAL_MTVEC_CLIC_VECTORED 0x03
-#define METAL_MTVEC_CLIC_RESERVED 0x3C
-#define METAL_MTVEC_MASK 0x3F
-#if __riscv_xlen == 32
-#define METAL_MCAUSE_INTR 0x80000000UL
-#define METAL_MCAUSE_CAUSE 0x000003FFUL
-#else
-#define METAL_MCAUSE_INTR 0x8000000000000000UL
-#define METAL_MCAUSE_CAUSE 0x00000000000003FFUL
-#endif
-#define METAL_MCAUSE_MINHV 0x40000000UL
-#define METAL_MCAUSE_MPP 0x30000000UL
-#define METAL_MCAUSE_MPIE 0x08000000UL
-#define METAL_MCAUSE_MPIL 0x00FF0000UL
-#define METAL_MSTATUS_MIE 0x00000008UL
-#define METAL_MSTATUS_MPIE 0x00000080UL
-#define METAL_MSTATUS_MPP 0x00001800UL
-#define METAL_MSTATUS_FS_INIT 0x00002000UL
-#define METAL_MSTATUS_FS_CLEAN 0x00004000UL
-#define METAL_MSTATUS_FS_DIRTY 0x00006000UL
-#define METAL_MSTATUS_MPRV 0x00020000UL
-#define METAL_MSTATUS_MXR 0x00080000UL
-#define METAL_MINTSTATUS_MIL 0xFF000000UL
-#define METAL_MINTSTATUS_SIL 0x0000FF00UL
-#define METAL_MINTSTATUS_UIL 0x000000FFUL
-
-#define METAL_LOCAL_INTR(X) (16 + X)
-#define METAL_MCAUSE_EVAL(cause) (cause & METAL_MCAUSE_INTR)
-#define METAL_INTERRUPT(cause) (METAL_MCAUSE_EVAL(cause) ? 1 : 0)
-#define METAL_EXCEPTION(cause) (METAL_MCAUSE_EVAL(cause) ? 0 : 1)
-#define METAL_SW_INTR_EXCEPTION (METAL_MCAUSE_INTR + 3)
-#define METAL_TMR_INTR_EXCEPTION (METAL_MCAUSE_INTR + 7)
-#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_RESERVE0 1
-#define METAL_LOCAL_INTR_RESERVE1 2
-#define METAL_LOCAL_INTR_RESERVE2 4
-#define METAL_LOCAL_INTERRUPT_SW 8 /* Bit3 0x008 */
-#define METAL_LOCAL_INTR_RESERVE4 16
-#define METAL_LOCAL_INTR_RESERVE5 32
-#define METAL_LOCAL_INTR_RESERVE6 64
-#define METAL_LOCAL_INTERRUPT_TMR 128 /* Bit7 0x080 */
-#define METAL_LOCAL_INTR_RESERVE8 256
-#define METAL_LOCAL_INTR_RESERVE9 512
-#define METAL_LOCAL_INTR_RESERVE10 1024
-#define METAL_LOCAL_INTERRUPT_EXT 2048 /* Bit11 0x800 */
-/* Bit12 to Bit15 are Reserved */
-#define METAL_LOCAL_INTERRUPT(X) (0x10000 << X) /* Bit16+ Start of Custom Local Interrupt */
-#define METAL_MIE_INTERRUPT METAL_MSTATUS_MIE
-
-typedef enum {
- METAL_MACHINE_PRIVILEGE_MODE,
- METAL_SUPERVISOR_PRIVILEGE_MODE,
- METAL_USER_PRIVILEGE_MODE,
-} metal_privilege_mode_e;
-
-typedef enum {
- METAL_INTERRUPT_ID_BASE,
- METAL_INTERRUPT_ID_SW = (METAL_INTERRUPT_ID_BASE + 3),
- METAL_INTERRUPT_ID_TMR = (METAL_INTERRUPT_ID_BASE + 7),
- METAL_INTERRUPT_ID_EXT = (METAL_INTERRUPT_ID_BASE + 11),
- METAL_INTERRUPT_ID_LC0 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(0)),
- METAL_INTERRUPT_ID_LC1 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(1)),
- METAL_INTERRUPT_ID_LC2 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(2)),
- METAL_INTERRUPT_ID_LC3 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(3)),
- METAL_INTERRUPT_ID_LC4 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(4)),
- METAL_INTERRUPT_ID_LC5 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(5)),
- METAL_INTERRUPT_ID_LC6 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(6)),
- METAL_INTERRUPT_ID_LC7 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(7)),
- METAL_INTERRUPT_ID_LC8 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(8)),
- METAL_INTERRUPT_ID_LC9 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(9)),
- METAL_INTERRUPT_ID_LC10 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(10)),
- METAL_INTERRUPT_ID_LC11 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(11)),
- METAL_INTERRUPT_ID_LC12 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(12)),
- METAL_INTERRUPT_ID_LC13 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(13)),
- METAL_INTERRUPT_ID_LC14 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(14)),
- METAL_INTERRUPT_ID_LC15 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(15)),
- METAL_INTERRUPT_ID_LCMX,
- METAL_INTERRUPT_ID_GL0 = METAL_INTERRUPT_ID_LCMX,
- METAL_INTERRUPT_ID_GLMX = (METAL_MCAUSE_CAUSE + 1),
-} metal_interrupt_id_e;
-
-typedef enum {
- METAL_IAM_EXCEPTION_CODE, /* Instruction address misaligned */
- METAL_IAF_EXCEPTION_CODE, /* Instruction access faultd */
- METAL_II_EXCEPTION_CODE, /* Illegal instruction */
- METAL_BREAK_EXCEPTION_CODE, /* Breakpoint */
- METAL_LAM_EXCEPTION_CODE, /* Load address misaligned */
- METAL_LAF_EXCEPTION_CODE, /* Load access fault */
- METAL_SAMOAM_EXCEPTION_CODE, /* Store/AMO address misaligned */
- METAL_SAMOAF_EXCEPTION_CODE, /* Store/AMO access fault */
- METAL_ECALL_U_EXCEPTION_CODE, /* Environment call from U-mode */
- METAL_R9_EXCEPTION_CODE, /* Reserved */
- METAL_R10_EXCEPTION_CODE, /* Reserved */
- METAL_ECALL_M_EXCEPTION_CODE, /* Environment call from M-mode */
- METAL_MAX_EXCEPTION_CODE,
-} metal_exception_code_e;
-
-typedef enum {
- METAL_TIMER_MTIME_GET = 1,
- METAL_SOFTWARE_IPI_CLEAR,
- METAL_SOFTWARE_IPI_SET,
- METAL_SOFTWARE_MSIP_GET,
- METAL_MAX_INTERRUPT_GET,
- METAL_INDEX_INTERRUPT_GET,
-} metal_interrup_cmd_e;
-
-typedef struct __metal_interrupt_data {
- long long pad : 64;
- metal_interrupt_handler_t handler;
- void *sub_int;
- void *exint_data;
-} __metal_interrupt_data;
-
-/* CPU interrupt controller */
-
-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_interrupt_vtable controller_vtable;
-};
-
-
-void __metal_interrupt_global_enable(void);
-void __metal_interrupt_global_disable(void);
-void __metal_controller_interrupt_vector(metal_vector_mode mode, void *vec_table);
-inline int __metal_controller_interrupt_is_selective_vectored (void)
-{
- 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)
-
-struct __metal_driver_riscv_cpu_intc {
- struct metal_interrupt controller;
- int init_done;
- uintptr_t metal_mtvec_table[METAL_MAX_MI];
- __metal_interrupt_data metal_int_table[METAL_MAX_MI];
- metal_exception_handler_t metal_exception_table[METAL_MAX_ME];
-};
-
-/* CPU driver*/
-struct __metal_driver_vtable_cpu {
- struct metal_cpu_vtable cpu_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_cpu)
-
-struct __metal_driver_cpu {
- struct metal_cpu cpu;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__RISCV_PLIC0_H
-#define METAL__DRIVERS__RISCV_PLIC0_H
-
-#include <metal/compiler.h>
-#include <metal/drivers/riscv_cpu.h>
-
-#define METAL_PLIC_SOURCE_MASK 0x1F
-#define METAL_PLIC_SOURCE_SHIFT 5
-#define METAL_PLIC_SOURCE_PRIORITY_SHIFT 2
-#define METAL_PLIC_SOURCE_PENDING_SHIFT 0
-
-struct __metal_driver_vtable_riscv_plic0 {
- struct metal_interrupt_vtable plic_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_plic0)
-
-#define __METAL_MACHINE_MACROS
-#include <metal/machine.h>
-struct __metal_driver_riscv_plic0 {
- struct metal_interrupt controller;
- int init_done;
- metal_interrupt_handler_t metal_exint_table[__METAL_PLIC_SUBINTERRUPTS];
- __metal_interrupt_data metal_exdata_table[__METAL_PLIC_SUBINTERRUPTS];
-};
-#undef __METAL_MACHINE_MACROS
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_CLIC0_H
-#define METAL__DRIVERS__SIFIVE_CLIC0_H
-
-#include <metal/compiler.h>
-#include <metal/drivers/riscv_cpu.h>
-
-#define METAL_CLIC_MAX_NMBITS 2
-#define METAL_CLIC_MAX_NLBITS 8
-#define METAL_CLIC_MAX_NVBITS 1
-
-#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MMODE 0x00
-#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE1 0x20
-#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE2 0x40
-#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MASK 0x60
-#define METAL_SIFIVE_CLIC0_CLICCFG_NLBITS_MASK 0x1E
-#define METAL_SIFIVE_CLIC0_CLICCFG_NVBIT_MASK 0x01
-
-#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_MAX_INTERRUPT_LEVEL ((1 << METAL_CLIC_MAX_NLBITS) - 1)
-
-struct __metal_driver_vtable_sifive_clic0 {
- struct metal_interrupt_vtable clic_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_clic0)
-
-#define __METAL_MACHINE_MACROS
-#include <metal/machine.h>
-struct __metal_driver_sifive_clic0 {
- struct metal_interrupt controller;
- int init_done;
- metal_interrupt_handler_t metal_mtvt_table[__METAL_CLIC_SUBINTERRUPTS];
- __metal_interrupt_data metal_exint_table[__METAL_CLIC_SUBINTERRUPTS];
-};
-#undef __METAL_MACHINE_MACROS
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef 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/io.h>
-
-struct __metal_driver_vtable_sifive_fe310_g000_hfrosc {
- struct __metal_clock_vtable clock;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfrosc)
-
-struct __metal_driver_sifive_fe310_g000_hfrosc {
- struct metal_clock clock;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_HFXOSC_H
-#define METAL__DRIVERS__SIFIVE_FE310_G000_HFXOSC_H
-
-#include <metal/clock.h>
-#include <metal/drivers/sifive_fe310-g000_prci.h>
-
-struct __metal_driver_vtable_sifive_fe310_g000_hfxosc {
- struct __metal_clock_vtable clock;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfxosc)
-
-struct __metal_driver_sifive_fe310_g000_hfxosc {
- struct metal_clock clock;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_PLL_H
-#define METAL__DRIVERS__SIFIVE_FE310_G000_PLL_H
-
-struct __metal_driver_sifive_fe310_g000_pll;
-
-#include <metal/clock.h>
-#include <metal/drivers/sifive_fe310-g000_prci.h>
-#include <metal/machine.h>
-
-struct __metal_driver_vtable_sifive_fe310_g000_pll {
- void (*init)(struct __metal_driver_sifive_fe310_g000_pll *pll);
- struct __metal_clock_vtable clock;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_pll)
-
-struct __metal_driver_sifive_fe310_g000_pll {
- struct metal_clock clock;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_PRCI_H
-#define METAL__DRIVERS__SIFIVE_FE310_G000_PRCI_H
-
-#include <metal/compiler.h>
-#include <metal/io.h>
-
-struct __metal_driver_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 (*set_reg)(const struct __metal_driver_sifive_fe310_g000_prci *, long offset, long value);
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci)
-
-struct __metal_driver_sifive_fe310_g000_prci {
-};
-
-#endif
-
+++ /dev/null
-/* 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
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0_H
-#define METAL__DRIVERS__SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0_H
-
-#include <metal/compiler.h>
-#include <metal/drivers/riscv_cpu.h>
-
-struct __metal_driver_vtable_sifive_global_external_interrupts0 {
- struct metal_interrupt_vtable global0_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_global_external_interrupts0)
-
-struct __metal_driver_sifive_global_external_interrupts0 {
- struct metal_interrupt irc;
- int init_done;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H
-#define METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H
-
-#include <string.h>
-#include <metal/button.h>
-#include <metal/compiler.h>
-
-struct __metal_driver_vtable_sifive_button {
- struct metal_button_vtable button_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_button)
-
-struct __metal_driver_sifive_gpio_button {
- struct metal_button button;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_GPIO_LEDS_H
-#define METAL__DRIVERS__SIFIVE_GPIO_LEDS_H
-
-#include <metal/drivers/sifive_gpio0.h>
-#include <metal/led.h>
-#include <metal/compiler.h>
-
-struct __metal_driver_vtable_sifive_led {
- struct metal_led_vtable led_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_led)
-
-struct __metal_driver_sifive_gpio_led {
- struct metal_led led;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H
-#define METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H
-
-#include <metal/drivers/sifive_gpio0.h>
-#include <metal/switch.h>
-#include <metal/compiler.h>
-
-struct __metal_driver_vtable_sifive_switch {
- struct metal_switch_vtable switch_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_switch)
-
-struct __metal_driver_sifive_gpio_switch {
- struct metal_switch flip;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_GPIO0_H
-#define METAL__DRIVERS__SIFIVE_GPIO0_H
-
-#include <metal/compiler.h>
-#include <metal/gpio.h>
-
-struct __metal_driver_vtable_sifive_gpio0 {
- const struct __metal_gpio_vtable gpio;
-};
-
-//struct __metal_driver_sifive_gpio0;
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_gpio0)
-
-struct __metal_driver_sifive_gpio0 {
- struct metal_gpio gpio;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_EXTERNAL_INTERRUPTS0_H
-#define METAL__DRIVERS__SIFIVE_EXTERNAL_INTERRUPTS0_H
-
-#include <metal/compiler.h>
-#include <metal/drivers/riscv_cpu.h>
-
-struct __metal_driver_vtable_sifive_local_external_interrupts0 {
- struct metal_interrupt_vtable local0_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_local_external_interrupts0)
-
-struct __metal_driver_sifive_local_external_interrupts0 {
- struct metal_interrupt irc;
- int init_done;
-};
-
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_SPI0_H
-#define METAL__DRIVERS__SIFIVE_SPI0_H
-
-#include <metal/drivers/sifive_gpio0.h>
-#include <metal/clock.h>
-#include <metal/compiler.h>
-#include <metal/io.h>
-#include <metal/spi.h>
-
-struct __metal_driver_vtable_sifive_spi0 {
- const struct metal_spi_vtable spi;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_spi0)
-
-struct __metal_driver_sifive_spi0 {
- struct metal_spi spi;
- unsigned long baud_rate;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_TEST0_H
-#define METAL__DRIVERS__SIFIVE_TEST0_H
-
-#include <metal/compiler.h>
-#include <metal/shutdown.h>
-
-struct __metal_driver_vtable_sifive_test0 {
- const struct __metal_shutdown_vtable shutdown;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_test0)
-
-struct __metal_driver_sifive_test0 {
- struct __metal_shutdown shutdown;
-};
-
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef 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/io.h>
-#include <metal/uart.h>
-#include <metal/compiler.h>
-
-struct __metal_driver_vtable_sifive_uart0 {
- const struct metal_uart_vtable uart;
-};
-
-struct __metal_driver_sifive_uart0;
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_uart0)
-
-struct __metal_driver_sifive_uart0 {
- struct metal_uart uart;
- unsigned long baud_rate;
-};
-
-
-#endif
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__GPIO_H
-#define METAL__GPIO_H
-
-#include <metal/compiler.h>
-
-/*!
- * @file gpio.h
- * @brief API for manipulating general-purpose input/output
- */
-
-struct metal_gpio;
-
-struct __metal_gpio_vtable {
- int (*disable_input)(struct metal_gpio *, long pins);
- long (*output)(struct metal_gpio *);
- int (*enable_output)(struct metal_gpio *, long pins);
- int (*output_set)(struct metal_gpio *, long value);
- int (*output_clear)(struct metal_gpio *, long value);
- int (*output_toggle)(struct metal_gpio *, long value);
- int (*enable_io)(struct metal_gpio *, long pins, long dest);
-};
-
-/*!
- * @struct metal_gpio
- * @brief The handle for a GPIO interface
- */
-struct metal_gpio {
- const struct __metal_gpio_vtable *vtable;
-};
-
-/*!
- * @brief Get a GPIO device handle
- * @param device_num The GPIO device 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);
-
-/*!
- * @brief Disable 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 disabled
- */
-inline int metal_gpio_disable_input(struct metal_gpio *gpio, int pin) {
- if(!gpio) {
- return 1;
- }
-
- return gpio->vtable->disable_input(gpio, (1 << pin));
-}
-
-/*!
- * @brief Enable 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 enabled
- */
-inline int metal_gpio_enable_output(struct metal_gpio *gpio, int pin) {
- if(!gpio) {
- return 1;
- }
-
- return gpio->vtable->enable_output(gpio, (1 << pin));
-}
-
-/*!
- * @brief Set the output value of a GPIO pin
- * @param gpio The handle for the GPIO interface
- * @param pin The pin number indexed from 0
- * @param value The value to set the pin to
- * @return 0 if the output is successfully set
- */
-inline int metal_gpio_set_pin(struct metal_gpio *gpio, int pin, int value) {
- if(!gpio) {
- return 1;
- }
-
- if(value == 0) {
- return gpio->vtable->output_clear(gpio, (1 << pin));
- } else {
- return gpio->vtable->output_set(gpio, (1 << pin));
- }
-}
-
-/*!
- * @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_pin(struct metal_gpio *gpio, int pin) {
- if(!gpio) {
- return 0;
- }
-
- long value = gpio->vtable->output(gpio);
-
- if(value & (1 << pin)) {
- return 1;
- } else {
- return 0;
- }
-}
-
-/*!
- * @brief Clears the value of the GPIO pin
- * @param gpio The handle for the GPIO interface
- * @param pin The pin number indexed from 0
- * @return 0 if the pin is successfully cleared
- */
-inline int metal_gpio_clear_pin(struct metal_gpio *gpio, int pin) {
- if(!gpio) {
- return 1;
- }
-
- return gpio->vtable->output_clear(gpio, (1 << pin));
-}
-
-/*!
- * @brief Toggles the value of the GPIO pin
- * @param gpio The handle for the GPIO interface
- * @param pin The pin number indexed from 0
- * @return 0 if the pin is successfully toggled
- */
-inline int metal_gpio_toggle_pin(struct metal_gpio *gpio, int pin) {
- if(!gpio) {
- return 1;
- }
-
- return gpio->vtable->output_toggle(gpio, (1 << pin));
-}
-
-/*!
- * @brief Enables and sets the pinmux for a GPIO pin
- * @param gpio The handle for the GPIO interface
- * @param pin The bitmask for the pin to enable pinmux on
- * @param io_function The IO function to set
- * @return 0 if the pinmux is successfully set
- */
-inline int metal_gpio_enable_pinmux(struct metal_gpio *gpio, int pin, int io_function) {
- if(!gpio) {
- return 1;
- }
-
- return gpio->vtable->enable_io(gpio, (1 << pin), (io_function << pin));
-}
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__INTERRUPT_H
-#define METAL__INTERRUPT_H
-
-/*! @file interrupt.h
- * @brief API for registering and manipulating interrupts
- */
-
-#include <stddef.h>
-
-/*!
- * @brief Possible mode of interrupts to operate
- */
-typedef enum metal_vector_mode_ {
- METAL_DIRECT_MODE = 0,
- METAL_VECTOR_MODE = 1,
- METAL_SELECTIVE_VECTOR_MODE = 2,
- METAL_HARDWARE_VECTOR_MODE = 3
-} metal_vector_mode;
-
-/*!
- * @brief Function signature for interrupt callback handlers
- */
-typedef void (*metal_interrupt_handler_t) (int, void *);
-
-struct metal_interrupt;
-
-struct metal_interrupt_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 (*interrupt_vector_enable)(struct metal_interrupt *controller,
- int id, metal_vector_mode mode);
- int (*interrupt_vector_disable)(struct metal_interrupt *controller, int id);
- int (*command_request)(struct metal_interrupt *controller, int cmd, void *data);
- int (*mtimecmp_set)(struct metal_interrupt *controller, int hartid, unsigned long long time);
-};
-
-/*!
- * @brief A handle for an interrupt
- */
-struct metal_interrupt {
- const struct metal_interrupt_vtable *vtable;
-};
-
-/*!
- * @brief Initialize a given interrupt controller
- *
- * Initialize a given interrupt controller. This function must be called
- * before any interrupts are registered or enabled with the handler. It
- * is invalid to initialize an interrupt controller more than once.
- *
- * @param controller The handle for the interrupt controller
- */
-inline void metal_interrupt_init(struct metal_interrupt *controller)
-{
- return controller->vtable->interrupt_init(controller);
-}
-
-
-/*!
- * @brief Register an interrupt handler
- * @param controller The handle for the interrupt controller
- * @param id The interrupt ID to register
- * @param handler The interrupt handler callback
- * @param priv_data Private data for the interrupt handler
- * @return 0 upon success
- */
-inline int metal_interrupt_register_handler(struct metal_interrupt *controller,
- int id,
- metal_interrupt_handler_t handler,
- void *priv_data)
-{
- return controller->vtable->interrupt_register(controller, id, handler, priv_data);
-}
-
-/*!
- * @brief Enable an interrupt
- * @param controller The handle for the interrupt controller
- * @param id The interrupt ID to enable
- * @return 0 upon success
- */
-inline int metal_interrupt_enable(struct metal_interrupt *controller, int id)
-{
- return controller->vtable->interrupt_enable(controller, id);
-}
-
-/*!
- * @brief Disable an interrupt
- * @param controller The handle for the interrupt controller
- * @param id The interrupt ID to disable
- * @return 0 upon success
- */
-inline int metal_interrupt_disable(struct metal_interrupt *controller, int id)
-{
- return controller->vtable->interrupt_disable(controller, id);
-}
-
-/*!
- * @brief Enable an interrupt vector
- * @param controller The handle for the interrupt controller
- * @param id The interrupt ID to enable
- * @param mode The interrupt mode type to enable
- * @return 0 upon success
- */
-inline int metal_interrupt_vector_enable(struct metal_interrupt *controller,
- int id, metal_vector_mode mode)
-{
- return controller->vtable->interrupt_vector_enable(controller, id, mode);
-}
-
-/*!
- * @brief Disable an interrupt vector
- * @param controller The handle for the interrupt controller
- * @param id The interrupt ID to disable
- * @return 0 upon success
- */
-inline int metal_interrupt_vector_disable(struct metal_interrupt *controller, int 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,
- int cmd, void *data)
-{
- return controller->vtable->command_request(controller, cmd, data);
-}
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__IO_H
-#define METAL__IO_H
-
-/* This macro enforces that the compiler will not elide the given access. */
-#define __METAL_ACCESS_ONCE(x) (*(typeof(*x) volatile *)(x))
-
-/* Allows users to specify arbitrary fences. */
-#define __METAL_IO_FENCE(pred, succ) __asm__ volatile ("fence " #pred "," #succ ::: "memory");
-
-/* Types that explicitly describe an address as being used for memory-mapped
- * IO. These should only be accessed via __METAL_ACCESS_ONCE. */
-typedef unsigned char __metal_io_u8;
-typedef unsigned short __metal_io_u16;
-typedef unsigned int __metal_io_u32;
-#if __riscv_xlen >= 64
-typedef unsigned long __metal_io_u64;
-#endif
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__ITIM_H
-#define METAL__ITIM_H
-
-/*! @file itim.h
- *
- * API for manipulating ITIM allocation
- */
-
-
-/*! @def METAL_PLACE_IN_ITIM
- * @brief Link a function into the ITIM
- *
- * Link a function into the ITIM (Instruction Tightly Integrated
- * Memory) if the ITIM is present on the target device.
- */
-#define METAL_PLACE_IN_ITIM __attribute__((section(".itim")))
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__LED_H
-#define METAL__LED_H
-
-/*!
- * @file led.h
- * @brief API for manipulating LEDs
- */
-
-struct metal_led;
-
-struct metal_led_vtable {
- int (*led_exist)(struct metal_led *led, char *label);
- void (*led_enable)(struct metal_led *led);
- void (*led_on)(struct metal_led *led);
- void (*led_off)(struct metal_led *led);
- void (*led_toggle)(struct metal_led *led);
-};
-
-/*!
- * @brief A handle for an LED
- */
-struct metal_led {
- const struct metal_led_vtable *vtable;
-};
-
-/*!
- * @brief Get a handle for an 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
- */
-struct metal_led* metal_led_get(char *label);
-
-/*!
- * @brief Get a handle for a channel of an RGB LED
- * @param label The DeviceTree label for the desired LED
- * @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
- */
-struct metal_led* metal_led_get_rgb(char *label, char *color);
-
-/*!
- * @brief Enable an LED
- * @param led The handle for the LED
- */
-inline void metal_led_enable(struct metal_led *led) { led->vtable->led_enable(led); }
-
-/*!
- * @brief Turn an LED on
- * @param led The handle for the LED
- */
-inline void metal_led_on(struct metal_led *led) { led->vtable->led_on(led); }
-
-/*!
- * @brief Turn an LED off
- * @param led The handle for the LED
- */
-inline void metal_led_off(struct metal_led *led) { led->vtable->led_off(led); }
-
-/*!
- * @brief Toggle the on/off state of an LED
- * @param led The handle for the LED
- */
-inline void metal_led_toggle(struct metal_led *led) { led->vtable->led_toggle(led); }
-
-#endif
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__LOCK_H
-#define METAL__LOCK_H
-
-#include <metal/memory.h>
-#include <metal/compiler.h>
-
-/*!
- * @file lock.h
- * @brief An API for creating and using a software lock/mutex
- */
-
-/* TODO: How can we make the exception code platform-independant? */
-#define _METAL_STORE_AMO_ACCESS_FAULT 7
-
-/*!
- * @def METAL_LOCK_DECLARE
- * @brief Declare a 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.
- */
-#define METAL_LOCK_DECLARE(name) \
- __attribute__((section(".data.locks"))) \
- struct metal_lock name
-
-/*!
- * @brief A handle for a lock
- */
-struct metal_lock {
- int _state;
-};
-
-/*!
- * @brief Initialize a lock
- * @param lock The handle for a lock
- * @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
- * will result in a Store/AMO access fault.
- */
-inline int metal_lock_init(struct metal_lock *lock) {
-#ifdef __riscv_atomic
- /* 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));
- if(!lock_mem) {
- return 1;
- }
-
- /* If the memory doesn't support atomics, report an error */
- if(!metal_memory_supports_atomics(lock_mem)) {
- return 2;
- }
-
- lock->_state = 0;
-
- return 0;
-#else
- return 3;
-#endif
-}
-
-/*!
- * @brief Take a lock
- * @param lock The handle for a lock
- * @return 0 if the lock is successfully taken
- *
- * If the lock initialization failed, attempts to take a lock will result in
- * a Store/AMO access fault.
- */
-inline int metal_lock_take(struct metal_lock *lock) {
-#ifdef __riscv_atomic
- int old = 1;
- int new = 1;
-
- while(old != 0) {
- __asm__ volatile("amoswap.w.aq %[old], %[new], (%[state])"
- : [old] "=r" (old)
- : [new] "r" (new), [state] "r" (&(lock->_state))
- : "memory");
- }
-
- return 0;
-#else
- /* Store the memory address in mtval like a normal store/amo access fault */
- __asm__ ("csrw mtval, %[state]"
- :: [state] "r" (&(lock->_state)));
-
- /* Trigger a Store/AMO access fault */
- _metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);
-
- /* If execution returns, indicate failure */
- return 1;
-#endif
-}
-
-/*!
- * @brief Give back a held lock
- * @param lock The handle for a lock
- * @return 0 if the lock is successfully given
- *
- * If the lock initialization failed, attempts to give a lock will result in
- * a Store/AMO access fault.
- */
-inline int metal_lock_give(struct metal_lock *lock) {
-#ifdef __riscv_atomic
- __asm__ volatile("amoswap.w.rl x0, x0, (%[state])"
- :: [state] "r" (&(lock->_state))
- : "memory");
-
- return 0;
-#else
- /* Store the memory address in mtval like a normal store/amo access fault */
- __asm__ ("csrw mtval, %[state]"
- :: [state] "r" (&(lock->_state)));
-
- /* Trigger a Store/AMO access fault */
- _metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);
-
- /* If execution returns, indicate failure */
- return 1;
-#endif
-}
-
-#endif /* METAL__LOCK_H */
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-/* ----------------------------------- */
-/* ----------------------------------- */
-
-#ifndef ASSEMBLY
-
-#include <metal/machine/platform.h>
-
-#ifdef __METAL_MACHINE_MACROS
-
-#ifndef MACROS_IF_SIFIVE_HIFIVE1_REVB____METAL_H
-#define MACROS_IF_SIFIVE_HIFIVE1_REVB____METAL_H
-
-#define __METAL_CLINT_NUM_PARENTS 2
-
-#ifndef __METAL_CLINT_NUM_PARENTS
-#define __METAL_CLINT_NUM_PARENTS 0
-#endif
-#define __METAL_PLIC_SUBINTERRUPTS 27
-
-#define __METAL_PLIC_NUM_PARENTS 1
-
-#ifndef __METAL_PLIC_SUBINTERRUPTS
-#define __METAL_PLIC_SUBINTERRUPTS 0
-#endif
-#ifndef __METAL_PLIC_NUM_PARENTS
-#define __METAL_PLIC_NUM_PARENTS 0
-#endif
-#ifndef __METAL_CLIC_SUBINTERRUPTS
-#define __METAL_CLIC_SUBINTERRUPTS 0
-#endif
-
-#endif /* MACROS_IF_SIFIVE_HIFIVE1_REVB____METAL_H*/
-
-#else /* ! __METAL_MACHINE_MACROS */
-
-#ifndef MACROS_ELSE_SIFIVE_HIFIVE1_REVB____METAL_H
-#define MACROS_ELSE_SIFIVE_HIFIVE1_REVB____METAL_H
-
-#define __METAL_CLINT_2000000_INTERRUPTS 2
-
-#define METAL_MAX_CLINT_INTERRUPTS 2
-
-#define __METAL_CLINT_NUM_PARENTS 2
-
-#define __METAL_INTERRUPT_CONTROLLER_C000000_INTERRUPTS 1
-
-#define __METAL_PLIC_SUBINTERRUPTS 27
-
-#define METAL_MAX_PLIC_INTERRUPTS 1
-
-#define __METAL_PLIC_NUM_PARENTS 1
-
-#define __METAL_CLIC_SUBINTERRUPTS 0
-#define METAL_MAX_CLIC_INTERRUPTS 0
-
-#define __METAL_LOCAL_EXTERNAL_INTERRUPTS_0_INTERRUPTS 16
-
-#define METAL_MAX_LOCAL_EXT_INTERRUPTS 16
-
-#define METAL_MAX_GLOBAL_EXT_INTERRUPTS 0
-
-#define __METAL_GPIO_10012000_INTERRUPTS 16
-
-#define METAL_MAX_GPIO_INTERRUPTS 16
-
-#define __METAL_SERIAL_10013000_INTERRUPTS 1
-
-#define METAL_MAX_UART_INTERRUPTS 1
-
-
-#include <metal/drivers/fixed-clock.h>
-#include <metal/memory.h>
-#include <metal/drivers/riscv_clint0.h>
-#include <metal/drivers/riscv_cpu.h>
-#include <metal/drivers/riscv_plic0.h>
-#include <metal/pmp.h>
-#include <metal/drivers/sifive_local-external-interrupts0.h>
-#include <metal/drivers/sifive_gpio0.h>
-#include <metal/drivers/sifive_gpio-leds.h>
-#include <metal/drivers/sifive_spi0.h>
-#include <metal/drivers/sifive_uart0.h>
-#include <metal/drivers/sifive_fe310-g000_hfrosc.h>
-#include <metal/drivers/sifive_fe310-g000_hfxosc.h>
-#include <metal/drivers/sifive_fe310-g000_pll.h>
-#include <metal/drivers/sifive_fe310-g000_prci.h>
-
-/* From clock@0 */
-struct __metal_driver_fixed_clock __metal_dt_clock_0;
-
-/* From clock@2 */
-struct __metal_driver_fixed_clock __metal_dt_clock_2;
-
-/* From clock@5 */
-struct __metal_driver_fixed_clock __metal_dt_clock_5;
-
-struct metal_memory __metal_dt_mem_dtim_80000000;
-
-struct metal_memory __metal_dt_mem_spi_10014000;
-
-/* From clint@2000000 */
-struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000;
-
-/* From cpu@0 */
-struct __metal_driver_cpu __metal_dt_cpu_0;
-
-struct __metal_driver_riscv_cpu_intc __metal_dt_cpu_0_interrupt_controller;
-
-/* From interrupt_controller@c000000 */
-struct __metal_driver_riscv_plic0 __metal_dt_interrupt_controller_c000000;
-
-struct metal_pmp __metal_dt_pmp;
-
-/* From local_external_interrupts_0 */
-struct __metal_driver_sifive_local_external_interrupts0 __metal_dt_local_external_interrupts_0;
-
-/* From gpio@10012000 */
-struct __metal_driver_sifive_gpio0 __metal_dt_gpio_10012000;
-
-/* From led@0red */
-struct __metal_driver_sifive_gpio_led __metal_dt_led_0red;
-
-/* From led@0green */
-struct __metal_driver_sifive_gpio_led __metal_dt_led_0green;
-
-/* From led@0blue */
-struct __metal_driver_sifive_gpio_led __metal_dt_led_0blue;
-
-/* From spi@10014000 */
-struct __metal_driver_sifive_spi0 __metal_dt_spi_10014000;
-
-/* From serial@10013000 */
-struct __metal_driver_sifive_uart0 __metal_dt_serial_10013000;
-
-/* From clock@3 */
-struct __metal_driver_sifive_fe310_g000_hfrosc __metal_dt_clock_3;
-
-/* From clock@1 */
-struct __metal_driver_sifive_fe310_g000_hfxosc __metal_dt_clock_1;
-
-/* From clock@4 */
-struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4;
-
-/* From prci@10008000 */
-struct __metal_driver_sifive_fe310_g000_prci __metal_dt_prci_10008000;
-
-
-
-/* --------------------- fixed_clock ------------ */
-static inline unsigned long __metal_driver_fixed_clock_rate(const struct metal_clock *clock)
-{
- if ((uintptr_t)clock == (uintptr_t)&__metal_dt_clock_0) {
- return METAL_FIXED_CLOCK_0_CLOCK_FREQUENCY;
- }
- else if ((uintptr_t)clock == (uintptr_t)&__metal_dt_clock_2) {
- return METAL_FIXED_CLOCK_2_CLOCK_FREQUENCY;
- }
- else if ((uintptr_t)clock == (uintptr_t)&__metal_dt_clock_5) {
- return METAL_FIXED_CLOCK_5_CLOCK_FREQUENCY;
- }
- else {
- return 0;
- }
-}
-
-
-
-/* --------------------- fixed_factor_clock ------------ */
-
-
-/* --------------------- sifive_clint0 ------------ */
-static inline unsigned long __metal_driver_sifive_clint0_control_base(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_clint_2000000) {
- return METAL_RISCV_CLINT0_2000000_BASE_ADDRESS;
- }
- else {
- return 0;
- }
-}
-
-static inline unsigned long __metal_driver_sifive_clint0_control_size(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_clint_2000000) {
- return METAL_RISCV_CLINT0_2000000_SIZE;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_clint0_num_interrupts(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_clint_2000000) {
- return METAL_MAX_CLINT_INTERRUPTS;
- }
- else {
- return 0;
- }
-}
-
-static inline struct metal_interrupt * __metal_driver_sifive_clint0_interrupt_parents(struct metal_interrupt *controller, int idx)
-{
- if (idx == 0) {
- return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
- }
- else if (idx == 1) {
- return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
- }
- else {
- return NULL;
- }
-}
-
-static inline int __metal_driver_sifive_clint0_interrupt_lines(struct metal_interrupt *controller, int idx)
-{
- if (idx == 0) {
- return 3;
- }
- else if (idx == 1) {
- return 7;
- }
- else {
- return 0;
- }
-}
-
-
-
-/* --------------------- cpu ------------ */
-static inline int __metal_driver_cpu_hartid(struct metal_cpu *cpu)
-{
- if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
- return 0;
- }
- else {
- return -1;
- }
-}
-
-static inline int __metal_driver_cpu_timebase(struct metal_cpu *cpu)
-{
- if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
- return 1000000;
- }
- else {
- return 0;
- }
-}
-
-static inline struct metal_interrupt * __metal_driver_cpu_interrupt_controller(struct metal_cpu *cpu)
-{
- if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
- return &__metal_dt_cpu_0_interrupt_controller.controller;
- }
- else {
- return NULL;
- }
-}
-
-static inline int __metal_driver_cpu_num_pmp_regions(struct metal_cpu *cpu)
-{
- if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
- return 8;
- }
- else {
- return 0;
- }
-}
-
-
-
-/* --------------------- sifive_plic0 ------------ */
-static inline unsigned long __metal_driver_sifive_plic0_control_base(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
- return METAL_RISCV_PLIC0_C000000_BASE_ADDRESS;
- }
- else {
- return 0;
- }
-}
-
-static inline unsigned long __metal_driver_sifive_plic0_control_size(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
- return METAL_RISCV_PLIC0_C000000_SIZE;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_plic0_num_interrupts(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
- return METAL_RISCV_PLIC0_C000000_RISCV_NDEV;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_plic0_max_priority(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
- return METAL_RISCV_PLIC0_C000000_RISCV_MAX_PRIORITY;
- }
- else {
- return 0;
- }
-}
-
-static inline struct metal_interrupt * __metal_driver_sifive_plic0_interrupt_parents(struct metal_interrupt *controller, int idx)
-{
- if (idx == 0) {
- return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
- }
- else if (idx == 0) {
- return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
- }
- else {
- return NULL;
- }
-}
-
-static inline int __metal_driver_sifive_plic0_interrupt_lines(struct metal_interrupt *controller, int idx)
-{
- if (idx == 0) {
- return 11;
- }
- else if (idx == 0) {
- return 11;
- }
- else {
- return 0;
- }
-}
-
-
-
-/* --------------------- sifive_clic0 ------------ */
-
-
-/* --------------------- sifive_local_external_interrupts0 ------------ */
-static inline struct metal_interrupt * __metal_driver_sifive_local_external_interrupts0_interrupt_parent(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_local_external_interrupts_0) {
- return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
- }
- else {
- return NULL;
- }
-}
-
-static inline int __metal_driver_sifive_local_external_interrupts0_num_interrupts(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_local_external_interrupts_0) {
- return METAL_MAX_LOCAL_EXT_INTERRUPTS;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_local_external_interrupts0_interrupt_lines(struct metal_interrupt *controller, int idx)
-{
- if (idx == 0) {
- return 16;
- }
- else if (idx == 1) {
- return 17;
- }
- else if (idx == 2) {
- return 18;
- }
- else if (idx == 3) {
- return 19;
- }
- else if (idx == 4) {
- return 20;
- }
- else if (idx == 5) {
- return 21;
- }
- else if (idx == 6) {
- return 22;
- }
- else if (idx == 7) {
- return 23;
- }
- else if (idx == 8) {
- return 24;
- }
- else if (idx == 9) {
- return 25;
- }
- else if (idx == 10) {
- return 26;
- }
- else if (idx == 11) {
- return 27;
- }
- else if (idx == 12) {
- return 28;
- }
- else if (idx == 13) {
- return 29;
- }
- else if (idx == 14) {
- return 30;
- }
- else if (idx == 15) {
- return 31;
- }
- else {
- return 0;
- }
-}
-
-
-
-/* --------------------- sifive_global_external_interrupts0 ------------ */
-
-
-/* --------------------- sifive_gpio0 ------------ */
-static inline unsigned long __metal_driver_sifive_gpio0_base(struct metal_gpio *gpio)
-{
- if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
- return METAL_SIFIVE_GPIO0_10012000_BASE_ADDRESS;
- }
- else {
- return 0;
- }
-}
-
-static inline unsigned long __metal_driver_sifive_gpio0_size(struct metal_gpio *gpio)
-{
- if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
- return METAL_SIFIVE_GPIO0_10012000_SIZE;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_gpio0_num_interrupts(struct metal_gpio *gpio)
-{
- if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
- return METAL_MAX_GPIO_INTERRUPTS;
- }
- else {
- return 0;
- }
-}
-
-static inline struct metal_interrupt * __metal_driver_sifive_gpio0_interrupt_parent(struct metal_gpio *gpio)
-{
- if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
- return (struct metal_interrupt *)&__metal_dt_interrupt_controller_c000000.controller;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_gpio0_interrupt_lines(struct metal_gpio *gpio, int idx)
-{
- if (((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 0)) {
- return 7;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 1))) {
- return 8;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 2))) {
- return 9;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 3))) {
- return 10;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 4))) {
- return 11;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 5))) {
- return 12;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 6))) {
- return 13;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 7))) {
- return 14;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 8))) {
- return 15;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 9))) {
- return 16;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 10))) {
- return 17;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 11))) {
- return 18;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 12))) {
- return 19;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 13))) {
- return 20;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 14))) {
- return 21;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 15))) {
- return 22;
- }
- else {
- return 0;
- }
-}
-
-
-
-/* --------------------- sifive_gpio_button ------------ */
-
-
-/* --------------------- sifive_gpio_led ------------ */
-static inline struct metal_gpio * __metal_driver_sifive_gpio_led_gpio(struct metal_led *led)
-{
- if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0red) {
- return (struct metal_gpio *)&__metal_dt_gpio_10012000;
- }
- else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0green) {
- return (struct metal_gpio *)&__metal_dt_gpio_10012000;
- }
- else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0blue) {
- return (struct metal_gpio *)&__metal_dt_gpio_10012000;
- }
- else {
- return NULL;
- }
-}
-
-static inline int __metal_driver_sifive_gpio_led_pin(struct metal_led *led)
-{
- if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0red) {
- return 22;
- }
- else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0green) {
- return 19;
- }
- else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0blue) {
- return 21;
- }
- else {
- return 0;
- }
-}
-
-static inline char * __metal_driver_sifive_gpio_led_label(struct metal_led *led)
-{
- if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0red) {
- return "LD0red";
- }
- else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0green) {
- return "LD0green";
- }
- else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0blue) {
- return "LD0blue";
- }
- else {
- return "";
- }
-}
-
-
-
-/* --------------------- sifive_gpio_switch ------------ */
-
-
-/* --------------------- sifive_spi0 ------------ */
-static inline unsigned long __metal_driver_sifive_spi0_control_base(struct metal_spi *spi)
-{
- if ((uintptr_t)spi == (uintptr_t)&__metal_dt_spi_10014000) {
- return METAL_SIFIVE_SPI0_10014000_BASE_ADDRESS;
- }
- else {
- return 0;
- }
-}
-
-static inline unsigned long __metal_driver_sifive_spi0_control_size(struct metal_spi *spi)
-{
- if ((uintptr_t)spi == (uintptr_t)&__metal_dt_spi_10014000) {
- return METAL_SIFIVE_SPI0_10014000_SIZE;
- }
- else {
- return 0;
- }
-}
-
-static inline struct metal_clock * __metal_driver_sifive_spi0_clock(struct metal_spi *spi)
-{
- return (struct metal_clock *)&__metal_dt_clock_4.clock;
-}
-
-static inline struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_spi0_pinmux(struct metal_spi *spi)
-{
- return (struct __metal_driver_sifive_gpio0 *)&__metal_dt_gpio_10012000;
-}
-
-static inline unsigned long __metal_driver_sifive_spi0_pinmux_output_selector(struct metal_spi *spi)
-{
- return 60;
-}
-
-static inline unsigned long __metal_driver_sifive_spi0_pinmux_source_selector(struct metal_spi *spi)
-{
- return 60;
-}
-
-
-
-/* --------------------- sifive_test0 ------------ */
-
-
-/* --------------------- sifive_uart0 ------------ */
-static inline unsigned long __metal_driver_sifive_uart0_control_base(struct metal_uart *uart)
-{
- if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
- return METAL_SIFIVE_UART0_10013000_BASE_ADDRESS;
- }
- else {
- return 0;
- }
-}
-
-static inline unsigned long __metal_driver_sifive_uart0_control_size(struct metal_uart *uart)
-{
- if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
- return METAL_SIFIVE_UART0_10013000_SIZE;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_uart0_num_interrupts(struct metal_uart *uart)
-{
- if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
- return METAL_MAX_UART_INTERRUPTS;
- }
- else {
- return 0;
- }
-}
-
-static inline struct metal_interrupt * __metal_driver_sifive_uart0_interrupt_parent(struct metal_uart *uart)
-{
- if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
- return (struct metal_interrupt *)&__metal_dt_interrupt_controller_c000000.controller;
- }
- else {
- return NULL;
- }
-}
-
-static inline int __metal_driver_sifive_uart0_interrupt_line(struct metal_uart *uart)
-{
- return 5;
-}
-
-static inline struct metal_clock * __metal_driver_sifive_uart0_clock(struct metal_uart *uart)
-{
- return (struct metal_clock *)&__metal_dt_clock_4.clock;
-}
-
-static inline struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_uart0_pinmux(struct metal_uart *uart)
-{
- return (struct __metal_driver_sifive_gpio0 *)&__metal_dt_gpio_10012000;
-}
-
-static inline unsigned long __metal_driver_sifive_uart0_pinmux_output_selector(struct metal_uart *uart)
-{
- return 196608;
-}
-
-static inline unsigned long __metal_driver_sifive_uart0_pinmux_source_selector(struct metal_uart *uart)
-{
- return 196608;
-}
-
-
-
-/* --------------------- sifive_fe310_g000_hfrosc ------------ */
-static inline struct metal_clock * __metal_driver_sifive_fe310_g000_hfrosc_ref(const struct metal_clock *clock)
-{
- return (struct metal_clock *)&__metal_dt_clock_2.clock;
-}
-
-static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_base(const struct metal_clock *clock)
-{
- return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
-}
-
-static inline const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_vtable(struct metal_clock *clock)
-{
- return &__metal_driver_vtable_sifive_fe310_g000_prci;
-}
-
-static inline long __metal_driver_sifive_fe310_g000_hfrosc_config_offset(const struct metal_clock *clock)
-{
- return METAL_SIFIVE_FE310_G000_PRCI_HFROSCCFG;
-}
-
-
-
-/* --------------------- sifive_fe310_g000_hfxosc ------------ */
-static inline struct metal_clock * __metal_driver_sifive_fe310_g000_hfxosc_ref(const struct metal_clock *clock)
-{
- return (struct metal_clock *)&__metal_dt_clock_0.clock;
-}
-
-static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfxosc_config_base(const struct metal_clock *clock)
-{
- return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
-}
-
-static inline long __metal_driver_sifive_fe310_g000_hfxosc_config_offset(const struct metal_clock *clock)
-{
- return METAL_SIFIVE_FE310_G000_PRCI_HFXOSCCFG;
-}
-
-
-
-/* --------------------- sifive_fe310_g000_pll ------------ */
-static inline struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllsel0(const struct metal_clock *clock)
-{
- return (struct metal_clock *)&__metal_dt_clock_3.clock;
-}
-
-static inline struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllref(const struct metal_clock *clock)
-{
- return (struct metal_clock *)&__metal_dt_clock_1.clock;
-}
-
-static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_divider_base(const struct metal_clock *clock)
-{
- return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
-}
-
-static inline long __metal_driver_sifive_fe310_g000_pll_divider_offset(const struct metal_clock *clock)
-{
- return METAL_SIFIVE_FE310_G000_PRCI_PLLOUTDIV;
-}
-
-static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_config_base( )
-{
- return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
-}
-
-static inline long __metal_driver_sifive_fe310_g000_pll_config_offset( )
-{
- return METAL_SIFIVE_FE310_G000_PRCI_PLLCFG;
-}
-
-static inline long __metal_driver_sifive_fe310_g000_pll_init_rate( )
-{
- return 16000000;
-}
-
-
-
-/* --------------------- sifive_fe310_g000_prci ------------ */
-static inline long __metal_driver_sifive_fe310_g000_prci_base( )
-{
- return METAL_SIFIVE_FE310_G000_PRCI_10008000_BASE_ADDRESS;
-}
-
-static inline long __metal_driver_sifive_fe310_g000_prci_size( )
-{
- return METAL_SIFIVE_FE310_G000_PRCI_10008000_SIZE;
-}
-
-static inline const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_prci_vtable( )
-{
- return &__metal_driver_vtable_sifive_fe310_g000_prci;
-}
-
-
-
-/* --------------------- sifive_fu540_c000_l2 ------------ */
-
-
-#define __METAL_DT_MAX_MEMORIES 2
-
-asm (".weak __metal_memory_table");
-struct metal_memory *__metal_memory_table[] = {
- &__metal_dt_mem_dtim_80000000,
- &__metal_dt_mem_spi_10014000};
-
-/* From serial@10013000 */
-#define __METAL_DT_STDOUT_UART_HANDLE (&__metal_dt_serial_10013000.uart)
-
-#define __METAL_DT_SERIAL_10013000_HANDLE (&__metal_dt_serial_10013000.uart)
-
-#define __METAL_DT_STDOUT_UART_BAUD 115200
-
-/* From clint@2000000 */
-#define __METAL_DT_RISCV_CLINT0_HANDLE (&__metal_dt_clint_2000000.controller)
-
-#define __METAL_DT_CLINT_2000000_HANDLE (&__metal_dt_clint_2000000.controller)
-
-#define __METAL_DT_MAX_HARTS 1
-
-asm (".weak __metal_cpu_table");
-struct __metal_driver_cpu *__metal_cpu_table[] = {
- &__metal_dt_cpu_0};
-
-/* From interrupt_controller@c000000 */
-#define __METAL_DT_RISCV_PLIC0_HANDLE (&__metal_dt_interrupt_controller_c000000.controller)
-
-#define __METAL_DT_INTERRUPT_CONTROLLER_C000000_HANDLE (&__metal_dt_interrupt_controller_c000000.controller)
-
-#define __METAL_DT_PMP_HANDLE (&__metal_dt_pmp)
-
-/* From local_external_interrupts_0 */
-#define __METAL_DT_SIFIVE_LOCAL_EXINTR0_HANDLE (&__metal_dt_local_external_interrupts_0.irc)
-
-#define __METAL_DT_LOCAL_EXTERNAL_INTERRUPTS_0_HANDLE (&__metal_dt_local_external_interrupts_0.irc)
-
-#define __MEE_DT_MAX_GPIOS 1
-
-asm (".weak __metal_gpio_table");
-struct __metal_driver_sifive_gpio0 *__metal_gpio_table[] = {
- &__metal_dt_gpio_10012000};
-
-#define __METAL_DT_MAX_BUTTONS 0
-
-asm (".weak __metal_button_table");
-struct __metal_driver_sifive_gpio_button *__metal_button_table[] = {
- NULL };
-#define __METAL_DT_MAX_LEDS 3
-
-asm (".weak __metal_led_table");
-struct __metal_driver_sifive_gpio_led *__metal_led_table[] = {
- &__metal_dt_led_0red,
- &__metal_dt_led_0green,
- &__metal_dt_led_0blue};
-
-#define __METAL_DT_MAX_SWITCHES 0
-
-asm (".weak __metal_switch_table");
-struct __metal_driver_sifive_gpio_switch *__metal_switch_table[] = {
- NULL };
-#define __METAL_DT_MAX_SPIS 1
-
-asm (".weak __metal_spi_table");
-struct __metal_driver_sifive_spi0 *__metal_spi_table[] = {
- &__metal_dt_spi_10014000};
-
-/* From clock@4 */
-#define __METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE (&__metal_dt_clock_4)
-
-#define __METAL_DT_CLOCK_4_HANDLE (&__metal_dt_clock_4)
-
-#endif /* MACROS_ELSE_SIFIVE_HIFIVE1_REVB____METAL_H*/
-
-#endif /* ! __METAL_MACHINE_MACROS */
-
-#endif /* ! ASSEMBLY */
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-/* ----------------------------------- */
-/* ----------------------------------- */
-
-#ifndef ASSEMBLY
-
-#ifndef SIFIVE_HIFIVE1_REVB____METAL_INLINE_H
-#define SIFIVE_HIFIVE1_REVB____METAL_INLINE_H
-
-#include <metal/machine.h>
-
-
-/* --------------------- fixed_clock ------------ */
-extern inline unsigned long __metal_driver_fixed_clock_rate(const struct metal_clock *clock);
-
-
-/* --------------------- fixed_factor_clock ------------ */
-
-
-/* --------------------- 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_size(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 int __metal_driver_sifive_clint0_interrupt_lines(struct metal_interrupt *controller, int idx);
-
-
-/* --------------------- 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 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);
-
-
-/* --------------------- 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_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_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 int __metal_driver_sifive_plic0_interrupt_lines(struct metal_interrupt *controller, int idx);
-
-
-/* --------------------- sifive_clic0 ------------ */
-
-
-/* --------------------- 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_gpio0 ------------ */
-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 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 int __metal_driver_sifive_gpio0_interrupt_lines(struct metal_gpio *gpio, int idx);
-
-
-/* --------------------- sifive_gpio_button ------------ */
-
-
-/* --------------------- sifive_gpio_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 char * __metal_driver_sifive_gpio_led_label(struct metal_led *led);
-
-
-/* --------------------- sifive_gpio_switch ------------ */
-
-
-/* --------------------- 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_size(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_source_selector(struct metal_spi *spi);
-
-
-/* --------------------- sifive_test0 ------------ */
-
-
-/* --------------------- 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_size(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 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_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_source_selector(struct metal_uart *uart);
-
-
-/* --------------------- 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_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 long __metal_driver_sifive_fe310_g000_hfrosc_config_offset(const struct metal_clock *clock);
-
-
-/* --------------------- 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_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);
-
-
-/* --------------------- 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_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 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 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( );
-
-
-/* --------------------- fe310_g000_prci ------------ */
-extern inline long __metal_driver_sifive_fe310_g000_prci_base( );
-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( );
-
-
-/* --------------------- sifive_fu540_c000_l2 ------------ */
-
-
-/* From clock@0 */
-struct __metal_driver_fixed_clock __metal_dt_clock_0 = {
- .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
-};
-
-/* From clock@2 */
-struct __metal_driver_fixed_clock __metal_dt_clock_2 = {
- .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
-};
-
-/* From clock@5 */
-struct __metal_driver_fixed_clock __metal_dt_clock_5 = {
- .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
-};
-
-struct metal_memory __metal_dt_mem_dtim_80000000 = {
- ._base_address = 2147483648UL,
- ._size = 16384UL,
- ._attrs = {
- .R = 1,
- .W = 1,
- .X = 1,
- .C = 1,
- .A = 1},
-};
-
-struct metal_memory __metal_dt_mem_spi_10014000 = {
- ._base_address = 536870912UL,
- ._size = 500000UL,
- ._attrs = {
- .R = 1,
- .W = 1,
- .X = 1,
- .C = 1,
- .A = 1},
-};
-
-/* From clint@2000000 */
-struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000 = {
- .controller.vtable = &__metal_driver_vtable_riscv_clint0.clint_vtable,
- .init_done = 0,
-};
-
-/* From cpu@0 */
-struct __metal_driver_cpu __metal_dt_cpu_0 = {
- .cpu.vtable = &__metal_driver_vtable_cpu.cpu_vtable,
-};
-
-/* From interrupt_controller */
-struct __metal_driver_riscv_cpu_intc __metal_dt_cpu_0_interrupt_controller = {
- .controller.vtable = &__metal_driver_vtable_riscv_cpu_intc.controller_vtable,
- .init_done = 0,
-};
-
-/* From interrupt_controller@c000000 */
-struct __metal_driver_riscv_plic0 __metal_dt_interrupt_controller_c000000 = {
- .controller.vtable = &__metal_driver_vtable_riscv_plic0.plic_vtable,
- .init_done = 0,
-};
-
-/* From local_external_interrupts_0 */
-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 */
-struct __metal_driver_sifive_gpio0 __metal_dt_gpio_10012000 = {
- .gpio.vtable = &__metal_driver_vtable_sifive_gpio0.gpio,
-};
-
-/* From led@0red */
-struct __metal_driver_sifive_gpio_led __metal_dt_led_0red = {
- .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
-};
-
-/* From led@0green */
-struct __metal_driver_sifive_gpio_led __metal_dt_led_0green = {
- .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
-};
-
-/* From led@0blue */
-struct __metal_driver_sifive_gpio_led __metal_dt_led_0blue = {
- .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
-};
-
-/* From spi@10014000 */
-struct __metal_driver_sifive_spi0 __metal_dt_spi_10014000 = {
- .spi.vtable = &__metal_driver_vtable_sifive_spi0.spi,
-};
-
-/* From serial@10013000 */
-struct __metal_driver_sifive_uart0 __metal_dt_serial_10013000 = {
- .uart.vtable = &__metal_driver_vtable_sifive_uart0.uart,
-};
-
-/* From clock@3 */
-struct __metal_driver_sifive_fe310_g000_hfrosc __metal_dt_clock_3 = {
- .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfrosc.clock,
-};
-
-/* From clock@1 */
-struct __metal_driver_sifive_fe310_g000_hfxosc __metal_dt_clock_1 = {
- .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfxosc.clock,
-};
-
-/* From clock@4 */
-struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4 = {
- .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_pll.clock,
-};
-
-/* From prci@10008000 */
-struct __metal_driver_sifive_fe310_g000_prci __metal_dt_prci_10008000 = {
-};
-
-
-#endif /* SIFIVE_HIFIVE1_REVB____METAL_INLINE_H*/
-#endif /* ! ASSEMBLY */
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-/* ----------------------------------- */
-/* ----------------------------------- */
-
-#ifndef SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H
-#define SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H
-
-/* From clock@0 */
-#define METAL_FIXED_CLOCK_0_CLOCK_FREQUENCY 16000000UL
-
-/* From clock@2 */
-#define METAL_FIXED_CLOCK_2_CLOCK_FREQUENCY 72000000UL
-
-/* From clock@5 */
-#define METAL_FIXED_CLOCK_5_CLOCK_FREQUENCY 32000000UL
-
-#define METAL_FIXED_CLOCK
-
-/* From clint@2000000 */
-#define METAL_RISCV_CLINT0_2000000_BASE_ADDRESS 33554432UL
-#define METAL_RISCV_CLINT0_0_BASE_ADDRESS 33554432UL
-#define METAL_RISCV_CLINT0_2000000_SIZE 65536UL
-#define METAL_RISCV_CLINT0_0_SIZE 65536UL
-
-#define METAL_RISCV_CLINT0
-#define METAL_RISCV_CLINT0_MSIP_BASE 0UL
-#define METAL_RISCV_CLINT0_MTIMECMP_BASE 16384UL
-#define METAL_RISCV_CLINT0_MTIME 49144UL
-
-/* From interrupt_controller@c000000 */
-#define METAL_RISCV_PLIC0_C000000_BASE_ADDRESS 201326592UL
-#define METAL_RISCV_PLIC0_0_BASE_ADDRESS 201326592UL
-#define METAL_RISCV_PLIC0_C000000_SIZE 67108864UL
-#define METAL_RISCV_PLIC0_0_SIZE 67108864UL
-#define METAL_RISCV_PLIC0_C000000_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_0_RISCV_NDEV 27UL
-
-#define METAL_RISCV_PLIC0
-#define METAL_RISCV_PLIC0_PRIORITY_BASE 0UL
-#define METAL_RISCV_PLIC0_PENDING_BASE 4096UL
-#define METAL_RISCV_PLIC0_ENABLE_BASE 8192UL
-#define METAL_RISCV_PLIC0_THRESHOLD 2097152UL
-#define METAL_RISCV_PLIC0_CLAIM 2097156UL
-
-/* 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_AON0
-#define METAL_SIFIVE_AON0_WDOGCFG 0UL
-#define METAL_SIFIVE_AON0_WDOGCOUNT 8UL
-#define METAL_SIFIVE_AON0_WDOGS 16UL
-#define METAL_SIFIVE_AON0_WDOGFEED 24UL
-#define METAL_SIFIVE_AON0_WDOGKEY 28UL
-#define METAL_SIFIVE_AON0_WDOGCMP 32UL
-#define METAL_SIFIVE_AON0_RTCCFG 64UL
-#define METAL_SIFIVE_AON0_RTCLO 72UL
-#define METAL_SIFIVE_AON0_RTCHI 72UL
-#define METAL_SIFIVE_AON0_RTCS 80UL
-#define METAL_SIFIVE_AON0_RTCCMP 96UL
-#define METAL_SIFIVE_AON0_LFROSCCFG 112UL
-#define METAL_SIFIVE_AON0_BACKUP0 128UL
-#define METAL_SIFIVE_AON0_BACKUP1 132UL
-#define METAL_SIFIVE_AON0_BACKUP2 136UL
-#define METAL_SIFIVE_AON0_BACKUP3 140UL
-#define METAL_SIFIVE_AON0_BACKUP4 144UL
-#define METAL_SIFIVE_AON0_BACKUP5 148UL
-#define METAL_SIFIVE_AON0_BACKUP6 152UL
-#define METAL_SIFIVE_AON0_BACKUP7 152UL
-#define METAL_SIFIVE_AON0_BACKUP8 160UL
-#define METAL_SIFIVE_AON0_BACKUP9 164UL
-#define METAL_SIFIVE_AON0_BACKUP10 168UL
-#define METAL_SIFIVE_AON0_BACKUP11 172UL
-#define METAL_SIFIVE_AON0_BACKUP12 176UL
-#define METAL_SIFIVE_AON0_BACKUP13 180UL
-#define METAL_SIFIVE_AON0_BACKUP14 184UL
-#define METAL_SIFIVE_AON0_BACKUP15 188UL
-#define METAL_SIFIVE_AON0_BACKUP16 192UL
-#define METAL_SIFIVE_AON0_BACKUP17 196UL
-#define METAL_SIFIVE_AON0_BACKUP18 200UL
-#define METAL_SIFIVE_AON0_BACKUP19 204UL
-#define METAL_SIFIVE_AON0_BACKUP20 208UL
-#define METAL_SIFIVE_AON0_BACKUP21 212UL
-#define METAL_SIFIVE_AON0_BACKUP22 216UL
-#define METAL_SIFIVE_AON0_BACKUP23 220UL
-#define METAL_SIFIVE_AON0_BACKUP24 224UL
-#define METAL_SIFIVE_AON0_BACKUP25 228UL
-#define METAL_SIFIVE_AON0_BACKUP26 232UL
-#define METAL_SIFIVE_AON0_BACKUP27 236UL
-#define METAL_SIFIVE_AON0_BACKUP28 240UL
-#define METAL_SIFIVE_AON0_BACKUP29 244UL
-#define METAL_SIFIVE_AON0_BACKUP30 248UL
-#define METAL_SIFIVE_AON0_BACKUP31 252UL
-#define METAL_SIFIVE_AON0_PMU_WAKEUP_BASE 256UL
-#define METAL_SIFIVE_AON0_PWM_SLEEP_BASE 288UL
-#define METAL_SIFIVE_AON0_PMUIE 320UL
-#define METAL_SIFIVE_AON0_PMUCAUSE 324UL
-#define METAL_SIFIVE_AON0_PMUSLEEP 328UL
-#define METAL_SIFIVE_AON0_PMUKEY 332UL
-
-/* From clock@3 */
-
-#define METAL_SIFIVE_FE310_G000_HFROSC
-
-/* From clock@1 */
-
-#define METAL_SIFIVE_FE310_G000_HFXOSC
-
-/* From prci@10008000 */
-#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_10008000_SIZE 32768UL
-#define METAL_SIFIVE_FE310_G000_PRCI_0_SIZE 32768UL
-
-#define METAL_SIFIVE_FE310_G000_PRCI
-#define METAL_SIFIVE_FE310_G000_PRCI_HFROSCCFG 0UL
-#define METAL_SIFIVE_FE310_G000_PRCI_HFXOSCCFG 4UL
-#define METAL_SIFIVE_FE310_G000_PRCI_PLLCFG 8UL
-#define METAL_SIFIVE_FE310_G000_PRCI_PLLOUTDIV 12UL
-
-/* From clock@4 */
-#define METAL_SIFIVE_FE310_G000_PLL_4_CLOCK_FREQUENCY 16000000UL
-
-#define METAL_SIFIVE_FE310_G000_PLL
-
-/* From gpio@10012000 */
-#define METAL_SIFIVE_GPIO0_10012000_BASE_ADDRESS 268509184UL
-#define METAL_SIFIVE_GPIO0_0_BASE_ADDRESS 268509184UL
-#define METAL_SIFIVE_GPIO0_10012000_SIZE 4096UL
-#define METAL_SIFIVE_GPIO0_0_SIZE 4096UL
-
-#define METAL_SIFIVE_GPIO0
-#define METAL_SIFIVE_GPIO0_VALUE 0UL
-#define METAL_SIFIVE_GPIO0_INPUT_EN 4UL
-#define METAL_SIFIVE_GPIO0_OUTPUT_EN 8UL
-#define METAL_SIFIVE_GPIO0_PORT 12UL
-#define METAL_SIFIVE_GPIO0_PUE 16UL
-#define METAL_SIFIVE_GPIO0_DS 20UL
-#define METAL_SIFIVE_GPIO0_RISE_IE 24UL
-#define METAL_SIFIVE_GPIO0_RISE_IP 28UL
-#define METAL_SIFIVE_GPIO0_FALL_IE 32UL
-#define METAL_SIFIVE_GPIO0_FALL_IP 36UL
-#define METAL_SIFIVE_GPIO0_HIGH_IE 40UL
-#define METAL_SIFIVE_GPIO0_HIGH_IP 44UL
-#define METAL_SIFIVE_GPIO0_LOW_IE 48UL
-#define METAL_SIFIVE_GPIO0_LOW_IP 52UL
-#define METAL_SIFIVE_GPIO0_IOF_EN 56UL
-#define METAL_SIFIVE_GPIO0_IOF_SEL 60UL
-#define METAL_SIFIVE_GPIO0_OUT_XOR 64UL
-
-/* From led@0red */
-
-/* From led@0green */
-
-/* From led@0blue */
-
-#define METAL_SIFIVE_GPIO_LEDS
-
-/* From i2c@10016000 */
-#define METAL_SIFIVE_I2C0_10016000_BASE_ADDRESS 268525568UL
-#define METAL_SIFIVE_I2C0_0_BASE_ADDRESS 268525568UL
-#define METAL_SIFIVE_I2C0_10016000_SIZE 4096UL
-#define METAL_SIFIVE_I2C0_0_SIZE 4096UL
-
-#define METAL_SIFIVE_I2C0
-#define METAL_SIFIVE_I2C0_PRESCALE_LOW 0UL
-#define METAL_SIFIVE_I2C0_PRESCALE_HIGH 4UL
-#define METAL_SIFIVE_I2C0_CONTROL 8UL
-#define METAL_SIFIVE_I2C0_TRANSMIT 12UL
-#define METAL_SIFIVE_I2C0_RECEIVE 12UL
-#define METAL_SIFIVE_I2C0_COMMAND 16UL
-#define METAL_SIFIVE_I2C0_STATUS 16UL
-
-/* From local_external_interrupts_0 */
-
-#define METAL_SIFIVE_LOCAL_EXTERNAL_INTERRUPTS0
-
-/* From pwm@10015000 */
-#define METAL_SIFIVE_PWM0_10015000_BASE_ADDRESS 268521472UL
-#define METAL_SIFIVE_PWM0_0_BASE_ADDRESS 268521472UL
-#define METAL_SIFIVE_PWM0_10015000_SIZE 4096UL
-#define METAL_SIFIVE_PWM0_0_SIZE 4096UL
-
-#define METAL_SIFIVE_PWM0
-#define METAL_SIFIVE_PWM0_PWMCFG 0UL
-#define METAL_SIFIVE_PWM0_PWMCOUNT 8UL
-#define METAL_SIFIVE_PWM0_PWMS 16UL
-#define METAL_SIFIVE_PWM0_PWMCMP0 32UL
-#define METAL_SIFIVE_PWM0_PWMCMP1 36UL
-#define METAL_SIFIVE_PWM0_PWMCMP2 40UL
-#define METAL_SIFIVE_PWM0_PWMCMP3 44UL
-
-/* From spi@10014000 */
-#define METAL_SIFIVE_SPI0_10014000_BASE_ADDRESS 268517376UL
-#define METAL_SIFIVE_SPI0_0_BASE_ADDRESS 268517376UL
-#define METAL_SIFIVE_SPI0_10014000_SIZE 4096UL
-#define METAL_SIFIVE_SPI0_0_SIZE 4096UL
-
-#define METAL_SIFIVE_SPI0
-#define METAL_SIFIVE_SPI0_SCKDIV 0UL
-#define METAL_SIFIVE_SPI0_SCKMODE 4UL
-#define METAL_SIFIVE_SPI0_CSID 16UL
-#define METAL_SIFIVE_SPI0_CSDEF 20UL
-#define METAL_SIFIVE_SPI0_CSMODE 24UL
-#define METAL_SIFIVE_SPI0_DELAY0 40UL
-#define METAL_SIFIVE_SPI0_DELAY1 44UL
-#define METAL_SIFIVE_SPI0_FMT 64UL
-#define METAL_SIFIVE_SPI0_TXDATA 72UL
-#define METAL_SIFIVE_SPI0_RXDATA 76UL
-#define METAL_SIFIVE_SPI0_TXMARK 80UL
-#define METAL_SIFIVE_SPI0_RXMARK 84UL
-#define METAL_SIFIVE_SPI0_FCTRL 96UL
-#define METAL_SIFIVE_SPI0_FFMT 100UL
-#define METAL_SIFIVE_SPI0_IE 112UL
-#define METAL_SIFIVE_SPI0_IP 116UL
-
-/* From serial@10013000 */
-#define METAL_SIFIVE_UART0_10013000_BASE_ADDRESS 268513280UL
-#define METAL_SIFIVE_UART0_0_BASE_ADDRESS 268513280UL
-#define METAL_SIFIVE_UART0_10013000_SIZE 4096UL
-#define METAL_SIFIVE_UART0_0_SIZE 4096UL
-
-#define METAL_SIFIVE_UART0
-#define METAL_SIFIVE_UART0_TXDATA 0UL
-#define METAL_SIFIVE_UART0_RXDATA 4UL
-#define METAL_SIFIVE_UART0_TXCTRL 8UL
-#define METAL_SIFIVE_UART0_RXCTRL 12UL
-#define METAL_SIFIVE_UART0_IE 16UL
-#define METAL_SIFIVE_UART0_IP 20UL
-#define METAL_SIFIVE_UART0_DIV 24UL
-
-#endif /* SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H*/
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__MEMORY_H
-#define METAL__MEMORY_H
-
-#include <stdint.h>
-#include <stddef.h>
-
-/*!
- * @file memory.h
- *
- * @brief API for enumerating memory blocks
- */
-
-struct _metal_memory_attributes {
- int R : 1;
- int W : 1;
- int X : 1;
- int C : 1;
- int A : 1;
-};
-
-/*!
- * @brief A handle for a memory block
- */
-struct metal_memory {
- const uintptr_t _base_address;
- const size_t _size;
- const struct _metal_memory_attributes _attrs;
-};
-
-/*!
- * @brief Get the memory block which services the given address
- *
- * Given a physical memory address, get a handle for the memory block to which
- * that address is mapped.
- *
- * @param address The address to query
- * @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);
-
-/*!
- * @brief Get the base address for a memory block
- * @param memory The handle for the memory block
- * @return The base address of the memory block
- */
-inline uintptr_t metal_memory_get_base_address(const struct metal_memory *memory) {
- return memory->_base_address;
-}
-
-/*!
- * @brief Get the size of a memory block
- * @param memory The handle for the memory block
- * @return The size of the memory block
- */
-inline size_t metal_memory_get_size(const struct metal_memory *memory) {
- return memory->_size;
-}
-
-/*!
- * @brief Query if a memory block supports atomic operations
- * @param memory The handle for the memory block
- * @return nonzero if the memory block supports atomic operations
- */
-inline int metal_memory_supports_atomics(const struct metal_memory *memory) {
- return memory->_attrs.A;
-}
-
-/*!
- * @brief Query if a memory block is cacheable
- * @param memory The handle for the memory block
- * @return nonzero if the memory block is cachable
- */
-inline int metal_memory_is_cachable(const struct metal_memory *memory) {
- return memory->_attrs.C;
-}
-
-#endif /* METAL__MEMORY_H */
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__PMP_H
-#define METAL__PMP_H
-
-/*!
- * @file metal/pmp.h
- *
- * @brief API for Configuring Physical Memory Protection on RISC-V Cores
- *
- * The Physical Memory Protection (PMP) interface on RISC-V cores
- * is a form of memory protection unit which allows for a finite number
- * of physical memory regions to be configured with certain access
- * permissions.
- *
- * Additional information about the use and configuration rules for PMPs
- * can be found by reading the RISC-V Privileged Architecture Specification.
- */
-
-#include <stddef.h>
-#include <metal/machine.h>
-
-struct metal_pmp;
-
-/*!
- * @brief Set of available PMP addressing modes
- */
-enum metal_pmp_address_mode {
- /*! @brief Disable the PMP region */
- METAL_PMP_OFF = 0,
- /*! @brief Use Top-of-Range mode */
- METAL_PMP_TOR = 1,
- /*! @brief Use naturally-aligned 4-byte region mode */
- METAL_PMP_NA4 = 2,
- /*! @brief Use naturally-aligned power-of-two mode */
- METAL_PMP_NAPOT = 3
-};
-
-/*!
- * @brief Configuration for a PMP region
- */
-struct metal_pmp_config {
- /*! @brief Sets whether reads to the PMP region succeed */
- int R : 1;
- /*! @brief Sets whether writes to the PMP region succeed */
- int W : 1;
- /*! @brief Sets whether the PMP region is executable */
- int X : 1;
-
- /*! @brief Sets the addressing mode of the PMP region */
- enum metal_pmp_address_mode A : 2;
-
- int _pad : 2;
-
- /*! @brief Sets whether the PMP region is locked */
- enum metal_pmp_locked {
- METAL_PMP_UNLOCKED = 0,
- METAL_PMP_LOCKED = 1
- } L : 1;
-};
-
-/*!
- * @brief A handle for the PMP device
- */
-struct metal_pmp {
- /* The minimum granularity of the PMP region. Set by metal_pmp_init */
- uintptr_t _granularity[METAL_MAX_CORES];
-};
-
-/*!
- * @brief Get the PMP device handle
- */
-struct metal_pmp *metal_pmp_get_device(void);
-
-/*!
- * @brief Initialize the PMP
- * @param pmp The PMP device handle to be initialized
- *
- * The PMP initialization routine is optional and may be called as many times
- * as is desired. The effect of the initialization routine is to attempt to set
- * all regions to unlocked and disabled, as well as to clear the X, W, and R
- * bits. Only the pmp configuration of the hart which executes the routine will
- * be affected.
- *
- * If any regions are fused to preset values by the implementation or locked,
- * those PMP regions will silently remain uninitialized.
- */
-void metal_pmp_init(struct metal_pmp *pmp);
-
-/*!
- * @brief Configure a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to configure
- * @param config The desired configuration of the PMP region
- * @param address The desired address of the PMP region
- * @return 0 upon success
- */
-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
- * @param pmp The PMP device handle
- * @param region The PMP region to read
- * @param config Variable to store the PMP region configuration
- * @param address Variable to store the PMP region address
- * @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);
-
-/*!
- * @brief Lock a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to lock
- * @return 0 if the region is successfully locked
- */
-int metal_pmp_lock(struct metal_pmp *pmp, unsigned int region);
-
-/*!
- * @brief Set the address for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to set
- * @param address The desired address of the PMP region
- * @return 0 if the address is successfully set
- */
-int metal_pmp_set_address(struct metal_pmp *pmp, unsigned int region, size_t address);
-
-/*!
- * @brief Get the address of a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to read
- * @return The address of the PMP region, or 0 if the region could not be read
- */
-size_t metal_pmp_get_address(struct metal_pmp *pmp, unsigned int region);
-
-/*!
- * @brief Set the addressing mode of a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to set
- * @param mode The PMP addressing mode to 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);
-
-/*!
- * @brief Get the addressing mode of a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to read
- * @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);
-
-/*!
- * @brief Set the executable bit for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to set
- * @param X The desired value of the executable bit
- * @return 0 if the executable bit is successfully set
- */
-int metal_pmp_set_executable(struct metal_pmp *pmp, unsigned int region, int X);
-
-/*!
- * @brief Get the executable bit for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to read
- * @return the value of the executable bit
- */
-int metal_pmp_get_executable(struct metal_pmp *pmp, unsigned int region);
-
-/*!
- * @brief Set the writable bit for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to set
- * @param W The desired value of the writable bit
- * @return 0 if the writable bit is successfully set
- */
-int metal_pmp_set_writeable(struct metal_pmp *pmp, unsigned int region, int W);
-
-/*!
- * @brief Get the writable bit for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to read
- * @return the value of the writable bit
- */
-int metal_pmp_get_writeable(struct metal_pmp *pmp, unsigned int region);
-
-/*!
- * @brief Set the readable bit for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to set
- * @param R The desired value of the readable bit
- * @return 0 if the readable bit is successfully set
- */
-int metal_pmp_set_readable(struct metal_pmp *pmp, unsigned int region, int R);
-
-/*!
- * @brief Set the readable bit for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to read
- * @return the value of the readable bit
- */
-int metal_pmp_get_readable(struct metal_pmp *pmp, unsigned int region);
-
-#endif
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__PRIVILEGE_H
-#define METAL__PRIVILEGE_H
-
-/*!
- * @file metal/privilege.h
- *
- * @brief API for manipulating the privilege mode of a RISC-V system
- *
- * Additional information about privilege modes on RISC-V systems can be found
- * by reading the RISC-V Privileged Architecture Specification v1.10.
- */
-
-#include <stdint.h>
-
-enum metal_privilege_mode {
- METAL_PRIVILEGE_USER = 0,
- METAL_PRIVILEGE_SUPERVISOR = 1,
- METAL_PRIVELEGE_MACHINE = 3,
-};
-
-#if __riscv_xlen == 32
-typedef uint32_t metal_xreg_t;
-#elif __riscv_xlen == 64
-typedef uint64_t metal_xreg_t;
-#endif
-
-#if __riscv_flen == 32
-typedef uint32_t metal_freg_t;
-#elif __riscv_flen == 64
-typedef uint64_t metal_freg_t;
-#endif
-
-struct metal_register_file {
- metal_xreg_t ra;
- metal_xreg_t sp;
- metal_xreg_t gp;
- metal_xreg_t tp;
-
- metal_xreg_t t0;
- metal_xreg_t t1;
- metal_xreg_t t2;
-
- metal_xreg_t s0;
- metal_xreg_t s1;
-
- metal_xreg_t a0;
- metal_xreg_t a1;
- metal_xreg_t a2;
- metal_xreg_t a3;
- metal_xreg_t a4;
- metal_xreg_t a5;
-#ifndef __riscv_32e
- metal_xreg_t a6;
- metal_xreg_t a7;
-
- metal_xreg_t s2;
- metal_xreg_t s3;
- metal_xreg_t s4;
- metal_xreg_t s5;
- metal_xreg_t s6;
- metal_xreg_t s7;
- metal_xreg_t s8;
- metal_xreg_t s9;
- metal_xreg_t s10;
- metal_xreg_t s11;
-
- metal_xreg_t t3;
- metal_xreg_t t4;
- metal_xreg_t t5;
- metal_xreg_t t6;
-#endif /* __riscv_32e */
-
-#ifdef __riscv_flen
- metal_freg_t ft0;
- metal_freg_t ft1;
- metal_freg_t ft2;
- metal_freg_t ft3;
- metal_freg_t ft4;
- metal_freg_t ft5;
- metal_freg_t ft6;
- metal_freg_t ft7;
-
- metal_freg_t fs0;
- metal_freg_t fs1;
-
- metal_freg_t fa0;
- metal_freg_t fa1;
- metal_freg_t fa2;
- metal_freg_t fa3;
- metal_freg_t fa4;
- metal_freg_t fa5;
- metal_freg_t fa6;
- metal_freg_t fa7;
-
- metal_freg_t fs2;
- metal_freg_t fs3;
- metal_freg_t fs4;
- metal_freg_t fs5;
- metal_freg_t fs6;
- metal_freg_t fs7;
- metal_freg_t fs8;
- metal_freg_t fs9;
- metal_freg_t fs10;
- metal_freg_t fs11;
-
- metal_freg_t ft8;
- metal_freg_t ft9;
- metal_freg_t ft10;
- metal_freg_t ft11;
-#endif /* __riscv_flen */
-};
-
-typedef void (*metal_privilege_entry_point_t)();
-
-void metal_privilege_drop_to_mode(enum metal_privilege_mode mode,
- struct metal_register_file regfile,
- metal_privilege_entry_point_t entry_point);
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__SHUTDOWN_H
-#define METAL__SHUTDOWN_H
-
-/*!
- * @file shutdown.h
- * @brief API for shutting down a machine
- */
-
-struct __metal_shutdown;
-
-struct __metal_shutdown_vtable {
- void (*exit)(const struct __metal_shutdown *sd, int code) __attribute__((noreturn));
-};
-
-struct __metal_shutdown {
- 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, int code) { sd->vtable->exit(sd, code); }
-
-/*!
- * @brief The public METAL shutdown interface
- *
- * Shuts down the machine, if the machine enables an interface for
- * shutting down. When no interface is provided, will cause the machine
- * to spin indefinitely.
- *
- * @param code The return code to set. 0 indicates program success.
- */
-void metal_shutdown(int code) __attribute__((noreturn));
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__SPI_H
-#define METAL__SPI_H
-
-struct metal_spi;
-
-/*! @brief The configuration for a SPI transfer */
-struct metal_spi_config {
- /*! @brief The protocol for the SPI transfer */
- enum {
- METAL_SPI_SINGLE,
- METAL_SPI_DUAL,
- METAL_SPI_QUAD
- } protocol;
-
- /*! @brief The polarity of the SPI transfer, equivalent to CPOL */
- unsigned int polarity : 1;
- /*! @brief The phase of the SPI transfer, equivalent to CPHA */
- unsigned int phase : 1;
- /*! @brief The endianness of the SPI transfer */
- unsigned int little_endian : 1;
- /*! @brief The active state of the chip select line */
- unsigned int cs_active_high : 1;
- /*! @brief The chip select ID to activate for the SPI transfer */
- unsigned int csid;
-};
-
-struct metal_spi_vtable {
- 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 (*get_baud_rate)(struct metal_spi *spi);
- int (*set_baud_rate)(struct metal_spi *spi, int baud_rate);
-};
-
-/*! @brief A handle for a SPI device */
-struct metal_spi {
- const struct metal_spi_vtable *vtable;
-};
-
-/*! @brief Get a handle for a 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*/
-struct metal_spi *metal_spi_get_device(int device_num);
-
-/*! @brief Initialize a SPI device with a certain baud rate
- * @param spi The handle for the SPI device to initialize
- * @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); }
-
-/*! @brief Perform a SPI transfer
- * @param spi The handle for the SPI device to perform the transfer
- * @param config The configuration for the SPI 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 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
- */
-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);
-}
-
-/*! @brief Get the current baud rate of the SPI device
- * @param spi The handle for the SPI device
- * @return The baud rate in Hz
- */
-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
- * @param spi The handle for the SPI device
- * @param baud_rate The desired baud rate of the SPI device
- * @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); }
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__SWITCH_H
-#define METAL__SWITCH_H
-
-/*!
- * @file switch.h
- * @brief API for reading toggle switches
- */
-
-#include <metal/interrupt.h>
-
-struct metal_switch;
-
-struct metal_switch_vtable {
- int (*switch_exist)(struct metal_switch *sw, char *label);
- struct metal_interrupt* (*interrupt_controller)(struct metal_switch *sw);
- int (*get_interrupt_id)(struct metal_switch *sw);
-};
-
-/*!
- * @brief A handle for a switch
- */
-struct metal_switch {
- const struct metal_switch_vtable *vtable;
-};
-
-/*!
- * @brief Get a handle for a 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
- */
-struct metal_switch* metal_switch_get(char *label);
-
-/*!
- * @brief Get the interrupt controller for a switch
- * @param sw The handle for the switch
- * @return The interrupt controller handle
- */
-inline struct metal_interrupt*
- metal_switch_interrupt_controller(struct metal_switch *sw) { return sw->vtable->interrupt_controller(sw); }
-
-/*!
- * @brief Get the interrupt id for a switch
- * @param sw The handle 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); }
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__TIMER_H
-#define METAL__TIMER_H
-
-/*!
- * @file timer.h
- * @brief API for reading and manipulating the machine timer
- */
-
-/*!
- * @brief Read the machine cycle count
- * @param hartid The hart ID to read the cycle count of
- * @param cyclecount The variable to hold the value
- * @return 0 upon success
- */
-int metal_timer_get_cyclecount(int hartid, unsigned long long *cyclecount);
-
-/*!
- * @brief Get the machine timebase frequency
- * @param hartid The hart ID to read the timebase of
- * @param timebase The variable to hold the value
- * @return 0 upon success
- */
-int metal_timer_get_timebase_frequency(int hartid, unsigned long long *timebase);
-
-/*!
- * @brief Set the machine timer tick interval in seconds
- * @param hartid The hart ID to read the timebase of
- * @param second The number of seconds to set the tick interval to
- * @return 0 upon success
- */
-int metal_timer_set_tick(int hartid, int second);
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__TTY_H
-#define METAL__TTY_H
-
-/*!
- * @file tty.h
- * @brief API for emulated serial teriminals
- */
-
-/*!
- * @brief Write a character to the default output device
- *
- * Write a character to the default output device, which for most
- * targets is the UART serial port.
- *
- * @param c The character to write to the terminal
- * @return 0 on success, or -1 on failure.
- */
-int metal_tty_putc(unsigned char c);
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__UART_H
-#define METAL__UART_H
-
-/*!
- * @file uart.h
- * @brief API for UART serial ports
- */
-
-#include <metal/interrupt.h>
-
-struct metal_uart;
-
-struct metal_uart_vtable {
- void (*init)(struct metal_uart *uart, int baud_rate);
- int (*putc)(struct metal_uart *uart, unsigned char c);
- int (*getc)(struct metal_uart *uart, unsigned char *c);
- int (*get_baud_rate)(struct metal_uart *uart);
- int (*set_baud_rate)(struct metal_uart *uart, int baud_rate);
- struct metal_interrupt* (*controller_interrupt)(struct metal_uart *uart);
- int (*get_interrupt_id)(struct metal_uart *uart);
-};
-
-/*!
- * @brief Handle for a UART serial device
- */
-struct metal_uart {
- const struct metal_uart_vtable *vtable;
-};
-
-/*!
- * @brief Initialize UART device
-
- * Initialize the UART device described by the UART handle. This function must 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 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); }
-
-/*!
- * @brief Output a character over the UART
- * @param uart The UART device handle
- * @param c The character to send over the UART
- * @return 0 upon success
- */
-inline int metal_uart_putc(struct metal_uart *uart, unsigned char c) { return uart->vtable->putc(uart, c); }
-
-/*!
- * @brief Read a character sent over the UART
- * @param uart The UART device handle
- * @param c The varible to hold the read character
- * @return 0 upon success
- */
-inline int metal_uart_getc(struct metal_uart *uart, unsigned char *c) { return uart->vtable->getc(uart, c); }
-
-/*!
- * @brief Get the baud rate of the UART peripheral
- * @param uart The UART device handle
- * @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); }
-
-/*!
- * @brief Set the baud rate of the UART peripheral
- * @param uart The UART device handle
- * @param baud_rate The baud rate to configure
- * @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); }
-
-/*!
- * @brief Get the interrupt controller of the UART peripheral
- *
- * Get the interrupt controller for the UART peripheral. The interrupt
- * controller must be initialized before any interrupts can be registered
- * or enabled with it.
- *
- * @param uart The UART device handle
- * @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); }
-
-/*!
- * @brief Get the interrupt ID of the UART controller
- * @param uart The UART device handle
- * @return The UART interrupt id
- */
-inline int metal_uart_get_interrupt_id(struct metal_uart *uart) { return uart->vtable->get_interrupt_id(uart); }
-
-#endif
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-/* ----------------------------------- */
-/* ----------------------------------- */
-
-#ifndef ASSEMBLY
-
-#ifndef SIFIVE_HIFIVE1_REVB____METAL_INLINE_H
-#define SIFIVE_HIFIVE1_REVB____METAL_INLINE_H
-
-#include <metal/machine.h>
-
-
-/* --------------------- fixed_clock ------------ */
-extern inline unsigned long __metal_driver_fixed_clock_rate(const struct metal_clock *clock);
-
-
-/* --------------------- fixed_factor_clock ------------ */
-
-
-/* --------------------- 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_size(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 int __metal_driver_sifive_clint0_interrupt_lines(struct metal_interrupt *controller, int idx);
-
-
-/* --------------------- 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 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);
-
-
-/* --------------------- 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_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_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 int __metal_driver_sifive_plic0_interrupt_lines(struct metal_interrupt *controller, int idx);
-
-
-/* --------------------- sifive_clic0 ------------ */
-
-
-/* --------------------- 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_gpio0 ------------ */
-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 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 int __metal_driver_sifive_gpio0_interrupt_lines(struct metal_gpio *gpio, int idx);
-
-
-/* --------------------- sifive_gpio_button ------------ */
-
-
-/* --------------------- sifive_gpio_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 char * __metal_driver_sifive_gpio_led_label(struct metal_led *led);
-
-
-/* --------------------- sifive_gpio_switch ------------ */
-
-
-/* --------------------- 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_size(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_source_selector(struct metal_spi *spi);
-
-
-/* --------------------- sifive_test0 ------------ */
-
-
-/* --------------------- 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_size(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 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_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_source_selector(struct metal_uart *uart);
-
-
-/* --------------------- 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_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 long __metal_driver_sifive_fe310_g000_hfrosc_config_offset(const struct metal_clock *clock);
-
-
-/* --------------------- 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_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);
-
-
-/* --------------------- 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_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 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 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( );
-
-
-/* --------------------- fe310_g000_prci ------------ */
-extern inline long __metal_driver_sifive_fe310_g000_prci_base( );
-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( );
-
-
-/* --------------------- sifive_fu540_c000_l2 ------------ */
-
-
-/* From clock@0 */
-struct __metal_driver_fixed_clock __metal_dt_clock_0 = {
- .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
-};
-
-/* From clock@2 */
-struct __metal_driver_fixed_clock __metal_dt_clock_2 = {
- .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
-};
-
-/* From clock@5 */
-struct __metal_driver_fixed_clock __metal_dt_clock_5 = {
- .clock.vtable = &__metal_driver_vtable_fixed_clock.clock,
-};
-
-struct metal_memory __metal_dt_mem_dtim_80000000 = {
- ._base_address = 2147483648UL,
- ._size = 16384UL,
- ._attrs = {
- .R = 1,
- .W = 1,
- .X = 1,
- .C = 1,
- .A = 1},
-};
-
-struct metal_memory __metal_dt_mem_spi_10014000 = {
- ._base_address = 536870912UL,
- ._size = 500000UL,
- ._attrs = {
- .R = 1,
- .W = 1,
- .X = 1,
- .C = 1,
- .A = 1},
-};
-
-/* From clint@2000000 */
-struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000 = {
- .controller.vtable = &__metal_driver_vtable_riscv_clint0.clint_vtable,
- .init_done = 0,
-};
-
-/* From cpu@0 */
-struct __metal_driver_cpu __metal_dt_cpu_0 = {
- .cpu.vtable = &__metal_driver_vtable_cpu.cpu_vtable,
-};
-
-/* From interrupt_controller */
-struct __metal_driver_riscv_cpu_intc __metal_dt_cpu_0_interrupt_controller = {
- .controller.vtable = &__metal_driver_vtable_riscv_cpu_intc.controller_vtable,
- .init_done = 0,
-};
-
-/* From interrupt_controller@c000000 */
-struct __metal_driver_riscv_plic0 __metal_dt_interrupt_controller_c000000 = {
- .controller.vtable = &__metal_driver_vtable_riscv_plic0.plic_vtable,
- .init_done = 0,
-};
-
-/* From local_external_interrupts_0 */
-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 */
-struct __metal_driver_sifive_gpio0 __metal_dt_gpio_10012000 = {
- .gpio.vtable = &__metal_driver_vtable_sifive_gpio0.gpio,
-};
-
-/* From led@0red */
-struct __metal_driver_sifive_gpio_led __metal_dt_led_0red = {
- .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
-};
-
-/* From led@0green */
-struct __metal_driver_sifive_gpio_led __metal_dt_led_0green = {
- .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
-};
-
-/* From led@0blue */
-struct __metal_driver_sifive_gpio_led __metal_dt_led_0blue = {
- .led.vtable = &__metal_driver_vtable_sifive_led.led_vtable,
-};
-
-/* From spi@10014000 */
-struct __metal_driver_sifive_spi0 __metal_dt_spi_10014000 = {
- .spi.vtable = &__metal_driver_vtable_sifive_spi0.spi,
-};
-
-/* From serial@10013000 */
-struct __metal_driver_sifive_uart0 __metal_dt_serial_10013000 = {
- .uart.vtable = &__metal_driver_vtable_sifive_uart0.uart,
-};
-
-/* From clock@3 */
-struct __metal_driver_sifive_fe310_g000_hfrosc __metal_dt_clock_3 = {
- .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfrosc.clock,
-};
-
-/* From clock@1 */
-struct __metal_driver_sifive_fe310_g000_hfxosc __metal_dt_clock_1 = {
- .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_hfxosc.clock,
-};
-
-/* From clock@4 */
-struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4 = {
- .clock.vtable = &__metal_driver_vtable_sifive_fe310_g000_pll.clock,
-};
-
-/* From prci@10008000 */
-struct __metal_driver_sifive_fe310_g000_prci __metal_dt_prci_10008000 = {
-};
-
-
-#endif /* SIFIVE_HIFIVE1_REVB____METAL_INLINE_H*/
-#endif /* ! ASSEMBLY */
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-/* ----------------------------------- */
-/* ----------------------------------- */
-
-#ifndef SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H
-#define SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H
-
-/* From clock@0 */
-#define METAL_FIXED_CLOCK_0_CLOCK_FREQUENCY 16000000UL
-
-/* From clock@2 */
-#define METAL_FIXED_CLOCK_2_CLOCK_FREQUENCY 72000000UL
-
-/* From clock@5 */
-#define METAL_FIXED_CLOCK_5_CLOCK_FREQUENCY 32000000UL
-
-#define METAL_FIXED_CLOCK
-
-/* From clint@2000000 */
-#define METAL_RISCV_CLINT0_2000000_BASE_ADDRESS 33554432UL
-#define METAL_RISCV_CLINT0_0_BASE_ADDRESS 33554432UL
-#define METAL_RISCV_CLINT0_2000000_SIZE 65536UL
-#define METAL_RISCV_CLINT0_0_SIZE 65536UL
-
-#define METAL_RISCV_CLINT0
-#define METAL_RISCV_CLINT0_MSIP_BASE 0UL
-#define METAL_RISCV_CLINT0_MTIMECMP_BASE 16384UL
-#define METAL_RISCV_CLINT0_MTIME 49144UL
-
-/* From interrupt_controller@c000000 */
-#define METAL_RISCV_PLIC0_C000000_BASE_ADDRESS 201326592UL
-#define METAL_RISCV_PLIC0_0_BASE_ADDRESS 201326592UL
-#define METAL_RISCV_PLIC0_C000000_SIZE 67108864UL
-#define METAL_RISCV_PLIC0_0_SIZE 67108864UL
-#define METAL_RISCV_PLIC0_C000000_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_0_RISCV_NDEV 27UL
-
-#define METAL_RISCV_PLIC0
-#define METAL_RISCV_PLIC0_PRIORITY_BASE 0UL
-#define METAL_RISCV_PLIC0_PENDING_BASE 4096UL
-#define METAL_RISCV_PLIC0_ENABLE_BASE 8192UL
-#define METAL_RISCV_PLIC0_THRESHOLD 2097152UL
-#define METAL_RISCV_PLIC0_CLAIM 2097156UL
-
-/* 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_AON0
-#define METAL_SIFIVE_AON0_WDOGCFG 0UL
-#define METAL_SIFIVE_AON0_WDOGCOUNT 8UL
-#define METAL_SIFIVE_AON0_WDOGS 16UL
-#define METAL_SIFIVE_AON0_WDOGFEED 24UL
-#define METAL_SIFIVE_AON0_WDOGKEY 28UL
-#define METAL_SIFIVE_AON0_WDOGCMP 32UL
-#define METAL_SIFIVE_AON0_RTCCFG 64UL
-#define METAL_SIFIVE_AON0_RTCLO 72UL
-#define METAL_SIFIVE_AON0_RTCHI 72UL
-#define METAL_SIFIVE_AON0_RTCS 80UL
-#define METAL_SIFIVE_AON0_RTCCMP 96UL
-#define METAL_SIFIVE_AON0_LFROSCCFG 112UL
-#define METAL_SIFIVE_AON0_BACKUP0 128UL
-#define METAL_SIFIVE_AON0_BACKUP1 132UL
-#define METAL_SIFIVE_AON0_BACKUP2 136UL
-#define METAL_SIFIVE_AON0_BACKUP3 140UL
-#define METAL_SIFIVE_AON0_BACKUP4 144UL
-#define METAL_SIFIVE_AON0_BACKUP5 148UL
-#define METAL_SIFIVE_AON0_BACKUP6 152UL
-#define METAL_SIFIVE_AON0_BACKUP7 152UL
-#define METAL_SIFIVE_AON0_BACKUP8 160UL
-#define METAL_SIFIVE_AON0_BACKUP9 164UL
-#define METAL_SIFIVE_AON0_BACKUP10 168UL
-#define METAL_SIFIVE_AON0_BACKUP11 172UL
-#define METAL_SIFIVE_AON0_BACKUP12 176UL
-#define METAL_SIFIVE_AON0_BACKUP13 180UL
-#define METAL_SIFIVE_AON0_BACKUP14 184UL
-#define METAL_SIFIVE_AON0_BACKUP15 188UL
-#define METAL_SIFIVE_AON0_BACKUP16 192UL
-#define METAL_SIFIVE_AON0_BACKUP17 196UL
-#define METAL_SIFIVE_AON0_BACKUP18 200UL
-#define METAL_SIFIVE_AON0_BACKUP19 204UL
-#define METAL_SIFIVE_AON0_BACKUP20 208UL
-#define METAL_SIFIVE_AON0_BACKUP21 212UL
-#define METAL_SIFIVE_AON0_BACKUP22 216UL
-#define METAL_SIFIVE_AON0_BACKUP23 220UL
-#define METAL_SIFIVE_AON0_BACKUP24 224UL
-#define METAL_SIFIVE_AON0_BACKUP25 228UL
-#define METAL_SIFIVE_AON0_BACKUP26 232UL
-#define METAL_SIFIVE_AON0_BACKUP27 236UL
-#define METAL_SIFIVE_AON0_BACKUP28 240UL
-#define METAL_SIFIVE_AON0_BACKUP29 244UL
-#define METAL_SIFIVE_AON0_BACKUP30 248UL
-#define METAL_SIFIVE_AON0_BACKUP31 252UL
-#define METAL_SIFIVE_AON0_PMU_WAKEUP_BASE 256UL
-#define METAL_SIFIVE_AON0_PWM_SLEEP_BASE 288UL
-#define METAL_SIFIVE_AON0_PMUIE 320UL
-#define METAL_SIFIVE_AON0_PMUCAUSE 324UL
-#define METAL_SIFIVE_AON0_PMUSLEEP 328UL
-#define METAL_SIFIVE_AON0_PMUKEY 332UL
-
-/* From clock@3 */
-
-#define METAL_SIFIVE_FE310_G000_HFROSC
-
-/* From clock@1 */
-
-#define METAL_SIFIVE_FE310_G000_HFXOSC
-
-/* From prci@10008000 */
-#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_10008000_SIZE 32768UL
-#define METAL_SIFIVE_FE310_G000_PRCI_0_SIZE 32768UL
-
-#define METAL_SIFIVE_FE310_G000_PRCI
-#define METAL_SIFIVE_FE310_G000_PRCI_HFROSCCFG 0UL
-#define METAL_SIFIVE_FE310_G000_PRCI_HFXOSCCFG 4UL
-#define METAL_SIFIVE_FE310_G000_PRCI_PLLCFG 8UL
-#define METAL_SIFIVE_FE310_G000_PRCI_PLLOUTDIV 12UL
-
-/* From clock@4 */
-#define METAL_SIFIVE_FE310_G000_PLL_4_CLOCK_FREQUENCY 16000000UL
-
-#define METAL_SIFIVE_FE310_G000_PLL
-
-/* From gpio@10012000 */
-#define METAL_SIFIVE_GPIO0_10012000_BASE_ADDRESS 268509184UL
-#define METAL_SIFIVE_GPIO0_0_BASE_ADDRESS 268509184UL
-#define METAL_SIFIVE_GPIO0_10012000_SIZE 4096UL
-#define METAL_SIFIVE_GPIO0_0_SIZE 4096UL
-
-#define METAL_SIFIVE_GPIO0
-#define METAL_SIFIVE_GPIO0_VALUE 0UL
-#define METAL_SIFIVE_GPIO0_INPUT_EN 4UL
-#define METAL_SIFIVE_GPIO0_OUTPUT_EN 8UL
-#define METAL_SIFIVE_GPIO0_PORT 12UL
-#define METAL_SIFIVE_GPIO0_PUE 16UL
-#define METAL_SIFIVE_GPIO0_DS 20UL
-#define METAL_SIFIVE_GPIO0_RISE_IE 24UL
-#define METAL_SIFIVE_GPIO0_RISE_IP 28UL
-#define METAL_SIFIVE_GPIO0_FALL_IE 32UL
-#define METAL_SIFIVE_GPIO0_FALL_IP 36UL
-#define METAL_SIFIVE_GPIO0_HIGH_IE 40UL
-#define METAL_SIFIVE_GPIO0_HIGH_IP 44UL
-#define METAL_SIFIVE_GPIO0_LOW_IE 48UL
-#define METAL_SIFIVE_GPIO0_LOW_IP 52UL
-#define METAL_SIFIVE_GPIO0_IOF_EN 56UL
-#define METAL_SIFIVE_GPIO0_IOF_SEL 60UL
-#define METAL_SIFIVE_GPIO0_OUT_XOR 64UL
-
-/* From led@0red */
-
-/* From led@0green */
-
-/* From led@0blue */
-
-#define METAL_SIFIVE_GPIO_LEDS
-
-/* From i2c@10016000 */
-#define METAL_SIFIVE_I2C0_10016000_BASE_ADDRESS 268525568UL
-#define METAL_SIFIVE_I2C0_0_BASE_ADDRESS 268525568UL
-#define METAL_SIFIVE_I2C0_10016000_SIZE 4096UL
-#define METAL_SIFIVE_I2C0_0_SIZE 4096UL
-
-#define METAL_SIFIVE_I2C0
-#define METAL_SIFIVE_I2C0_PRESCALE_LOW 0UL
-#define METAL_SIFIVE_I2C0_PRESCALE_HIGH 4UL
-#define METAL_SIFIVE_I2C0_CONTROL 8UL
-#define METAL_SIFIVE_I2C0_TRANSMIT 12UL
-#define METAL_SIFIVE_I2C0_RECEIVE 12UL
-#define METAL_SIFIVE_I2C0_COMMAND 16UL
-#define METAL_SIFIVE_I2C0_STATUS 16UL
-
-/* From local_external_interrupts_0 */
-
-#define METAL_SIFIVE_LOCAL_EXTERNAL_INTERRUPTS0
-
-/* From pwm@10015000 */
-#define METAL_SIFIVE_PWM0_10015000_BASE_ADDRESS 268521472UL
-#define METAL_SIFIVE_PWM0_0_BASE_ADDRESS 268521472UL
-#define METAL_SIFIVE_PWM0_10015000_SIZE 4096UL
-#define METAL_SIFIVE_PWM0_0_SIZE 4096UL
-
-#define METAL_SIFIVE_PWM0
-#define METAL_SIFIVE_PWM0_PWMCFG 0UL
-#define METAL_SIFIVE_PWM0_PWMCOUNT 8UL
-#define METAL_SIFIVE_PWM0_PWMS 16UL
-#define METAL_SIFIVE_PWM0_PWMCMP0 32UL
-#define METAL_SIFIVE_PWM0_PWMCMP1 36UL
-#define METAL_SIFIVE_PWM0_PWMCMP2 40UL
-#define METAL_SIFIVE_PWM0_PWMCMP3 44UL
-
-/* From spi@10014000 */
-#define METAL_SIFIVE_SPI0_10014000_BASE_ADDRESS 268517376UL
-#define METAL_SIFIVE_SPI0_0_BASE_ADDRESS 268517376UL
-#define METAL_SIFIVE_SPI0_10014000_SIZE 4096UL
-#define METAL_SIFIVE_SPI0_0_SIZE 4096UL
-
-#define METAL_SIFIVE_SPI0
-#define METAL_SIFIVE_SPI0_SCKDIV 0UL
-#define METAL_SIFIVE_SPI0_SCKMODE 4UL
-#define METAL_SIFIVE_SPI0_CSID 16UL
-#define METAL_SIFIVE_SPI0_CSDEF 20UL
-#define METAL_SIFIVE_SPI0_CSMODE 24UL
-#define METAL_SIFIVE_SPI0_DELAY0 40UL
-#define METAL_SIFIVE_SPI0_DELAY1 44UL
-#define METAL_SIFIVE_SPI0_FMT 64UL
-#define METAL_SIFIVE_SPI0_TXDATA 72UL
-#define METAL_SIFIVE_SPI0_RXDATA 76UL
-#define METAL_SIFIVE_SPI0_TXMARK 80UL
-#define METAL_SIFIVE_SPI0_RXMARK 84UL
-#define METAL_SIFIVE_SPI0_FCTRL 96UL
-#define METAL_SIFIVE_SPI0_FFMT 100UL
-#define METAL_SIFIVE_SPI0_IE 112UL
-#define METAL_SIFIVE_SPI0_IP 116UL
-
-/* From serial@10013000 */
-#define METAL_SIFIVE_UART0_10013000_BASE_ADDRESS 268513280UL
-#define METAL_SIFIVE_UART0_0_BASE_ADDRESS 268513280UL
-#define METAL_SIFIVE_UART0_10013000_SIZE 4096UL
-#define METAL_SIFIVE_UART0_0_SIZE 4096UL
-
-#define METAL_SIFIVE_UART0
-#define METAL_SIFIVE_UART0_TXDATA 0UL
-#define METAL_SIFIVE_UART0_RXDATA 4UL
-#define METAL_SIFIVE_UART0_TXCTRL 8UL
-#define METAL_SIFIVE_UART0_RXCTRL 12UL
-#define METAL_SIFIVE_UART0_IE 16UL
-#define METAL_SIFIVE_UART0_IP 20UL
-#define METAL_SIFIVE_UART0_DIV 24UL
-
-#endif /* SIFIVE_HIFIVE1_REVB____METAL_PLATFORM_H*/
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-/* ----------------------------------- */
-/* ----------------------------------- */
-
-OUTPUT_ARCH("riscv")
-
-ENTRY(_enter)
-
-MEMORY
-{
- ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 0x4000
- flash (rxai!w) : ORIGIN = 0x20010000, LENGTH = 0x6a120
-}
-
-PHDRS
-{
- flash PT_LOAD;
- ram_init PT_LOAD;
- itim_init PT_LOAD;
- ram PT_NULL;
- itim PT_NULL;
-}
-
-SECTIONS
-{
- __stack_size = DEFINED(__stack_size) ? __stack_size : 0x400;
- PROVIDE(__stack_size = __stack_size);
- __heap_size = DEFINED(__heap_size) ? __heap_size : 0x4;
- PROVIDE(__metal_boot_hart = 0);
- PROVIDE(__metal_chicken_bit = 0);
-
-
- .init :
- {
- KEEP (*(.text.metal.init.enter))
- KEEP (*(SORT_NONE(.init)))
- KEEP (*(.text.libgloss.start))
- } >flash AT>flash :flash
-
-
- .text :
- {
- *(.text.unlikely .text.unlikely.*)
- *(.text.startup .text.startup.*)
- *(.text .text.*)
- *(.itim .itim.*)
- *(.gnu.linkonce.t.*)
- } >flash AT>flash :flash
-
-
- .fini :
- {
- KEEP (*(SORT_NONE(.fini)))
- } >flash AT>flash :flash
-
-
- PROVIDE (__etext = .);
- PROVIDE (_etext = .);
- PROVIDE (etext = .);
-
-
- .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
-
-
-}
-
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-/* ----------------------------------- */
-/* ----------------------------------- */
-
-#ifndef ASSEMBLY
-
-#include <metal/machine/platform.h>
-
-#ifdef __METAL_MACHINE_MACROS
-
-#ifndef MACROS_IF_SIFIVE_HIFIVE1_REVB____METAL_H
-#define MACROS_IF_SIFIVE_HIFIVE1_REVB____METAL_H
-
-#define __METAL_CLINT_NUM_PARENTS 2
-
-#ifndef __METAL_CLINT_NUM_PARENTS
-#define __METAL_CLINT_NUM_PARENTS 0
-#endif
-#define __METAL_PLIC_SUBINTERRUPTS 27
-
-#define __METAL_PLIC_NUM_PARENTS 1
-
-#ifndef __METAL_PLIC_SUBINTERRUPTS
-#define __METAL_PLIC_SUBINTERRUPTS 0
-#endif
-#ifndef __METAL_PLIC_NUM_PARENTS
-#define __METAL_PLIC_NUM_PARENTS 0
-#endif
-#ifndef __METAL_CLIC_SUBINTERRUPTS
-#define __METAL_CLIC_SUBINTERRUPTS 0
-#endif
-
-#endif /* MACROS_IF_SIFIVE_HIFIVE1_REVB____METAL_H*/
-
-#else /* ! __METAL_MACHINE_MACROS */
-
-#ifndef MACROS_ELSE_SIFIVE_HIFIVE1_REVB____METAL_H
-#define MACROS_ELSE_SIFIVE_HIFIVE1_REVB____METAL_H
-
-#define __METAL_CLINT_2000000_INTERRUPTS 2
-
-#define METAL_MAX_CLINT_INTERRUPTS 2
-
-#define __METAL_CLINT_NUM_PARENTS 2
-
-#define __METAL_INTERRUPT_CONTROLLER_C000000_INTERRUPTS 1
-
-#define __METAL_PLIC_SUBINTERRUPTS 27
-
-#define METAL_MAX_PLIC_INTERRUPTS 1
-
-#define __METAL_PLIC_NUM_PARENTS 1
-
-#define __METAL_CLIC_SUBINTERRUPTS 0
-#define METAL_MAX_CLIC_INTERRUPTS 0
-
-#define __METAL_LOCAL_EXTERNAL_INTERRUPTS_0_INTERRUPTS 16
-
-#define METAL_MAX_LOCAL_EXT_INTERRUPTS 16
-
-#define METAL_MAX_GLOBAL_EXT_INTERRUPTS 0
-
-#define __METAL_GPIO_10012000_INTERRUPTS 16
-
-#define METAL_MAX_GPIO_INTERRUPTS 16
-
-#define __METAL_SERIAL_10013000_INTERRUPTS 1
-
-#define METAL_MAX_UART_INTERRUPTS 1
-
-
-#include <metal/drivers/fixed-clock.h>
-#include <metal/memory.h>
-#include <metal/drivers/riscv_clint0.h>
-#include <metal/drivers/riscv_cpu.h>
-#include <metal/drivers/riscv_plic0.h>
-#include <metal/pmp.h>
-#include <metal/drivers/sifive_local-external-interrupts0.h>
-#include <metal/drivers/sifive_gpio0.h>
-#include <metal/drivers/sifive_gpio-leds.h>
-#include <metal/drivers/sifive_spi0.h>
-#include <metal/drivers/sifive_uart0.h>
-#include <metal/drivers/sifive_fe310-g000_hfrosc.h>
-#include <metal/drivers/sifive_fe310-g000_hfxosc.h>
-#include <metal/drivers/sifive_fe310-g000_pll.h>
-#include <metal/drivers/sifive_fe310-g000_prci.h>
-
-/* From clock@0 */
-struct __metal_driver_fixed_clock __metal_dt_clock_0;
-
-/* From clock@2 */
-struct __metal_driver_fixed_clock __metal_dt_clock_2;
-
-/* From clock@5 */
-struct __metal_driver_fixed_clock __metal_dt_clock_5;
-
-struct metal_memory __metal_dt_mem_dtim_80000000;
-
-struct metal_memory __metal_dt_mem_spi_10014000;
-
-/* From clint@2000000 */
-struct __metal_driver_riscv_clint0 __metal_dt_clint_2000000;
-
-/* From cpu@0 */
-struct __metal_driver_cpu __metal_dt_cpu_0;
-
-struct __metal_driver_riscv_cpu_intc __metal_dt_cpu_0_interrupt_controller;
-
-/* From interrupt_controller@c000000 */
-struct __metal_driver_riscv_plic0 __metal_dt_interrupt_controller_c000000;
-
-struct metal_pmp __metal_dt_pmp;
-
-/* From local_external_interrupts_0 */
-struct __metal_driver_sifive_local_external_interrupts0 __metal_dt_local_external_interrupts_0;
-
-/* From gpio@10012000 */
-struct __metal_driver_sifive_gpio0 __metal_dt_gpio_10012000;
-
-/* From led@0red */
-struct __metal_driver_sifive_gpio_led __metal_dt_led_0red;
-
-/* From led@0green */
-struct __metal_driver_sifive_gpio_led __metal_dt_led_0green;
-
-/* From led@0blue */
-struct __metal_driver_sifive_gpio_led __metal_dt_led_0blue;
-
-/* From spi@10014000 */
-struct __metal_driver_sifive_spi0 __metal_dt_spi_10014000;
-
-/* From serial@10013000 */
-struct __metal_driver_sifive_uart0 __metal_dt_serial_10013000;
-
-/* From clock@3 */
-struct __metal_driver_sifive_fe310_g000_hfrosc __metal_dt_clock_3;
-
-/* From clock@1 */
-struct __metal_driver_sifive_fe310_g000_hfxosc __metal_dt_clock_1;
-
-/* From clock@4 */
-struct __metal_driver_sifive_fe310_g000_pll __metal_dt_clock_4;
-
-/* From prci@10008000 */
-struct __metal_driver_sifive_fe310_g000_prci __metal_dt_prci_10008000;
-
-
-
-/* --------------------- fixed_clock ------------ */
-static inline unsigned long __metal_driver_fixed_clock_rate(const struct metal_clock *clock)
-{
- if ((uintptr_t)clock == (uintptr_t)&__metal_dt_clock_0) {
- return METAL_FIXED_CLOCK_0_CLOCK_FREQUENCY;
- }
- else if ((uintptr_t)clock == (uintptr_t)&__metal_dt_clock_2) {
- return METAL_FIXED_CLOCK_2_CLOCK_FREQUENCY;
- }
- else if ((uintptr_t)clock == (uintptr_t)&__metal_dt_clock_5) {
- return METAL_FIXED_CLOCK_5_CLOCK_FREQUENCY;
- }
- else {
- return 0;
- }
-}
-
-
-
-/* --------------------- fixed_factor_clock ------------ */
-
-
-/* --------------------- sifive_clint0 ------------ */
-static inline unsigned long __metal_driver_sifive_clint0_control_base(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_clint_2000000) {
- return METAL_RISCV_CLINT0_2000000_BASE_ADDRESS;
- }
- else {
- return 0;
- }
-}
-
-static inline unsigned long __metal_driver_sifive_clint0_control_size(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_clint_2000000) {
- return METAL_RISCV_CLINT0_2000000_SIZE;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_clint0_num_interrupts(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_clint_2000000) {
- return METAL_MAX_CLINT_INTERRUPTS;
- }
- else {
- return 0;
- }
-}
-
-static inline struct metal_interrupt * __metal_driver_sifive_clint0_interrupt_parents(struct metal_interrupt *controller, int idx)
-{
- if (idx == 0) {
- return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
- }
- else if (idx == 1) {
- return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
- }
- else {
- return NULL;
- }
-}
-
-static inline int __metal_driver_sifive_clint0_interrupt_lines(struct metal_interrupt *controller, int idx)
-{
- if (idx == 0) {
- return 3;
- }
- else if (idx == 1) {
- return 7;
- }
- else {
- return 0;
- }
-}
-
-
-
-/* --------------------- cpu ------------ */
-static inline int __metal_driver_cpu_hartid(struct metal_cpu *cpu)
-{
- if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
- return 0;
- }
- else {
- return -1;
- }
-}
-
-static inline int __metal_driver_cpu_timebase(struct metal_cpu *cpu)
-{
- if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
- return 1000000;
- }
- else {
- return 0;
- }
-}
-
-static inline struct metal_interrupt * __metal_driver_cpu_interrupt_controller(struct metal_cpu *cpu)
-{
- if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
- return &__metal_dt_cpu_0_interrupt_controller.controller;
- }
- else {
- return NULL;
- }
-}
-
-static inline int __metal_driver_cpu_num_pmp_regions(struct metal_cpu *cpu)
-{
- if ((uintptr_t)cpu == (uintptr_t)&__metal_dt_cpu_0) {
- return 8;
- }
- else {
- return 0;
- }
-}
-
-
-
-/* --------------------- sifive_plic0 ------------ */
-static inline unsigned long __metal_driver_sifive_plic0_control_base(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
- return METAL_RISCV_PLIC0_C000000_BASE_ADDRESS;
- }
- else {
- return 0;
- }
-}
-
-static inline unsigned long __metal_driver_sifive_plic0_control_size(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
- return METAL_RISCV_PLIC0_C000000_SIZE;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_plic0_num_interrupts(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
- return METAL_RISCV_PLIC0_C000000_RISCV_NDEV;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_plic0_max_priority(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_interrupt_controller_c000000) {
- return METAL_RISCV_PLIC0_C000000_RISCV_MAX_PRIORITY;
- }
- else {
- return 0;
- }
-}
-
-static inline struct metal_interrupt * __metal_driver_sifive_plic0_interrupt_parents(struct metal_interrupt *controller, int idx)
-{
- if (idx == 0) {
- return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
- }
- else if (idx == 0) {
- return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
- }
- else {
- return NULL;
- }
-}
-
-static inline int __metal_driver_sifive_plic0_interrupt_lines(struct metal_interrupt *controller, int idx)
-{
- if (idx == 0) {
- return 11;
- }
- else if (idx == 0) {
- return 11;
- }
- else {
- return 0;
- }
-}
-
-
-
-/* --------------------- sifive_clic0 ------------ */
-
-
-/* --------------------- sifive_local_external_interrupts0 ------------ */
-static inline struct metal_interrupt * __metal_driver_sifive_local_external_interrupts0_interrupt_parent(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_local_external_interrupts_0) {
- return (struct metal_interrupt *)&__metal_dt_cpu_0_interrupt_controller.controller;
- }
- else {
- return NULL;
- }
-}
-
-static inline int __metal_driver_sifive_local_external_interrupts0_num_interrupts(struct metal_interrupt *controller)
-{
- if ((uintptr_t)controller == (uintptr_t)&__metal_dt_local_external_interrupts_0) {
- return METAL_MAX_LOCAL_EXT_INTERRUPTS;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_local_external_interrupts0_interrupt_lines(struct metal_interrupt *controller, int idx)
-{
- if (idx == 0) {
- return 16;
- }
- else if (idx == 1) {
- return 17;
- }
- else if (idx == 2) {
- return 18;
- }
- else if (idx == 3) {
- return 19;
- }
- else if (idx == 4) {
- return 20;
- }
- else if (idx == 5) {
- return 21;
- }
- else if (idx == 6) {
- return 22;
- }
- else if (idx == 7) {
- return 23;
- }
- else if (idx == 8) {
- return 24;
- }
- else if (idx == 9) {
- return 25;
- }
- else if (idx == 10) {
- return 26;
- }
- else if (idx == 11) {
- return 27;
- }
- else if (idx == 12) {
- return 28;
- }
- else if (idx == 13) {
- return 29;
- }
- else if (idx == 14) {
- return 30;
- }
- else if (idx == 15) {
- return 31;
- }
- else {
- return 0;
- }
-}
-
-
-
-/* --------------------- sifive_global_external_interrupts0 ------------ */
-
-
-/* --------------------- sifive_gpio0 ------------ */
-static inline unsigned long __metal_driver_sifive_gpio0_base(struct metal_gpio *gpio)
-{
- if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
- return METAL_SIFIVE_GPIO0_10012000_BASE_ADDRESS;
- }
- else {
- return 0;
- }
-}
-
-static inline unsigned long __metal_driver_sifive_gpio0_size(struct metal_gpio *gpio)
-{
- if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
- return METAL_SIFIVE_GPIO0_10012000_SIZE;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_gpio0_num_interrupts(struct metal_gpio *gpio)
-{
- if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
- return METAL_MAX_GPIO_INTERRUPTS;
- }
- else {
- return 0;
- }
-}
-
-static inline struct metal_interrupt * __metal_driver_sifive_gpio0_interrupt_parent(struct metal_gpio *gpio)
-{
- if ((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) {
- return (struct metal_interrupt *)&__metal_dt_interrupt_controller_c000000.controller;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_gpio0_interrupt_lines(struct metal_gpio *gpio, int idx)
-{
- if (((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 0)) {
- return 7;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 1))) {
- return 8;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 2))) {
- return 9;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 3))) {
- return 10;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 4))) {
- return 11;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 5))) {
- return 12;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 6))) {
- return 13;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 7))) {
- return 14;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 8))) {
- return 15;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 9))) {
- return 16;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 10))) {
- return 17;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 11))) {
- return 18;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 12))) {
- return 19;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 13))) {
- return 20;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 14))) {
- return 21;
- }
- else if ((((uintptr_t)gpio == (uintptr_t)&__metal_dt_gpio_10012000) && (idx == 15))) {
- return 22;
- }
- else {
- return 0;
- }
-}
-
-
-
-/* --------------------- sifive_gpio_button ------------ */
-
-
-/* --------------------- sifive_gpio_led ------------ */
-static inline struct metal_gpio * __metal_driver_sifive_gpio_led_gpio(struct metal_led *led)
-{
- if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0red) {
- return (struct metal_gpio *)&__metal_dt_gpio_10012000;
- }
- else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0green) {
- return (struct metal_gpio *)&__metal_dt_gpio_10012000;
- }
- else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0blue) {
- return (struct metal_gpio *)&__metal_dt_gpio_10012000;
- }
- else {
- return NULL;
- }
-}
-
-static inline int __metal_driver_sifive_gpio_led_pin(struct metal_led *led)
-{
- if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0red) {
- return 22;
- }
- else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0green) {
- return 19;
- }
- else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0blue) {
- return 21;
- }
- else {
- return 0;
- }
-}
-
-static inline char * __metal_driver_sifive_gpio_led_label(struct metal_led *led)
-{
- if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0red) {
- return "LD0red";
- }
- else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0green) {
- return "LD0green";
- }
- else if ((uintptr_t)led == (uintptr_t)&__metal_dt_led_0blue) {
- return "LD0blue";
- }
- else {
- return "";
- }
-}
-
-
-
-/* --------------------- sifive_gpio_switch ------------ */
-
-
-/* --------------------- sifive_spi0 ------------ */
-static inline unsigned long __metal_driver_sifive_spi0_control_base(struct metal_spi *spi)
-{
- if ((uintptr_t)spi == (uintptr_t)&__metal_dt_spi_10014000) {
- return METAL_SIFIVE_SPI0_10014000_BASE_ADDRESS;
- }
- else {
- return 0;
- }
-}
-
-static inline unsigned long __metal_driver_sifive_spi0_control_size(struct metal_spi *spi)
-{
- if ((uintptr_t)spi == (uintptr_t)&__metal_dt_spi_10014000) {
- return METAL_SIFIVE_SPI0_10014000_SIZE;
- }
- else {
- return 0;
- }
-}
-
-static inline struct metal_clock * __metal_driver_sifive_spi0_clock(struct metal_spi *spi)
-{
- return (struct metal_clock *)&__metal_dt_clock_4.clock;
-}
-
-static inline struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_spi0_pinmux(struct metal_spi *spi)
-{
- return (struct __metal_driver_sifive_gpio0 *)&__metal_dt_gpio_10012000;
-}
-
-static inline unsigned long __metal_driver_sifive_spi0_pinmux_output_selector(struct metal_spi *spi)
-{
- return 60;
-}
-
-static inline unsigned long __metal_driver_sifive_spi0_pinmux_source_selector(struct metal_spi *spi)
-{
- return 60;
-}
-
-
-
-/* --------------------- sifive_test0 ------------ */
-
-
-/* --------------------- sifive_uart0 ------------ */
-static inline unsigned long __metal_driver_sifive_uart0_control_base(struct metal_uart *uart)
-{
- if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
- return METAL_SIFIVE_UART0_10013000_BASE_ADDRESS;
- }
- else {
- return 0;
- }
-}
-
-static inline unsigned long __metal_driver_sifive_uart0_control_size(struct metal_uart *uart)
-{
- if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
- return METAL_SIFIVE_UART0_10013000_SIZE;
- }
- else {
- return 0;
- }
-}
-
-static inline int __metal_driver_sifive_uart0_num_interrupts(struct metal_uart *uart)
-{
- if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
- return METAL_MAX_UART_INTERRUPTS;
- }
- else {
- return 0;
- }
-}
-
-static inline struct metal_interrupt * __metal_driver_sifive_uart0_interrupt_parent(struct metal_uart *uart)
-{
- if ((uintptr_t)uart == (uintptr_t)&__metal_dt_serial_10013000) {
- return (struct metal_interrupt *)&__metal_dt_interrupt_controller_c000000.controller;
- }
- else {
- return NULL;
- }
-}
-
-static inline int __metal_driver_sifive_uart0_interrupt_line(struct metal_uart *uart)
-{
- return 5;
-}
-
-static inline struct metal_clock * __metal_driver_sifive_uart0_clock(struct metal_uart *uart)
-{
- return (struct metal_clock *)&__metal_dt_clock_4.clock;
-}
-
-static inline struct __metal_driver_sifive_gpio0 * __metal_driver_sifive_uart0_pinmux(struct metal_uart *uart)
-{
- return (struct __metal_driver_sifive_gpio0 *)&__metal_dt_gpio_10012000;
-}
-
-static inline unsigned long __metal_driver_sifive_uart0_pinmux_output_selector(struct metal_uart *uart)
-{
- return 196608;
-}
-
-static inline unsigned long __metal_driver_sifive_uart0_pinmux_source_selector(struct metal_uart *uart)
-{
- return 196608;
-}
-
-
-
-/* --------------------- sifive_fe310_g000_hfrosc ------------ */
-static inline struct metal_clock * __metal_driver_sifive_fe310_g000_hfrosc_ref(const struct metal_clock *clock)
-{
- return (struct metal_clock *)&__metal_dt_clock_2.clock;
-}
-
-static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_base(const struct metal_clock *clock)
-{
- return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
-}
-
-static inline const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfrosc_config_vtable(struct metal_clock *clock)
-{
- return &__metal_driver_vtable_sifive_fe310_g000_prci;
-}
-
-static inline long __metal_driver_sifive_fe310_g000_hfrosc_config_offset(const struct metal_clock *clock)
-{
- return METAL_SIFIVE_FE310_G000_PRCI_HFROSCCFG;
-}
-
-
-
-/* --------------------- sifive_fe310_g000_hfxosc ------------ */
-static inline struct metal_clock * __metal_driver_sifive_fe310_g000_hfxosc_ref(const struct metal_clock *clock)
-{
- return (struct metal_clock *)&__metal_dt_clock_0.clock;
-}
-
-static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_hfxosc_config_base(const struct metal_clock *clock)
-{
- return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
-}
-
-static inline long __metal_driver_sifive_fe310_g000_hfxosc_config_offset(const struct metal_clock *clock)
-{
- return METAL_SIFIVE_FE310_G000_PRCI_HFXOSCCFG;
-}
-
-
-
-/* --------------------- sifive_fe310_g000_pll ------------ */
-static inline struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllsel0(const struct metal_clock *clock)
-{
- return (struct metal_clock *)&__metal_dt_clock_3.clock;
-}
-
-static inline struct metal_clock * __metal_driver_sifive_fe310_g000_pll_pllref(const struct metal_clock *clock)
-{
- return (struct metal_clock *)&__metal_dt_clock_1.clock;
-}
-
-static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_divider_base(const struct metal_clock *clock)
-{
- return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
-}
-
-static inline long __metal_driver_sifive_fe310_g000_pll_divider_offset(const struct metal_clock *clock)
-{
- return METAL_SIFIVE_FE310_G000_PRCI_PLLOUTDIV;
-}
-
-static inline struct __metal_driver_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_pll_config_base( )
-{
- return (struct __metal_driver_sifive_fe310_g000_prci *)&__metal_dt_prci_10008000;
-}
-
-static inline long __metal_driver_sifive_fe310_g000_pll_config_offset( )
-{
- return METAL_SIFIVE_FE310_G000_PRCI_PLLCFG;
-}
-
-static inline long __metal_driver_sifive_fe310_g000_pll_init_rate( )
-{
- return 16000000;
-}
-
-
-
-/* --------------------- sifive_fe310_g000_prci ------------ */
-static inline long __metal_driver_sifive_fe310_g000_prci_base( )
-{
- return METAL_SIFIVE_FE310_G000_PRCI_10008000_BASE_ADDRESS;
-}
-
-static inline long __metal_driver_sifive_fe310_g000_prci_size( )
-{
- return METAL_SIFIVE_FE310_G000_PRCI_10008000_SIZE;
-}
-
-static inline const struct __metal_driver_vtable_sifive_fe310_g000_prci * __metal_driver_sifive_fe310_g000_prci_vtable( )
-{
- return &__metal_driver_vtable_sifive_fe310_g000_prci;
-}
-
-
-
-/* --------------------- sifive_fu540_c000_l2 ------------ */
-
-
-#define __METAL_DT_MAX_MEMORIES 2
-
-asm (".weak __metal_memory_table");
-struct metal_memory *__metal_memory_table[] = {
- &__metal_dt_mem_dtim_80000000,
- &__metal_dt_mem_spi_10014000};
-
-/* From serial@10013000 */
-#define __METAL_DT_STDOUT_UART_HANDLE (&__metal_dt_serial_10013000.uart)
-
-#define __METAL_DT_SERIAL_10013000_HANDLE (&__metal_dt_serial_10013000.uart)
-
-#define __METAL_DT_STDOUT_UART_BAUD 115200
-
-/* From clint@2000000 */
-#define __METAL_DT_RISCV_CLINT0_HANDLE (&__metal_dt_clint_2000000.controller)
-
-#define __METAL_DT_CLINT_2000000_HANDLE (&__metal_dt_clint_2000000.controller)
-
-#define __METAL_DT_MAX_HARTS 1
-
-asm (".weak __metal_cpu_table");
-struct __metal_driver_cpu *__metal_cpu_table[] = {
- &__metal_dt_cpu_0};
-
-/* From interrupt_controller@c000000 */
-#define __METAL_DT_RISCV_PLIC0_HANDLE (&__metal_dt_interrupt_controller_c000000.controller)
-
-#define __METAL_DT_INTERRUPT_CONTROLLER_C000000_HANDLE (&__metal_dt_interrupt_controller_c000000.controller)
-
-#define __METAL_DT_PMP_HANDLE (&__metal_dt_pmp)
-
-/* From local_external_interrupts_0 */
-#define __METAL_DT_SIFIVE_LOCAL_EXINTR0_HANDLE (&__metal_dt_local_external_interrupts_0.irc)
-
-#define __METAL_DT_LOCAL_EXTERNAL_INTERRUPTS_0_HANDLE (&__metal_dt_local_external_interrupts_0.irc)
-
-#define __MEE_DT_MAX_GPIOS 1
-
-asm (".weak __metal_gpio_table");
-struct __metal_driver_sifive_gpio0 *__metal_gpio_table[] = {
- &__metal_dt_gpio_10012000};
-
-#define __METAL_DT_MAX_BUTTONS 0
-
-asm (".weak __metal_button_table");
-struct __metal_driver_sifive_gpio_button *__metal_button_table[] = {
- NULL };
-#define __METAL_DT_MAX_LEDS 3
-
-asm (".weak __metal_led_table");
-struct __metal_driver_sifive_gpio_led *__metal_led_table[] = {
- &__metal_dt_led_0red,
- &__metal_dt_led_0green,
- &__metal_dt_led_0blue};
-
-#define __METAL_DT_MAX_SWITCHES 0
-
-asm (".weak __metal_switch_table");
-struct __metal_driver_sifive_gpio_switch *__metal_switch_table[] = {
- NULL };
-#define __METAL_DT_MAX_SPIS 1
-
-asm (".weak __metal_spi_table");
-struct __metal_driver_sifive_spi0 *__metal_spi_table[] = {
- &__metal_dt_spi_10014000};
-
-/* From clock@4 */
-#define __METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE (&__metal_dt_clock_4)
-
-#define __METAL_DT_CLOCK_4_HANDLE (&__metal_dt_clock_4)
-
-#endif /* MACROS_ELSE_SIFIVE_HIFIVE1_REVB____METAL_H*/
-
-#endif /* ! __METAL_MACHINE_MACROS */
-
-#endif /* ! ASSEMBLY */
+++ /dev/null
-[{000214A0-0000-0000-C000-000000000046}]\r
-Prop3=19,11\r
-[InternetShortcut]\r
-IDList=\r
-URL=https://github.com/sifive/freedom-metal-docs\r
+++ /dev/null
-/* Copyright (c) 2017-2018 SiFive Inc. All rights reserved.
-
- This copyrighted material is made available to anyone wishing to use,
- modify, copy, or redistribute it subject to the terms and conditions
- of the FreeBSD License. This program is distributed in the hope that
- it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
- including the implied warranties of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. A copy of this license is available at
- http://www.opensource.org/licenses.
-*/
-
-/* crt0.S: Entry point for RISC-V METAL programs. */
-
-.section .text.libgloss.start
-.global _start
-.type _start, @function
-
- /* _start is defined by the METAL to have been called with the following
- * arguments:
- * a0: the hart ID of the currently executing hart. Harts can start at
- * any arbitrary point, it's the C library's job to ensure the code is
- * safe.
- * a1: a pointer to a description of the machine on which this code is
- * currently executing. This is probably 0 on an embedded system
- * because they tend to not be dynamically portable. As such, newlib
- * ignores this argument.
- * a2: a pointer to a function that must be run after the envirnoment has
- * been initialized, but before user code can be expected to be run.
- * If this is 0 then there is no function to be run. */
-_start:
-.cfi_startproc
-.cfi_undefined ra
-
- /* This is a bit funky: it's not usually sane for _start to return, but in
- * this case we actually want to in order to signal an error to the METAL. */
- mv s0, ra
-
- /* Before doing anything we must initialize the global pointer, as we cannot
- * safely perform any access that may be relaxed without GP being set. This
- * is done with relaxation disabled to avoid relaxing the address calculation
- * to just "addi gp, gp, 0". */
-.option push
-.option norelax
- la gp, __global_pointer$
-.option pop
-
- /* The METAL is designed for a bare-metal environment and therefor is expected
- * 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 */
- la t0, __metal_boot_hart
- bne a0, t0, _skip_init
-
- /* Embedded systems frequently require relocating the data segment before C
- * code can be run -- for example, the data segment may exist in flash upon
- * boot and then need to get relocated into a non-persistant writable memory
- * before C code can execute. If this is the case we do so here. This step
- * is optional: if the METAL provides an environment in which this relocation
- * is not necessary then it must simply set metal_segment_data_source_start to
- * be equal to metal_segment_data_target_start. */
- la t0, metal_segment_data_source_start
- la t1, metal_segment_data_target_start
- la t2, metal_segment_data_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:
-
- /* Copy the ITIM section */
- la t0, metal_segment_itim_source_start
- la t1, metal_segment_itim_target_start
- la t2, metal_segment_itim_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 ITIM writes
- complete */
- fence.i
-
- /* Zero the BSS segment. */
- la t1, metal_segment_bss_target_start
- la t2, metal_segment_bss_target_end
-
- bge t1, t2, 2f
-
-1:
-#if __riscv_xlen == 32
- sw x0, 0(t1)
- addi t1, t1, 4
- blt t1, t2, 1b
-#else
- sd x0, 0(t1)
- addi t1, t1, 8
- blt t1, t2, 1b
-#endif
-2:
-
- /* 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
- * requested to do so. */
- beqz a2, 1f
- jalr a2
-1:
-
- /* The RISC-V port only uses new-style constructors and destructors. */
- la a0, __libc_fini_array
- call atexit
- call __libc_init_array
-
-_skip_init:
-
- /* Synchronize harts so that secondary harts wait until hart 0 finishes
- initializing */
- call __metal_synchronize_harts
-
- /* Check RISC-V isa and enable FS bits if Floating Point architecture. */
- csrr a5, misa
- li a4, 0x10028
- and a5, a5, a4
- beqz a5, 1f
- csrr a5, mstatus
- lui a4, 0x2
- or a5, a5, a4
- csrw mstatus, a5
- csrwi fcsr, 0
-1:
-
- /* 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
- * instead just setup as close to a NOP as we can. */
- li a0, 1 /* argc=1 */
- la a1, argv /* argv = {"libgloss", NULL} */
- la a2, envp /* envp = {NULL} */
- call secondary_main
-
- /* Call exit to handle libc's cleanup routines. Under normal contains this
- * shouldn't even get called, but I'm still not using a tail call here
- * because returning to the METAL is the right thing to do in pathological
- * situations. */
- call exit
-
- /* And here's where we return. Again, it's a bit odd but the METAL defines
- * this as a bad idea (ie, as opposed to leaving it undefined) and at this
- * point it's really the only thing left to do. */
- mv ra, s0
- ret
-
-.cfi_endproc
-
-/* RISC-V systems always use __libc_{init,fini}_array, but for compatibility we
- * define _{init,fini} to do nothing. */
-.global _init
-.type _init, @function
-.global _fini
-.type _fini, @function
-_init:
-_fini:
- ret
-.size _init, .-_init
-.size _fini, .-_fini
-
-/* By default, secondary_main will cause secondary harts to spin forever.
- * Users can redefine secondary_main themselves to run code on secondary harts */
-.weak secondary_main
-.global secondary_main
-.type secondary_main, @function
-
-secondary_main:
- addi sp, sp, -16
-#if __riscv_xlen == 32
- sw ra, 4(sp)
-#else
- sd ra, 8(sp)
-#endif
- csrr t0, mhartid
- la t1, __metal_boot_hart
- beq t0, t1, 2f
-1:
- wfi
- j 1b
-2:
- call main
-#if __riscv_xlen == 32
- lw ra, 4(sp)
-#else
- ld ra, 8(sp)
-#endif
- addi sp, sp, 16
- ret
-
-/* This shim allows main() to be passed a set of arguments that can satisfy the
- * requirements of the C API. */
-.section .rodata.libgloss.start
-argv:
-.dc.a name
-envp:
-.dc.a 0
-name:
-.asciz "libgloss"
-
+++ /dev/null
-#include <errno.h>
-#include <sys/time.h>
-
-int
-nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-/* 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 */
-}
-
+++ /dev/null
-#include <errno.h>
-
-int
-_access(const char *file, int mode)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-
-int
-_chdir(const char *path)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-#include <sys/types.h>
-
-int
-_chmod(const char *path, mode_t mode)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <sys/types.h>
-#include <errno.h>
-
-int
-_chown(const char *path, uid_t owner, gid_t group)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-
-int
-_close(int file)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-
-int
-_execve(const char *name, char *const argv[], char *const env[])
-{
- errno = ENOMEM;
- return -1;
-}
+++ /dev/null
-#include <metal/shutdown.h>
-
-void
-_exit(int exit_status)
-{
- metal_shutdown(exit_status);
- while (1);
-}
+++ /dev/null
-#include <errno.h>
-
-int
-_faccessat(int dirfd, const char *file, int mode, int flags)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-
-int
-_fork()
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-#include <sys/stat.h>
-
-int
-_fstat(int file, struct stat *st)
-{
- errno = -ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-#include <sys/stat.h>
-
-int
-_fstatat(int dirfd, const char *file, struct stat *st, int flags)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-#include <sys/timeb.h>
-
-int
-_ftime(struct timeb *tp)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-
-char *
-_getcwd(char *buf, size_t size)
-{
- errno = -ENOSYS;
- return NULL;
-}
+++ /dev/null
-#include <errno.h>
-
-int
-_getpid()
-{
- return 1;
-}
+++ /dev/null
-#include <errno.h>
-#include <metal/timer.h>
-#include <sys/time.h>
-
-int
-_gettimeofday(struct timeval *tp, void *tzp)
-{
- int rv;
- unsigned long long mcc, timebase;
- rv = metal_timer_get_cyclecount(0, &mcc);
- if (rv != 0) {
- return -1;
- }
- rv = metal_timer_get_timebase_frequency(0, &timebase);
- if (rv != 0) {
- return -1;
- }
- tp->tv_sec = mcc / timebase;
- tp->tv_usec = mcc % timebase * 1000000 / timebase;
- return 0;
-}
+++ /dev/null
-#include <unistd.h>
-
-int
-_isatty(int file)
-{
- return (file == STDOUT_FILENO);
-}
+++ /dev/null
-#include <errno.h>
-
-int
-_kill(int pid, int sig)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-
-int _link(const char *old_name, const char *new_name)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <sys/types.h>
-#include <errno.h>
-
-off_t
-_lseek(int file, off_t ptr, int dir)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-#include <sys/stat.h>
-
-int _lstat(const char *file, struct stat *st)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-
-int
-_open(const char *name, int flags, int mode)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-
-int
-_openat(int dirfd, const char *name, int flags, int mode)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <sys/types.h>
-#include <errno.h>
-
-ssize_t
-_read(int file, void *ptr, size_t len)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <sys/types.h>
-
-/* brk is handled entirely within the C library. This limits METAL programs that
- * use the C library to be disallowed from dynamically allocating memory
- * without talking to the C library, but that sounds like a sane way to go
- * about it. Note that there is no error checking anywhere in this file, users
- * will simply get the relevant error when actually trying to use the memory
- * that's been allocated. */
-extern char metal_segment_heap_target_start;
-extern char metal_segment_heap_target_end;
-static char *brk = &metal_segment_heap_target_start;
-
-int
-_brk(void *addr)
-{
- brk = addr;
- return 0;
-}
-
-char *
-_sbrk(ptrdiff_t incr)
-{
- char *old = brk;
-
- /* If __heap_size == 0, we can't allocate memory on the heap */
- if(&metal_segment_heap_target_start == &metal_segment_heap_target_end) {
- return (void *)-1;
- }
-
- /* Don't move the break past the end of the heap */
- if ((brk + incr) < &metal_segment_heap_target_end) {
- brk += incr;
- } else {
- brk = &metal_segment_heap_target_end;
- return (void *)-1;
- }
-
- return old;
-}
+++ /dev/null
-#include <errno.h>
-#include <sys/stat.h>
-
-int
-_stat(const char *file, struct stat *st)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <unistd.h>
-#include <time.h>
-
-/* Get configurable system variables. */
-
-long
-_sysconf(int name)
-{
- switch (name)
- {
- case _SC_CLK_TCK:
- return CLOCKS_PER_SEC;
- }
-
- return -1;
-}
+++ /dev/null
-#include <sys/times.h>
-#include <sys/time.h>
-#include <metal/timer.h>
-#include <errno.h>
-
-extern int _gettimeofday(struct timeval *, void *);
-
-/* Timing information for current process. From
- newlib/libc/include/sys/times.h the tms struct fields are as follows:
-
- - clock_t tms_utime : user clock ticks
- - clock_t tms_stime : system clock ticks
- - clock_t tms_cutime : children's user clock ticks
- - clock_t tms_cstime : children's system clock ticks
-
- Since maven does not currently support processes we set both of the
- children's times to zero. Eventually we might want to separately
- account for user vs system time, but for now we just return the total
- number of cycles since starting the program. */
-clock_t
-_times(struct tms *buf)
-{
- int rv;
- // when called for the first time, initialize t0
- static struct timeval t0;
- if (t0.tv_sec == 0 && t0.tv_usec == 0)
- _gettimeofday (&t0, 0);
-
- struct timeval t;
- _gettimeofday (&t, 0);
-
- unsigned long long timebase;
- rv = metal_timer_get_timebase_frequency(0, &timebase);
- if (rv != 0) {
- return -1;
- }
-
- long long utime = (t.tv_sec - t0.tv_sec) * 1000000 + (t.tv_usec - t0.tv_usec);
- buf->tms_utime = utime * timebase / 1000000;
- buf->tms_stime = buf->tms_cstime = buf->tms_cutime = 0;
- return 0;
-}
+++ /dev/null
-#include <errno.h>
-
-int
-_unlink(const char *name)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-struct utimbuf;
-
-int
-_utime(const char *path, const struct utimbuf *times)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <errno.h>
-
-int _wait(int *status)
-{
- errno = ENOSYS;
- return -1;
-}
+++ /dev/null
-#include <metal/tty.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <unistd.h>
-
-/* Write to a file. */
-ssize_t
-_write(int file, const void *ptr, size_t len)
-{
- if (file != STDOUT_FILENO) {
- errno = ENOSYS;
- return -1;
- }
-
- const char *bptr = ptr;
- for (size_t i = 0; i < len; ++i)
- metal_tty_putc(bptr[i]);
- return 0;
-}
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__BUTTON_H
-#define METAL__BUTTON_H
-
-/*!
- * @file button.h
- * API for interfacing with physical buttons
- */
-
-#include <metal/interrupt.h>
-
-struct metal_button;
-
-struct metal_button_vtable {
- int (*button_exist)(struct metal_button *button, char *label);
- struct metal_interrupt* (*interrupt_controller)(struct metal_button *button);
- int (*get_interrupt_id)(struct metal_button *button);
-};
-
-/*!
- * @brief A button device handle
- *
- * A `struct metal_button` is an implementation-defined object which represents
- * a button on a development board.
- */
-struct metal_button {
- const struct metal_button_vtable *vtable;
-};
-
-/*!
- * @brief Get a reference to a button
- *
- * @param label The DeviceTree label for the button
- * @return A handle for the button
- */
-struct metal_button* metal_button_get(char *label);
-
-
-/*!
- * @brief Get the interrupt controller for a button
- *
- * @param button The handle for the button
- * @return A pointer to the interrupt controller responsible for handling
- * button interrupts.
- */
-__inline__ struct metal_interrupt*
- metal_button_interrupt_controller(struct metal_button *button) { return button->vtable->interrupt_controller(button); }
-
-/*!
- * @brief Get the interrupt id for a button
- *
- * @param button The handle for the 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); }
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__CACHE_H
-#define METAL__CACHE_H
-
-/*!
- * @file cache.h
- *
- * @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
- */
-struct metal_cache {
- const struct __metal_cache_vtable *vtable;
-};
-
-/*!
- * @brief Initialize a cache
- * @param cache The handle for the cache to initialize
- * @param ways The number of ways to enable
- *
- * Initializes a cache with the requested number of ways enabled.
- */
-__inline__ void metal_cache_init(struct metal_cache *cache, int ways) {
- cache->vtable->init(cache, ways);
-}
-
-/*!
- * @brief Get the current number of enabled cache ways
- * @param cache The handle for the cache
- * @return The current number of enabled cache ways
- */
-__inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache) {
- return cache->vtable->get_enabled_ways(cache);
-}
-
-/*!
- * @brief Enable the requested number of cache ways
- * @param cache The handle for the cache
- * @param ways The number of ways to enabled
- * @return 0 if the ways are successfully enabled
- */
-__inline__ int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways) {
- return cache->vtable->set_enabled_ways(cache, 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);
-
-/*!
- * @brief Flush icache for L1 on the requested core
- * @param hartid The core to flush
- * @return None
- */
-void metal_icache_l1_flush(int hartid);
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__CLOCK_H
-#define METAL__CLOCK_H
-
-/*!
- * @file clock.h
- * @brief API for manipulating clock sources
- *
- * The clock interface allows for controlling the rate of various clocks in the system.
- */
-
-struct metal_clock;
-
-#include <stddef.h>
-
-/* The generic interface to all clocks. */
-struct __metal_clock_vtable {
- long (*get_rate_hz)(const struct metal_clock *clk);
- long (*set_rate_hz)(struct metal_clock *clk, long hz);
-};
-
-/*!
- * @brief Function signature of clock rate change callbacks
- */
-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 Type for the linked list of callbacks for clock rate changes
- */
-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
- * @brief The handle for a clock
- *
- * Clocks are defined as a pointer to a `struct metal_clock`, the contents of which
- * are implementation defined. Users of the clock interface must call 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
- * defined, making it impossible to call any of these functions without invoking
- * implementation-defined behavior.
- */
-struct metal_clock {
- const struct __metal_clock_vtable *vtable;
-
- /* Pre-rate change callback linked list */
- metal_clock_callback *_pre_rate_change_callback;
-
- /* Post-rate change callback linked list */
- metal_clock_callback *_post_rate_change_callback;
-};
-
-/*!
- * @brief Returns the current rate of the given clock
- *
- * @param clk The handle for the clock
- * @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); }
-
-/*!
- * @brief Set the current rate of a clock
- *
- * @param clk The handle for the clock
- * @param hz The desired rate in Hz
- * @return The new rate of the clock in Hz.
- *
- * Attempts to set the current rate of the given clock to as close as possible
- * to the given rate in Hz. Returns the actual value that's been selected, which
- * could be anything!
- *
- * Prior to and after the rate change of the clock, this will call the registered
- * pre- and post-rate change callbacks.
- */
-__inline__ long metal_clock_set_rate_hz(struct metal_clock *clk, long hz)
-{
- _metal_clock_call_all_callbacks(clk->_pre_rate_change_callback);
-
- long out = clk->vtable->set_rate_hz(clk, hz);
-
- _metal_clock_call_all_callbacks(clk->_post_rate_change_callback);
-
- return out;
-}
-
-/*!
- * @brief Register a callback that must be called before a rate change
- *
- * @param clk The handle for the clock
- * @param cb The callback to be registered
- */
-__inline__ void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb)
-{
- clk->_pre_rate_change_callback = _metal_clock_append_to_callbacks(clk->_pre_rate_change_callback, cb);
-}
-
-/*!
- * @brief Registers a callback that must be called after a rate change
- *
- * @param clk The handle for the clock
- * @param cb The callback to be registered
- */
-__inline__ void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb)
-{
- clk->_post_rate_change_callback = _metal_clock_append_to_callbacks(clk->_post_rate_change_callback, cb);
-}
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__COMPILER_H
-#define METAL__COMPILER_H
-
-#define __METAL_DECLARE_VTABLE(type) \
- extern const struct type type;
-
-#define __METAL_DEFINE_VTABLE(type) \
- const struct type type
-
-#define __METAL_GET_FIELD(reg, mask) \
- (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
-
-/* Set field with mask for a given value */
-#define __METAL_SET_FIELD(reg, mask, val) \
- (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
-
-void _metal_trap(int ecode);
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-
-/* SPDX-License-Identifier: Apache-2.0 */
-
-/*! @file cpu.h
- * @brief API for accessing CPU capabilities.
- */
-
-#ifndef METAL__CPU_H
-#define METAL__CPU_H
-
-#include <stdint.h>
-#include <metal/interrupt.h>
-
-struct metal_cpu;
-
-/*!
- * @brief Function signature for exception handlers
- */
-typedef void (*metal_exception_handler_t) (struct metal_cpu *cpu, int ecode);
-
-struct metal_cpu_vtable {
- unsigned long long (*mcycle_get)(struct metal_cpu *cpu);
- unsigned long long (*timebase_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);
- struct metal_interrupt* (*tmr_controller_interrupt)(struct metal_cpu *cpu);
- int (*get_tmr_interrupt_id)(struct metal_cpu *cpu);
- struct metal_interrupt* (*sw_controller_interrupt)(struct metal_cpu *cpu);
- int (*get_sw_interrupt_id)(struct metal_cpu *cpu);
- int (*set_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);
- struct metal_interrupt* (*controller_interrupt)(struct metal_cpu *cpu);
- int (*exception_register)(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler);
- int (*get_ilen)(struct metal_cpu *cpu, uintptr_t epc);
- uintptr_t (*get_epc)(struct metal_cpu *cpu);
- int (*set_epc)(struct metal_cpu *cpu, uintptr_t epc);
-};
-
-/*! @brief A device handle for a CPU hart
- */
-struct metal_cpu {
- const struct metal_cpu_vtable *vtable;
-};
-
-/*! @brief Get a reference to a CPU hart
- *
- * @param hartid The ID of the desired CPU hart
- * @return A pointer to the CPU device handle
- */
-struct metal_cpu* metal_cpu_get(unsigned int hartid);
-
-/*! @brief Get the hartid of the CPU hart executing this function
- *
- * @return The hartid of the current CPU hart */
-int metal_cpu_get_current_hartid(void);
-
-/*! @brief Get the number of CPU harts
- *
- * @return The number of CPU harts */
-int metal_cpu_get_num_harts(void);
-
-/*! @brief Get the CPU cycle count timer value
- *
- * Get the value of the cycle count timer for a given CPU
- *
- * @param cpu The CPU device handle
- * @return The value of the CPU cycle count timer
- */
-__inline__ unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu)
-{ return cpu->vtable->mcycle_get(cpu); }
-
-/*! @brief Get the timebase of the CPU
- *
- * Get the value of the timebase of the cycle count timer
- *
- * @param cpu The CPU device handle
- * @return The value of the cycle count timer timebase
- */
-__inline__ unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu)
-{ return cpu->vtable->timebase_get(cpu); }
-
-/*! @brief Get the value of the mtime RTC
- *
- * Get the value of the mtime real-time clock. The CPU interrupt controller
- * must be initialized before this function is called or the return value
- * will be 0.
- *
- * @param cpu The CPU device handle
- * @return The value of mtime, or 0 if failure
- */
-__inline__ unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu)
-{ return cpu->vtable->mtime_get(cpu); }
-
-/*! @brief Set the value of the RTC mtimecmp RTC
- *
- * Set the value of the mtime real-time clock compare register. The CPU
- * interrupt controller must be initialized before this function is called
- * or the return value will be -1;
- *
- * @param cpu The CPU device handle
- * @param time The value to set the compare register to
- * @return The value of mtimecmp or -1 if error
- */
-__inline__ int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time)
-{ return cpu->vtable->mtimecmp_set(cpu, time); }
-
-/*! @brief Get a reference to RTC timer interrupt controller
- *
- * Get a reference to the interrupt controller for the real-time clock interrupt.
- * The controller returned by this function must be initialized before any interrupts
- * are registered or enabled with it.
- *
- * @param cpu The CPU device handle
- * @return A pointer to the timer interrupt handle
- */
-__inline__ struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu)
-{ return cpu->vtable->tmr_controller_interrupt(cpu); }
-
-/*! @brief Get the RTC timer interrupt id
- *
- * Get the interrupt ID of the real-time clock interrupt
- *
- * @param cpu The CPU device handle
- * @return The timer interrupt ID
- */
-__inline__ int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu)
-{ return cpu->vtable->get_tmr_interrupt_id(cpu); }
-
-/*! @brief Get a reference to the software interrupt controller
- *
- * Get a reference to the interrupt controller for the software/inter-process
- * interrupt. The controller returned by this function must be initialized before
- * any interrupts are registered or enabled with it.
- *
- * @param cpu The CPU device handle
- * @return A pointer to the software interrupt handle
- */
-__inline__ struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu)
-{ return cpu->vtable->sw_controller_interrupt(cpu); }
-
-/*! @brief Get the software interrupt id
- *
- * Get the interrupt ID for the software/inter-process interrupt
- *
- * @param cpu The CPU device handle
- * @return the software interrupt ID
- */
-__inline__ int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu)
-{ return cpu->vtable->get_sw_interrupt_id(cpu); }
-
-/*!
- * @brief Set the inter-process interrupt for a hart
- *
- * Trigger a software/inter-process interrupt for a hart. The CPU interrupt
- * controller for the CPU handle passed to this function must be initialized
- * before this function is called.
- *
- * @param cpu The CPU device handle
- * @param hartid The CPU hart ID to be interrupted
- * @return 0 upon success
- */
-__inline__ int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid)
-{ return cpu->vtable->set_sw_ipi(cpu, hartid); }
-
-/*!
- * @brief Clear the inter-process interrupt for a hart
- *
- * Clear the software/inter-process interrupt for a hart. The CPU interrupt
- * controller for the CPU handle passed to this function must be initialized
- * before this function is called.
- *
- * @param cpu The CPU device handle
- * @param hartid The CPU hart ID to clear
- * @return 0 upon success
- */
-__inline__ int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid)
-{ return cpu->vtable->clear_sw_ipi(cpu, hartid); }
-
-/*!
- * @brief Get the value of MSIP for the given hart
- *
- * Get the value of the machine software interrupt pending bit for
- * the given hart. The CPU interrupt controller for the CPU handle passed
- * as argument to this function must be initialized before this function
- * is called.
- *
- * @param cpu the CPU device handle
- * @param hartid The CPU hart to read
- * @return 0 upon success
- */
-__inline__ int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid)
-{ return cpu->vtable->get_msip(cpu, hartid); }
-
-/*!
- * @brief Get the interrupt controller for the CPU
- *
- * Get the CPU interrupt controller. The controller returned by this
- * function must be initialized before any interrupts are registered
- * or enabled and before any exception handlers are registered with
- * this CPU.
- *
- * @param cpu The CPU device handle
- * @return The handle for the CPU interrupt controller
- */
-__inline__ struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu)
-{ return cpu->vtable->controller_interrupt(cpu); }
-
-/*!
- * @brief Register an exception handler
- *
- * Register an exception handler for the CPU. The CPU interrupt controller must be initialized
- * before this function is called.
- *
- * @param cpu The CPU device handle
- * @param ecode The exception code to register a handler for
- * @param handler Callback function for the exception handler
- * @return 0 upon success
- */
-__inline__ int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler)
-{ return cpu->vtable->exception_register(cpu, ecode, handler); }
-
-/*!
- * @brief Get the length of an instruction in bytes
- *
- * Get the length of an instruction in bytes.
- *
- * On RISC-V platforms, this is useful for detecting whether an instruction is
- * compressed (2 bytes long) or uncompressed (4 bytes long).
- *
- * This function is useful in conjuction with `metal_cpu_get_exception_pc()`
- * and `metal_cpu_set_exception_pc()` in order to cause the exception handler to
- * return execution after the faulting instruction.
- *
- * @param cpu The CPU device handle
- * @param epc The address of the instruction to measure
- * @return the length of the instruction in bytes
- */
-__inline__ int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
-{ return cpu->vtable->get_ilen(cpu, epc); }
-
-/*!
- * @brief Get the program counter of the current exception.
- *
- * This function must be called within an exception handler. The behavior is
- * undefined outside of an exception handler.
- *
- * @param cpu The CPU device handle
- * @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)
-{ return cpu->vtable->get_epc(cpu); }
-
-/*!
- * @brief Set the exception program counter
- *
- * This function must be called within an exception handler. The behavior
- * is undefined outside of an exception handler.
- *
- * This function can be used to cause an exception handler to return execution
- * to an address other than the one that caused the exception.
- *
- * @param cpu the CPU device handle
- * @param epc The address to set the exception program counter to
- * @return 0 upon success
- */
-__inline__ int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc)
-{ return cpu->vtable->set_epc(cpu, epc); }
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__FIXED_CLOCK_H
-#define METAL__DRIVERS__FIXED_CLOCK_H
-
-struct __metal_driver_fixed_clock;
-
-#include <metal/compiler.h>
-#include <metal/clock.h>
-
-struct __metal_driver_vtable_fixed_clock {
- struct __metal_clock_vtable clock;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_fixed_clock)
-
-struct __metal_driver_fixed_clock {
- struct metal_clock clock;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__FIXED_FACTOR_CLOCK_H
-#define METAL__DRIVERS__FIXED_FACTOR_CLOCK_H
-
-struct __metal_driver_fixed_factor_clock;
-
-#include <metal/compiler.h>
-#include <metal/clock.h>
-
-struct __metal_driver_vtable_fixed_factor_clock {
- struct __metal_clock_vtable clock;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_fixed_factor_clock)
-
-struct __metal_driver_fixed_factor_clock {
- struct metal_clock clock;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__RISCV_CLINT0_H
-#define METAL__DRIVERS__RISCV_CLINT0_H
-
-#include <metal/compiler.h>
-#include <metal/drivers/riscv_cpu.h>
-
-struct __metal_driver_vtable_riscv_clint0 {
- struct metal_interrupt_vtable clint_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_clint0)
-
-#define __METAL_MACHINE_MACROS
-#include <metal/machine.h>
-struct __metal_driver_riscv_clint0 {
- struct metal_interrupt controller;
- int init_done;
-};
-#undef __METAL_MACHINE_MACROS
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__RISCV_CPU_H
-#define METAL__DRIVERS__RISCV_CPU_H
-
-#include <stdint.h>
-#include <metal/cpu.h>
-#include <metal/compiler.h>
-
-#define METAL_MAX_CORES 8
-#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_DEFAULT_RTC_FREQ 32768
-
-#define METAL_DISABLE 0
-#define METAL_ENABLE 1
-
-#define METAL_ISA_A_EXTENSIONS 0x0001
-#define METAL_ISA_C_EXTENSIONS 0x0004
-#define METAL_ISA_D_EXTENSIONS 0x0008
-#define METAL_ISA_E_EXTENSIONS 0x0010
-#define METAL_ISA_F_EXTENSIONS 0x0020
-#define METAL_ISA_G_EXTENSIONS 0x0040
-#define METAL_ISA_I_EXTENSIONS 0x0100
-#define METAL_ISA_M_EXTENSIONS 0x1000
-#define METAL_ISA_N_EXTENSIONS 0x2000
-#define METAL_ISA_Q_EXTENSIONS 0x10000
-#define METAL_ISA_S_EXTENSIONS 0x40000
-#define METAL_ISA_U_EXTENSIONS 0x100000
-#define METAL_ISA_V_EXTENSIONS 0x200000
-#define METAL_ISA_XL32_EXTENSIONS 0x40000000UL
-#define METAL_ISA_XL64_EXTENSIONS 0x8000000000000000UL
-#define METAL_ISA_XL128_EXTENSIONS 0xC000000000000000UL
-
-#define METAL_MTVEC_DIRECT 0x00
-#define METAL_MTVEC_VECTORED 0x01
-#define METAL_MTVEC_CLIC 0x02
-#define METAL_MTVEC_CLIC_VECTORED 0x03
-#define METAL_MTVEC_CLIC_RESERVED 0x3C
-#define METAL_MTVEC_MASK 0x3F
-#if __riscv_xlen == 32
-#define METAL_MCAUSE_INTR 0x80000000UL
-#define METAL_MCAUSE_CAUSE 0x000003FFUL
-#else
-#define METAL_MCAUSE_INTR 0x8000000000000000UL
-#define METAL_MCAUSE_CAUSE 0x00000000000003FFUL
-#endif
-#define METAL_MCAUSE_MINHV 0x40000000UL
-#define METAL_MCAUSE_MPP 0x30000000UL
-#define METAL_MCAUSE_MPIE 0x08000000UL
-#define METAL_MCAUSE_MPIL 0x00FF0000UL
-#define METAL_MSTATUS_MIE 0x00000008UL
-#define METAL_MSTATUS_MPIE 0x00000080UL
-#define METAL_MSTATUS_MPP 0x00001800UL
-#define METAL_MSTATUS_FS_INIT 0x00002000UL
-#define METAL_MSTATUS_FS_CLEAN 0x00004000UL
-#define METAL_MSTATUS_FS_DIRTY 0x00006000UL
-#define METAL_MSTATUS_MPRV 0x00020000UL
-#define METAL_MSTATUS_MXR 0x00080000UL
-#define METAL_MINTSTATUS_MIL 0xFF000000UL
-#define METAL_MINTSTATUS_SIL 0x0000FF00UL
-#define METAL_MINTSTATUS_UIL 0x000000FFUL
-
-#define METAL_LOCAL_INTR(X) (16 + X)
-#define METAL_MCAUSE_EVAL(cause) (cause & METAL_MCAUSE_INTR)
-#define METAL_INTERRUPT(cause) (METAL_MCAUSE_EVAL(cause) ? 1 : 0)
-#define METAL_EXCEPTION(cause) (METAL_MCAUSE_EVAL(cause) ? 0 : 1)
-#define METAL_SW_INTR_EXCEPTION (METAL_MCAUSE_INTR + 3)
-#define METAL_TMR_INTR_EXCEPTION (METAL_MCAUSE_INTR + 7)
-#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_RESERVE0 1
-#define METAL_LOCAL_INTR_RESERVE1 2
-#define METAL_LOCAL_INTR_RESERVE2 4
-#define METAL_LOCAL_INTERRUPT_SW 8 /* Bit3 0x008 */
-#define METAL_LOCAL_INTR_RESERVE4 16
-#define METAL_LOCAL_INTR_RESERVE5 32
-#define METAL_LOCAL_INTR_RESERVE6 64
-#define METAL_LOCAL_INTERRUPT_TMR 128 /* Bit7 0x080 */
-#define METAL_LOCAL_INTR_RESERVE8 256
-#define METAL_LOCAL_INTR_RESERVE9 512
-#define METAL_LOCAL_INTR_RESERVE10 1024
-#define METAL_LOCAL_INTERRUPT_EXT 2048 /* Bit11 0x800 */
-/* Bit12 to Bit15 are Reserved */
-#define METAL_LOCAL_INTERRUPT(X) (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 {
- METAL_MACHINE_PRIVILEGE_MODE,
- METAL_SUPERVISOR_PRIVILEGE_MODE,
- METAL_USER_PRIVILEGE_MODE,
-} metal_privilege_mode_e;
-
-typedef enum {
- METAL_INTERRUPT_ID_BASE,
- METAL_INTERRUPT_ID_SW = (METAL_INTERRUPT_ID_BASE + 3),
- METAL_INTERRUPT_ID_TMR = (METAL_INTERRUPT_ID_BASE + 7),
- METAL_INTERRUPT_ID_EXT = (METAL_INTERRUPT_ID_BASE + 11),
- METAL_INTERRUPT_ID_CSW = (METAL_INTERRUPT_ID_BASE + 12),
- METAL_INTERRUPT_ID_LC0 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(0)),
- METAL_INTERRUPT_ID_LC1 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(1)),
- METAL_INTERRUPT_ID_LC2 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(2)),
- METAL_INTERRUPT_ID_LC3 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(3)),
- METAL_INTERRUPT_ID_LC4 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(4)),
- METAL_INTERRUPT_ID_LC5 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(5)),
- METAL_INTERRUPT_ID_LC6 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(6)),
- METAL_INTERRUPT_ID_LC7 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(7)),
- METAL_INTERRUPT_ID_LC8 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(8)),
- METAL_INTERRUPT_ID_LC9 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(9)),
- METAL_INTERRUPT_ID_LC10 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(10)),
- METAL_INTERRUPT_ID_LC11 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(11)),
- METAL_INTERRUPT_ID_LC12 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(12)),
- METAL_INTERRUPT_ID_LC13 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(13)),
- METAL_INTERRUPT_ID_LC14 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(14)),
- METAL_INTERRUPT_ID_LC15 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(15)),
- METAL_INTERRUPT_ID_LCMX,
- METAL_INTERRUPT_ID_GL0 = METAL_INTERRUPT_ID_LCMX,
- METAL_INTERRUPT_ID_GLMX = (METAL_MCAUSE_CAUSE + 1),
-} metal_interrupt_id_e;
-
-typedef enum {
- METAL_IAM_EXCEPTION_CODE, /* Instruction address misaligned */
- METAL_IAF_EXCEPTION_CODE, /* Instruction access faultd */
- METAL_II_EXCEPTION_CODE, /* Illegal instruction */
- METAL_BREAK_EXCEPTION_CODE, /* Breakpoint */
- METAL_LAM_EXCEPTION_CODE, /* Load address misaligned */
- METAL_LAF_EXCEPTION_CODE, /* Load access fault */
- METAL_SAMOAM_EXCEPTION_CODE, /* Store/AMO address misaligned */
- METAL_SAMOAF_EXCEPTION_CODE, /* Store/AMO access fault */
- METAL_ECALL_U_EXCEPTION_CODE, /* Environment call from U-mode */
- METAL_R9_EXCEPTION_CODE, /* Reserved */
- METAL_R10_EXCEPTION_CODE, /* Reserved */
- METAL_ECALL_M_EXCEPTION_CODE, /* Environment call from M-mode */
- METAL_MAX_EXCEPTION_CODE,
-} metal_exception_code_e;
-
-typedef enum {
- METAL_TIMER_MTIME_GET = 1,
- METAL_SOFTWARE_IPI_CLEAR,
- METAL_SOFTWARE_IPI_SET,
- METAL_SOFTWARE_MSIP_GET,
- METAL_MAX_INTERRUPT_GET,
- METAL_INDEX_INTERRUPT_GET,
-} metal_interrup_cmd_e;
-
-typedef struct __metal_interrupt_data {
- long long pad : 64;
- metal_interrupt_handler_t handler;
- void *sub_int;
- void *exint_data;
-} __metal_interrupt_data;
-
-/* CPU interrupt controller */
-
-uintptr_t __metal_myhart_id(void);
-
-struct __metal_driver_vtable_riscv_cpu_intc {
- struct metal_interrupt_vtable controller_vtable;
-};
-
-
-void __metal_interrupt_global_enable(void);
-void __metal_interrupt_global_disable(void);
-metal_vector_mode __metal_controller_interrupt_vector_mode(void);
-void __metal_controller_interrupt_vector(metal_vector_mode mode, void *vec_table);
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_cpu_intc)
-
-struct __metal_driver_riscv_cpu_intc {
- struct metal_interrupt controller;
- int init_done;
- uintptr_t metal_mtvec_table[METAL_MAX_MI];
- __metal_interrupt_data metal_int_table[METAL_MAX_MI];
- metal_exception_handler_t metal_exception_table[METAL_MAX_ME];
-};
-
-/* CPU driver*/
-struct __metal_driver_vtable_cpu {
- struct metal_cpu_vtable cpu_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_cpu)
-
-struct __metal_driver_cpu {
- struct metal_cpu cpu;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__RISCV_PLIC0_H
-#define METAL__DRIVERS__RISCV_PLIC0_H
-
-#include <metal/compiler.h>
-#include <metal/drivers/riscv_cpu.h>
-
-#define METAL_PLIC_SOURCE_MASK 0x1F
-#define METAL_PLIC_SOURCE_SHIFT 5
-#define METAL_PLIC_SOURCE_PRIORITY_SHIFT 2
-#define METAL_PLIC_SOURCE_PENDING_SHIFT 0
-
-struct __metal_driver_vtable_riscv_plic0 {
- struct metal_interrupt_vtable plic_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_plic0)
-
-#define __METAL_MACHINE_MACROS
-#include <metal/machine.h>
-struct __metal_driver_riscv_plic0 {
- struct metal_interrupt controller;
- int init_done;
- metal_interrupt_handler_t metal_exint_table[__METAL_PLIC_SUBINTERRUPTS];
- __metal_interrupt_data metal_exdata_table[__METAL_PLIC_SUBINTERRUPTS];
-};
-#undef __METAL_MACHINE_MACROS
-
-#endif
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_CCACHE0_H
-#define METAL__DRIVERS__SIFIVE_CCACHE0_H
-
-#include <metal/cache.h>
-#include <metal/compiler.h>
-
-struct __metal_driver_vtable_sifive_ccache0 {
- struct __metal_cache_vtable cache;
-};
-
-struct __metal_driver_sifive_ccache0;
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_ccache0)
-
-struct __metal_driver_sifive_ccache0 {
- struct metal_cache cache;
-};
-
-#endif
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_CLIC0_H
-#define METAL__DRIVERS__SIFIVE_CLIC0_H
-
-#include <metal/compiler.h>
-#include <metal/drivers/riscv_cpu.h>
-
-#define METAL_CLIC_MAX_NMBITS 2
-#define METAL_CLIC_MAX_NLBITS 8
-#define METAL_CLIC_MAX_NVBITS 1
-
-#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MMODE 0x00
-#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE1 0x20
-#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_SMODE2 0x40
-#define METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MASK 0x60
-#define METAL_SIFIVE_CLIC0_CLICCFG_NLBITS_MASK 0x1E
-#define METAL_SIFIVE_CLIC0_CLICCFG_NVBIT_MASK 0x01
-
-#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_MAX_INTERRUPT_LEVEL ((1 << METAL_CLIC_MAX_NLBITS) - 1)
-
-struct __metal_driver_vtable_sifive_clic0 {
- struct metal_interrupt_vtable clic_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_clic0)
-
-#define __METAL_MACHINE_MACROS
-#include <metal/machine.h>
-struct __metal_driver_sifive_clic0 {
- struct metal_interrupt controller;
- int init_done;
- int pad[14];
- metal_interrupt_vector_handler_t metal_mtvt_table[__METAL_CLIC_SUBINTERRUPTS];
- __metal_interrupt_data metal_exint_table[__METAL_CLIC_SUBINTERRUPTS];
-};
-#undef __METAL_MACHINE_MACROS
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef 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/io.h>
-
-struct __metal_driver_vtable_sifive_fe310_g000_hfrosc {
- struct __metal_clock_vtable clock;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfrosc)
-
-struct __metal_driver_sifive_fe310_g000_hfrosc {
- struct metal_clock clock;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_HFXOSC_H
-#define METAL__DRIVERS__SIFIVE_FE310_G000_HFXOSC_H
-
-#include <metal/clock.h>
-#include <metal/drivers/sifive_fe310-g000_prci.h>
-
-struct __metal_driver_vtable_sifive_fe310_g000_hfxosc {
- struct __metal_clock_vtable clock;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfxosc)
-
-struct __metal_driver_sifive_fe310_g000_hfxosc {
- struct metal_clock clock;
-};
-
-#endif
+++ /dev/null
-/* 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/compiler.h>
-#include <metal/clock.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
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_PLL_H
-#define METAL__DRIVERS__SIFIVE_FE310_G000_PLL_H
-
-struct __metal_driver_sifive_fe310_g000_pll;
-
-#include <metal/clock.h>
-#include <metal/drivers/sifive_fe310-g000_prci.h>
-#include <metal/machine.h>
-
-struct __metal_driver_vtable_sifive_fe310_g000_pll {
- void (*init)(struct __metal_driver_sifive_fe310_g000_pll *pll);
- struct __metal_clock_vtable clock;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_pll)
-
-struct __metal_driver_sifive_fe310_g000_pll {
- struct metal_clock clock;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_PRCI_H
-#define METAL__DRIVERS__SIFIVE_FE310_G000_PRCI_H
-
-#include <metal/compiler.h>
-#include <metal/io.h>
-
-struct __metal_driver_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 (*set_reg)(const struct __metal_driver_sifive_fe310_g000_prci *, long offset, long value);
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci)
-
-struct __metal_driver_sifive_fe310_g000_prci {
- const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable;
-};
-
-#endif
-
+++ /dev/null
-/* 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
-
-#include <metal/cache.h>
-#include <metal/compiler.h>
-
-struct __metal_driver_vtable_sifive_fu540_c000_l2 {
- struct __metal_cache_vtable cache;
-};
-
-struct __metal_driver_sifive_fu540_c000_l2;
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2)
-
-struct __metal_driver_sifive_fu540_c000_l2 {
- struct metal_cache cache;
-};
-
-#endif
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0_H
-#define METAL__DRIVERS__SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0_H
-
-#include <metal/compiler.h>
-#include <metal/drivers/riscv_cpu.h>
-
-struct __metal_driver_vtable_sifive_global_external_interrupts0 {
- struct metal_interrupt_vtable global0_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_global_external_interrupts0)
-
-struct __metal_driver_sifive_global_external_interrupts0 {
- struct metal_interrupt irc;
- int init_done;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H
-#define METAL__DRIVERS__SIFIVE_GPIO_BUTTONS_H
-
-#include <string.h>
-#include <metal/button.h>
-#include <metal/compiler.h>
-
-struct __metal_driver_vtable_sifive_button {
- struct metal_button_vtable button_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_button)
-
-struct __metal_driver_sifive_gpio_button {
- struct metal_button button;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_GPIO_LEDS_H
-#define METAL__DRIVERS__SIFIVE_GPIO_LEDS_H
-
-#include <metal/drivers/sifive_gpio0.h>
-#include <metal/led.h>
-#include <metal/compiler.h>
-
-struct __metal_driver_vtable_sifive_led {
- struct metal_led_vtable led_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_led)
-
-struct __metal_driver_sifive_gpio_led {
- struct metal_led led;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H
-#define METAL__DRIVERS__SIFIVE_GPIO_SWITCHES_H
-
-#include <metal/drivers/sifive_gpio0.h>
-#include <metal/switch.h>
-#include <metal/compiler.h>
-
-struct __metal_driver_vtable_sifive_switch {
- struct metal_switch_vtable switch_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_switch)
-
-struct __metal_driver_sifive_gpio_switch {
- struct metal_switch flip;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_GPIO0_H
-#define METAL__DRIVERS__SIFIVE_GPIO0_H
-
-#include <metal/compiler.h>
-#include <metal/gpio.h>
-
-struct __metal_driver_vtable_sifive_gpio0 {
- const struct __metal_gpio_vtable gpio;
-};
-
-//struct __metal_driver_sifive_gpio0;
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_gpio0)
-
-struct __metal_driver_sifive_gpio0 {
- struct metal_gpio gpio;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_EXTERNAL_INTERRUPTS0_H
-#define METAL__DRIVERS__SIFIVE_EXTERNAL_INTERRUPTS0_H
-
-#include <metal/compiler.h>
-#include <metal/drivers/riscv_cpu.h>
-
-struct __metal_driver_vtable_sifive_local_external_interrupts0 {
- struct metal_interrupt_vtable local0_vtable;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_local_external_interrupts0)
-
-struct __metal_driver_sifive_local_external_interrupts0 {
- struct metal_interrupt irc;
- int init_done;
-};
-
-
-#endif
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_RTC0_H
-#define METAL__DRIVERS__SIFIVE_RTC0_H
-
-#include <metal/io.h>
-#include <metal/compiler.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
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_SPI0_H
-#define METAL__DRIVERS__SIFIVE_SPI0_H
-
-#include <metal/drivers/sifive_gpio0.h>
-#include <metal/clock.h>
-#include <metal/compiler.h>
-#include <metal/io.h>
-#include <metal/spi.h>
-
-struct __metal_driver_vtable_sifive_spi0 {
- const struct metal_spi_vtable spi;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_spi0)
-
-struct __metal_driver_sifive_spi0 {
- struct metal_spi spi;
- unsigned long baud_rate;
- metal_clock_callback pre_rate_change_callback;
- metal_clock_callback post_rate_change_callback;
-};
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_TEST0_H
-#define METAL__DRIVERS__SIFIVE_TEST0_H
-
-#include <metal/compiler.h>
-#include <metal/shutdown.h>
-
-struct __metal_driver_vtable_sifive_test0 {
- const struct __metal_shutdown_vtable shutdown;
-};
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_test0)
-
-struct __metal_driver_sifive_test0 {
- struct __metal_shutdown shutdown;
-};
-
-
-#endif
+++ /dev/null
-/* 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 */
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef 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/io.h>
-#include <metal/uart.h>
-#include <metal/compiler.h>
-
-struct __metal_driver_vtable_sifive_uart0 {
- const struct metal_uart_vtable uart;
-};
-
-struct __metal_driver_sifive_uart0;
-
-__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_uart0)
-
-struct __metal_driver_sifive_uart0 {
- struct metal_uart uart;
- unsigned long baud_rate;
- metal_clock_callback pre_rate_change_callback;
- metal_clock_callback post_rate_change_callback;
-};
-
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__DRIVERS__SIFIVE_WDOG0_H
-#define METAL__DRIVERS__SIFIVE_WDOG0_H
-
-#include <metal/io.h>
-#include <metal/compiler.h>
-
-#include <metal/watchdog.h>
-#include <metal/clock.h>
-#include <metal/interrupt.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
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__GPIO_H
-#define METAL__GPIO_H
-
-#include <metal/compiler.h>
-#include <metal/interrupt.h>
-
-/*!
- * @file gpio.h
- * @brief API for manipulating general-purpose input/output
- */
-
-struct metal_gpio;
-
-struct __metal_gpio_vtable {
- 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 *);
- int (*disable_output)(struct metal_gpio *, long pins);
- int (*enable_output)(struct metal_gpio *, long pins);
- int (*output_set)(struct metal_gpio *, long value);
- int (*output_clear)(struct metal_gpio *, long value);
- int (*output_toggle)(struct metal_gpio *, long value);
- 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
- * @brief The handle for a GPIO interface
- */
-struct metal_gpio {
- const struct __metal_gpio_vtable *vtable;
-};
-
-/*!
- * @brief Get a GPIO device handle
- * @param device_num The GPIO device index
- * @return The GPIO device handle, or NULL if there is no device at that index
- */
-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
- * @param gpio The handle for the GPIO interface
- * @param pin The pin number indexed from 0
- * @return 0 if the input is successfully disabled
- */
-__inline__ int metal_gpio_disable_input(struct metal_gpio *gpio, int pin) {
- if(!gpio) {
- return 1;
- }
-
- return gpio->vtable->disable_input(gpio, (1 << pin));
-}
-
-/*!
- * @brief Enable 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 enabled
- */
-__inline__ int metal_gpio_enable_output(struct metal_gpio *gpio, int pin) {
- if(!gpio) {
- return 1;
- }
-
- 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
- * @param gpio The handle for the GPIO interface
- * @param pin The pin number indexed from 0
- * @param value The value to set the pin to
- * @return 0 if the output is successfully set
- */
-__inline__ int metal_gpio_set_pin(struct metal_gpio *gpio, int pin, int value) {
- if(!gpio) {
- return 1;
- }
-
- if(value == 0) {
- return gpio->vtable->output_clear(gpio, (1 << pin));
- } else {
- return gpio->vtable->output_set(gpio, (1 << pin));
- }
-}
-
-/*!
- * @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_input_pin(struct metal_gpio *gpio, int pin) {
- if(!gpio) {
- 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);
-
- if(value & (1 << pin)) {
- return 1;
- } else {
- return 0;
- }
-}
-
-/*!
- * @brief Clears the value of the GPIO pin
- * @param gpio The handle for the GPIO interface
- * @param pin The pin number indexed from 0
- * @return 0 if the pin is successfully cleared
- */
-__inline__ int metal_gpio_clear_pin(struct metal_gpio *gpio, int pin) {
- if(!gpio) {
- return 1;
- }
-
- return gpio->vtable->output_clear(gpio, (1 << pin));
-}
-
-/*!
- * @brief Toggles the value of the GPIO pin
- * @param gpio The handle for the GPIO interface
- * @param pin The pin number indexed from 0
- * @return 0 if the pin is successfully toggled
- */
-__inline__ int metal_gpio_toggle_pin(struct metal_gpio *gpio, int pin) {
- if(!gpio) {
- return 1;
- }
-
- return gpio->vtable->output_toggle(gpio, (1 << pin));
-}
-
-/*!
- * @brief Enables and sets the pinmux for a GPIO pin
- * @param gpio The handle for the GPIO interface
- * @param pin The bitmask for the pin to enable pinmux on
- * @param io_function The IO function to set
- * @return 0 if the pinmux is successfully set
- */
-__inline__ int metal_gpio_enable_pinmux(struct metal_gpio *gpio, int pin, int io_function) {
- if(!gpio) {
- return 1;
- }
-
- 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
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__INTERRUPT_H
-#define METAL__INTERRUPT_H
-
-/*! @file interrupt.h
- * @brief API for registering and manipulating interrupts
- */
-
-#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
- */
-typedef enum metal_vector_mode_ {
- METAL_DIRECT_MODE = 0,
- METAL_VECTOR_MODE = 1,
- METAL_SELECTIVE_NONVECTOR_MODE = 2,
- METAL_SELECTIVE_VECTOR_MODE = 3,
- METAL_HARDWARE_VECTOR_MODE = 4
-} 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 Function signature for interrupt callback handlers
- */
-typedef void (*metal_interrupt_handler_t) (int, void *);
-typedef void (*metal_interrupt_vector_handler_t) (void);
-
-struct metal_interrupt;
-
-struct metal_interrupt_vtable {
- 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,
- 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_disable)(struct metal_interrupt *controller, int id);
- int (*interrupt_vector_enable)(struct metal_interrupt *controller, int id);
- int (*interrupt_vector_disable)(struct metal_interrupt *controller, int id);
- unsigned int (*interrupt_get_threshold)(struct metal_interrupt *controller);
- 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);
- int (*command_request)(struct metal_interrupt *controller, int cmd, void *data);
- int (*mtimecmp_set)(struct metal_interrupt *controller, int hartid, unsigned long long time);
-};
-
-/*!
- * @brief A handle for an interrupt
- */
-struct metal_interrupt {
- const struct metal_interrupt_vtable *vtable;
-};
-
-/*!
- * @brief Initialize a given interrupt controller
- *
- * Initialize a given interrupt controller. This function must be called
- * before any interrupts are registered or enabled with the handler. It
- * is invalid to initialize an interrupt controller more than once.
- *
- * @param controller The handle for the interrupt controller
- */
-__inline__ void metal_interrupt_init(struct metal_interrupt *controller)
-{
- 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
- * @param controller The handle for the interrupt controller
- * @param id The interrupt ID to register
- * @param handler The interrupt handler callback
- * @param priv_data Private data for the interrupt handler
- * @return 0 upon success
- */
-__inline__ int metal_interrupt_register_handler(struct metal_interrupt *controller,
- int id,
- metal_interrupt_handler_t handler,
- void *priv_data)
-{
- return controller->vtable->interrupt_register(controller, id, handler, 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);
-}
-
-/*!
- * @brief Enable an interrupt
- * @param controller The handle for the interrupt controller
- * @param id The interrupt ID to enable
- * @return 0 upon success
- */
-__inline__ int metal_interrupt_enable(struct metal_interrupt *controller, int id)
-{
- return controller->vtable->interrupt_enable(controller, id);
-}
-
-/*!
- * @brief Disable an interrupt
- * @param controller The handle for the interrupt controller
- * @param id The interrupt ID to disable
- * @return 0 upon success
- */
-__inline__ int metal_interrupt_disable(struct metal_interrupt *controller, int 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 Enable an interrupt vector
- * @param controller The handle for the interrupt controller
- * @param id The interrupt ID to enable
- * @return 0 upon success
- */
-__inline__ int metal_interrupt_vector_enable(struct metal_interrupt *controller, int id)
-{
- return controller->vtable->interrupt_vector_enable(controller, id);
-}
-
-/*!
- * @brief Disable an interrupt vector
- * @param controller The handle for the interrupt controller
- * @param id The interrupt ID to disable
- * @return 0 upon success
- */
-__inline__ int metal_interrupt_vector_disable(struct metal_interrupt *controller, int id)
-{
- return controller->vtable->interrupt_vector_disable(controller, id);
-}
-
-/*!
- * @brief Default interrupt vector handler, that can be overriden by user
- * @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);
-}
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__IO_H
-#define METAL__IO_H
-
-/* This macro enforces that the compiler will not elide the given access. */
-#define __METAL_ACCESS_ONCE(x) (*(__typeof__(*x) volatile *)(x))
-
-/* Allows users to specify arbitrary fences. */
-#define __METAL_IO_FENCE(pred, succ) __asm__ volatile ("fence " #pred "," #succ ::: "memory");
-
-/* Types that explicitly describe an address as being used for memory-mapped
- * IO. These should only be accessed via __METAL_ACCESS_ONCE. */
-typedef unsigned char __metal_io_u8;
-typedef unsigned short __metal_io_u16;
-typedef unsigned int __metal_io_u32;
-#if __riscv_xlen >= 64
-typedef unsigned long __metal_io_u64;
-#endif
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__ITIM_H
-#define METAL__ITIM_H
-
-/*! @file itim.h
- *
- * API for manipulating ITIM allocation
- */
-
-
-/*! @def METAL_PLACE_IN_ITIM
- * @brief Link a function into the ITIM
- *
- * Link a function into the ITIM (Instruction Tightly Integrated
- * Memory) if the ITIM is present on the target device.
- */
-#define METAL_PLACE_IN_ITIM __attribute__((section(".itim")))
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__LED_H
-#define METAL__LED_H
-
-/*!
- * @file led.h
- * @brief API for manipulating LEDs
- */
-
-struct metal_led;
-
-struct metal_led_vtable {
- int (*led_exist)(struct metal_led *led, char *label);
- void (*led_enable)(struct metal_led *led);
- void (*led_on)(struct metal_led *led);
- void (*led_off)(struct metal_led *led);
- void (*led_toggle)(struct metal_led *led);
-};
-
-/*!
- * @brief A handle for an LED
- */
-struct metal_led {
- const struct metal_led_vtable *vtable;
-};
-
-/*!
- * @brief Get a handle for an 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
- */
-struct metal_led* metal_led_get(char *label);
-
-/*!
- * @brief Get a handle for a channel of an RGB LED
- * @param label The DeviceTree label for the desired LED
- * @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
- */
-struct metal_led* metal_led_get_rgb(char *label, char *color);
-
-/*!
- * @brief Enable an LED
- * @param led The handle for the LED
- */
-__inline__ void metal_led_enable(struct metal_led *led) { led->vtable->led_enable(led); }
-
-/*!
- * @brief Turn an LED on
- * @param led The handle for the LED
- */
-__inline__ void metal_led_on(struct metal_led *led) { led->vtable->led_on(led); }
-
-/*!
- * @brief Turn an LED off
- * @param led The handle for the LED
- */
-__inline__ void metal_led_off(struct metal_led *led) { led->vtable->led_off(led); }
-
-/*!
- * @brief Toggle the on/off state of an LED
- * @param led The handle for the LED
- */
-__inline__ void metal_led_toggle(struct metal_led *led) { led->vtable->led_toggle(led); }
-
-#endif
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__LOCK_H
-#define METAL__LOCK_H
-
-#include <metal/machine.h>
-#include <metal/memory.h>
-#include <metal/compiler.h>
-
-/*!
- * @file lock.h
- * @brief An API for creating and using a software lock/mutex
- */
-
-/* TODO: How can we make the exception code platform-independant? */
-#define _METAL_STORE_AMO_ACCESS_FAULT 7
-
-#define METAL_LOCK_BACKOFF_CYCLES 32
-#define METAL_LOCK_BACKOFF_EXPONENT 2
-
-/*!
- * @def METAL_LOCK_DECLARE
- * @brief Declare a 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.
- */
-#define METAL_LOCK_DECLARE(name) \
- __attribute__((section(".data.locks"))) \
- struct metal_lock name
-
-/*!
- * @brief A handle for a lock
- */
-struct metal_lock {
- int _state;
-};
-
-/*!
- * @brief Initialize a lock
- * @param lock The handle for a lock
- * @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
- * will result in a Store/AMO access fault.
- */
-__inline__ int metal_lock_init(struct metal_lock *lock) {
-#ifdef __riscv_atomic
- /* 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));
- if(!lock_mem) {
- return 1;
- }
-
- /* If the memory doesn't support atomics, report an error */
- if(!metal_memory_supports_atomics(lock_mem)) {
- return 2;
- }
-
- lock->_state = 0;
-
- return 0;
-#else
- return 3;
-#endif
-}
-
-/*!
- * @brief Take a lock
- * @param lock The handle for a lock
- * @return 0 if the lock is successfully taken
- *
- * If the lock initialization failed, attempts to take a lock will result in
- * a Store/AMO access fault.
- */
-__inline__ int metal_lock_take(struct metal_lock *lock) {
-#ifdef __riscv_atomic
- int old = 1;
- int new = 1;
-
- int backoff = 1;
- const int max_backoff = METAL_LOCK_BACKOFF_CYCLES * METAL_MAX_CORES;
-
- while(1) {
- __asm__ volatile("amoswap.w.aq %[old], %[new], (%[state])"
- : [old] "=r" (old)
- : [new] "r" (new), [state] "r" (&(lock->_state))
- : "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;
-#else
- /* Store the memory address in mtval like a normal store/amo access fault */
- __asm__ ("csrw mtval, %[state]"
- :: [state] "r" (&(lock->_state)));
-
- /* Trigger a Store/AMO access fault */
- _metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);
-
- /* If execution returns, indicate failure */
- return 1;
-#endif
-}
-
-/*!
- * @brief Give back a held lock
- * @param lock The handle for a lock
- * @return 0 if the lock is successfully given
- *
- * If the lock initialization failed, attempts to give a lock will result in
- * a Store/AMO access fault.
- */
-__inline__ int metal_lock_give(struct metal_lock *lock) {
-#ifdef __riscv_atomic
- __asm__ volatile("amoswap.w.rl x0, x0, (%[state])"
- :: [state] "r" (&(lock->_state))
- : "memory");
-
- return 0;
-#else
- /* Store the memory address in mtval like a normal store/amo access fault */
- __asm__ ("csrw mtval, %[state]"
- :: [state] "r" (&(lock->_state)));
-
- /* Trigger a Store/AMO access fault */
- _metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);
-
- /* If execution returns, indicate failure */
- return 1;
-#endif
-}
-
-#endif /* METAL__LOCK_H */
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__MEMORY_H
-#define METAL__MEMORY_H
-
-#include <stdint.h>
-#include <stddef.h>
-
-/*!
- * @file memory.h
- *
- * @brief API for enumerating memory blocks
- */
-
-struct _metal_memory_attributes {
- unsigned int R : 1;
- unsigned int W : 1;
- unsigned int X : 1;
- unsigned int C : 1;
- unsigned int A : 1;
-};
-
-/*!
- * @brief A handle for a memory block
- */
-struct metal_memory {
- const uintptr_t _base_address;
- const size_t _size;
- const struct _metal_memory_attributes _attrs;
-};
-
-/*!
- * @brief Get the memory block which services the given address
- *
- * Given a physical memory address, get a handle for the memory block to which
- * that address is mapped.
- *
- * @param address The address to query
- * @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);
-
-/*!
- * @brief Get the base address for a memory block
- * @param memory The handle for the memory block
- * @return The base address of the memory block
- */
-__inline__ uintptr_t metal_memory_get_base_address(const struct metal_memory *memory) {
- return memory->_base_address;
-}
-
-/*!
- * @brief Get the size of a memory block
- * @param memory The handle for the memory block
- * @return The size of the memory block
- */
-__inline__ size_t metal_memory_get_size(const struct metal_memory *memory) {
- return memory->_size;
-}
-
-/*!
- * @brief Query if a memory block supports atomic operations
- * @param memory The handle for the memory block
- * @return nonzero if the memory block supports atomic operations
- */
-__inline__ int metal_memory_supports_atomics(const struct metal_memory *memory) {
- return memory->_attrs.A;
-}
-
-/*!
- * @brief Query if a memory block is cacheable
- * @param memory The handle for the memory block
- * @return nonzero if the memory block is cachable
- */
-__inline__ int metal_memory_is_cachable(const struct metal_memory *memory) {
- return memory->_attrs.C;
-}
-
-#endif /* METAL__MEMORY_H */
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__PMP_H
-#define METAL__PMP_H
-
-/*!
- * @file metal/pmp.h
- *
- * @brief API for Configuring Physical Memory Protection on RISC-V Cores
- *
- * The Physical Memory Protection (PMP) interface on RISC-V cores
- * is a form of memory protection unit which allows for a finite number
- * of physical memory regions to be configured with certain access
- * permissions.
- *
- * Additional information about the use and configuration rules for PMPs
- * can be found by reading the RISC-V Privileged Architecture Specification.
- */
-
-#include <stddef.h>
-#include <metal/machine.h>
-
-struct metal_pmp;
-
-/*!
- * @brief Set of available PMP addressing modes
- */
-enum metal_pmp_address_mode {
- /*! @brief Disable the PMP region */
- METAL_PMP_OFF = 0,
- /*! @brief Use Top-of-Range mode */
- METAL_PMP_TOR = 1,
- /*! @brief Use naturally-aligned 4-byte region mode */
- METAL_PMP_NA4 = 2,
- /*! @brief Use naturally-aligned power-of-two mode */
- METAL_PMP_NAPOT = 3
-};
-
-/*!
- * @brief Configuration for a PMP region
- */
-struct metal_pmp_config {
- /*! @brief Sets whether reads to the PMP region succeed */
- unsigned int R : 1;
- /*! @brief Sets whether writes to the PMP region succeed */
- unsigned int W : 1;
- /*! @brief Sets whether the PMP region is executable */
- unsigned int X : 1;
-
- /*! @brief Sets the addressing mode of the PMP region */
- enum metal_pmp_address_mode A : 2;
-
- int _pad : 2;
-
- /*! @brief Sets whether the PMP region is locked */
- enum metal_pmp_locked {
- METAL_PMP_UNLOCKED = 0,
- METAL_PMP_LOCKED = 1
- } L : 1;
-};
-
-/*!
- * @brief A handle for the PMP device
- */
-struct metal_pmp {
- /* The minimum granularity of the PMP region. Set by metal_pmp_init */
- uintptr_t _granularity[METAL_MAX_CORES];
-};
-
-/*!
- * @brief Get the PMP device handle
- */
-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
- * @param pmp The PMP device handle to be initialized
- *
- * The PMP initialization routine is optional and may be called as many times
- * as is desired. The effect of the initialization routine is to attempt to set
- * all regions to unlocked and disabled, as well as to clear the X, W, and R
- * bits. Only the pmp configuration of the hart which executes the routine will
- * be affected.
- *
- * If any regions are fused to preset values by the implementation or locked,
- * those PMP regions will silently remain uninitialized.
- */
-void metal_pmp_init(struct metal_pmp *pmp);
-
-/*!
- * @brief Configure a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to configure
- * @param config The desired configuration of the PMP region
- * @param address The desired address of the PMP region
- * @return 0 upon success
- */
-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
- * @param pmp The PMP device handle
- * @param region The PMP region to read
- * @param config Variable to store the PMP region configuration
- * @param address Variable to store the PMP region address
- * @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);
-
-/*!
- * @brief Lock a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to lock
- * @return 0 if the region is successfully locked
- */
-int metal_pmp_lock(struct metal_pmp *pmp, unsigned int region);
-
-/*!
- * @brief Set the address for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to set
- * @param address The desired address of the PMP region
- * @return 0 if the address is successfully set
- */
-int metal_pmp_set_address(struct metal_pmp *pmp, unsigned int region, size_t address);
-
-/*!
- * @brief Get the address of a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to read
- * @return The address of the PMP region, or 0 if the region could not be read
- */
-size_t metal_pmp_get_address(struct metal_pmp *pmp, unsigned int region);
-
-/*!
- * @brief Set the addressing mode of a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to set
- * @param mode The PMP addressing mode to 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);
-
-/*!
- * @brief Get the addressing mode of a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to read
- * @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);
-
-/*!
- * @brief Set the executable bit for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to set
- * @param X The desired value of the executable bit
- * @return 0 if the executable bit is successfully set
- */
-int metal_pmp_set_executable(struct metal_pmp *pmp, unsigned int region, int X);
-
-/*!
- * @brief Get the executable bit for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to read
- * @return the value of the executable bit
- */
-int metal_pmp_get_executable(struct metal_pmp *pmp, unsigned int region);
-
-/*!
- * @brief Set the writable bit for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to set
- * @param W The desired value of the writable bit
- * @return 0 if the writable bit is successfully set
- */
-int metal_pmp_set_writeable(struct metal_pmp *pmp, unsigned int region, int W);
-
-/*!
- * @brief Get the writable bit for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to read
- * @return the value of the writable bit
- */
-int metal_pmp_get_writeable(struct metal_pmp *pmp, unsigned int region);
-
-/*!
- * @brief Set the readable bit for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to set
- * @param R The desired value of the readable bit
- * @return 0 if the readable bit is successfully set
- */
-int metal_pmp_set_readable(struct metal_pmp *pmp, unsigned int region, int R);
-
-/*!
- * @brief Set the readable bit for a PMP region
- * @param pmp The PMP device handle
- * @param region The PMP region to read
- * @return the value of the readable bit
- */
-int metal_pmp_get_readable(struct metal_pmp *pmp, unsigned int region);
-
-#endif
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__PRIVILEGE_H
-#define METAL__PRIVILEGE_H
-
-/*!
- * @file metal/privilege.h
- *
- * @brief API for manipulating the privilege mode of a RISC-V system
- *
- * Additional information about privilege modes on RISC-V systems can be found
- * by reading the RISC-V Privileged Architecture Specification v1.10.
- */
-
-#include <stdint.h>
-
-enum metal_privilege_mode {
- METAL_PRIVILEGE_USER = 0,
- METAL_PRIVILEGE_SUPERVISOR = 1,
- METAL_PRIVILEGE_MACHINE = 3,
-};
-
-#if __riscv_xlen == 32
-typedef uint32_t metal_xreg_t;
-#elif __riscv_xlen == 64
-typedef uint64_t metal_xreg_t;
-#endif
-
-#if __riscv_flen == 32
-typedef uint32_t metal_freg_t;
-#elif __riscv_flen == 64
-typedef uint64_t metal_freg_t;
-#endif
-
-struct metal_register_file {
- metal_xreg_t ra;
- metal_xreg_t sp;
- metal_xreg_t gp;
- metal_xreg_t tp;
-
- metal_xreg_t t0;
- metal_xreg_t t1;
- metal_xreg_t t2;
-
- metal_xreg_t s0;
- metal_xreg_t s1;
-
- metal_xreg_t a0;
- metal_xreg_t a1;
- metal_xreg_t a2;
- metal_xreg_t a3;
- metal_xreg_t a4;
- metal_xreg_t a5;
-#ifndef __riscv_32e
- metal_xreg_t a6;
- metal_xreg_t a7;
-
- metal_xreg_t s2;
- metal_xreg_t s3;
- metal_xreg_t s4;
- metal_xreg_t s5;
- metal_xreg_t s6;
- metal_xreg_t s7;
- metal_xreg_t s8;
- metal_xreg_t s9;
- metal_xreg_t s10;
- metal_xreg_t s11;
-
- metal_xreg_t t3;
- metal_xreg_t t4;
- metal_xreg_t t5;
- metal_xreg_t t6;
-#endif /* __riscv_32e */
-
-#ifdef __riscv_flen
- metal_freg_t ft0;
- metal_freg_t ft1;
- metal_freg_t ft2;
- metal_freg_t ft3;
- metal_freg_t ft4;
- metal_freg_t ft5;
- metal_freg_t ft6;
- metal_freg_t ft7;
-
- metal_freg_t fs0;
- metal_freg_t fs1;
-
- metal_freg_t fa0;
- metal_freg_t fa1;
- metal_freg_t fa2;
- metal_freg_t fa3;
- metal_freg_t fa4;
- metal_freg_t fa5;
- metal_freg_t fa6;
- metal_freg_t fa7;
-
- metal_freg_t fs2;
- metal_freg_t fs3;
- metal_freg_t fs4;
- metal_freg_t fs5;
- metal_freg_t fs6;
- metal_freg_t fs7;
- metal_freg_t fs8;
- metal_freg_t fs9;
- metal_freg_t fs10;
- metal_freg_t fs11;
-
- metal_freg_t ft8;
- metal_freg_t ft9;
- metal_freg_t ft10;
- metal_freg_t ft11;
-#endif /* __riscv_flen */
-};
-
-typedef void (*metal_privilege_entry_point_t)(void);
-
-void metal_privilege_drop_to_mode(enum metal_privilege_mode mode,
- struct metal_register_file regfile,
- metal_privilege_entry_point_t entry_point);
-
-#endif
+++ /dev/null
-/* 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
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__SHUTDOWN_H
-#define METAL__SHUTDOWN_H
-
-/*!
- * @file shutdown.h
- * @brief API for shutting down a machine
- */
-
-struct __metal_shutdown;
-
-struct __metal_shutdown_vtable {
- void (*exit)(const struct __metal_shutdown *sd, int code) __attribute__((noreturn));
-};
-
-struct __metal_shutdown {
- 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, int code) { sd->vtable->exit(sd, code); }
-
-/*!
- * @brief The public METAL shutdown interface
- *
- * Shuts down the machine, if the machine enables an interface for
- * shutting down. When no interface is provided, will cause the machine
- * to spin indefinitely.
- *
- * @param code The return code to set. 0 indicates program success.
- */
-void metal_shutdown(int code) __attribute__((noreturn));
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__SPI_H
-#define METAL__SPI_H
-
-struct metal_spi;
-
-/*! @brief The configuration for a SPI transfer */
-struct metal_spi_config {
- /*! @brief The protocol for the SPI transfer */
- enum {
- METAL_SPI_SINGLE,
- METAL_SPI_DUAL,
- METAL_SPI_QUAD
- } protocol;
-
- /*! @brief The polarity of the SPI transfer, equivalent to CPOL */
- unsigned int polarity : 1;
- /*! @brief The phase of the SPI transfer, equivalent to CPHA */
- unsigned int phase : 1;
- /*! @brief The endianness of the SPI transfer */
- unsigned int little_endian : 1;
- /*! @brief The active state of the chip select line */
- unsigned int cs_active_high : 1;
- /*! @brief The chip select ID to activate for the SPI transfer */
- 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 {
- 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 (*get_baud_rate)(struct metal_spi *spi);
- int (*set_baud_rate)(struct metal_spi *spi, int baud_rate);
-};
-
-/*! @brief A handle for a SPI device */
-struct metal_spi {
- const struct metal_spi_vtable *vtable;
-};
-
-/*! @brief Get a handle for a 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*/
-struct metal_spi *metal_spi_get_device(unsigned int device_num);
-
-/*! @brief Initialize a SPI device with a certain baud rate
- * @param spi The handle for the SPI device to initialize
- * @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); }
-
-/*! @brief Perform a SPI transfer
- * @param spi The handle for the SPI device to perform the transfer
- * @param config The configuration for the SPI 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 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
- */
-__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);
-}
-
-/*! @brief Get the current baud rate of the SPI device
- * @param spi The handle for the SPI device
- * @return The baud rate in Hz
- */
-__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
- * @param spi The handle for the SPI device
- * @param baud_rate The desired baud rate of the SPI device
- * @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); }
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__SWITCH_H
-#define METAL__SWITCH_H
-
-/*!
- * @file switch.h
- * @brief API for reading toggle switches
- */
-
-#include <metal/interrupt.h>
-
-struct metal_switch;
-
-struct metal_switch_vtable {
- int (*switch_exist)(struct metal_switch *sw, char *label);
- struct metal_interrupt* (*interrupt_controller)(struct metal_switch *sw);
- int (*get_interrupt_id)(struct metal_switch *sw);
-};
-
-/*!
- * @brief A handle for a switch
- */
-struct metal_switch {
- const struct metal_switch_vtable *vtable;
-};
-
-/*!
- * @brief Get a handle for a 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
- */
-struct metal_switch* metal_switch_get(char *label);
-
-/*!
- * @brief Get the interrupt controller for a switch
- * @param sw The handle for the switch
- * @return The interrupt controller handle
- */
-__inline__ struct metal_interrupt*
- metal_switch_interrupt_controller(struct metal_switch *sw) { return sw->vtable->interrupt_controller(sw); }
-
-/*!
- * @brief Get the interrupt id for a switch
- * @param sw The handle 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); }
-
-#endif
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__TIME_H
-#define METAL__TIME_H
-
-#include <time.h>
-
-/*!
- * @file time.h
- * @brief API for dealing with time
- */
-
-int metal_gettimeofday(struct timeval *tp, void *tzp);
-
-time_t metal_time(void);
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__TIMER_H
-#define METAL__TIMER_H
-
-/*!
- * @file timer.h
- * @brief API for reading and manipulating the machine timer
- */
-
-/*!
- * @brief Read the machine cycle count
- * @param hartid The hart ID to read the cycle count of
- * @param cyclecount The variable to hold the value
- * @return 0 upon success
- */
-int metal_timer_get_cyclecount(int hartid, unsigned long long *cyclecount);
-
-/*!
- * @brief Get the machine timebase frequency
- * @param hartid The hart ID to read the timebase of
- * @param timebase The variable to hold the value
- * @return 0 upon success
- */
-int metal_timer_get_timebase_frequency(int hartid, unsigned long long *timebase);
-
-/*!
- * @brief Set the machine timer tick interval in seconds
- * @param hartid The hart ID to read the timebase of
- * @param second The number of seconds to set the tick interval to
- * @return 0 upon success
- */
-int metal_timer_set_tick(int hartid, int second);
-
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__TTY_H
-#define METAL__TTY_H
-
-/*!
- * @file tty.h
- * @brief API for emulated serial teriminals
- */
-
-/*!
- * @brief Write a character to the default output device
- *
- * Write a character to the default output device, which for most
- * targets is the UART serial port.
- *
- * putc() does CR/LF mapping.
- * putc_raw() does not.
- *
- * @param c The character to write to the terminal
- * @return 0 on success, or -1 on failure.
- */
-int metal_tty_putc(int c);
-
-/*!
- * @brief Write a raw character to the default output device
- *
- * Write a character to the default output device, which for most
- * targets is the UART serial port.
- *
- * putc() does CR/LF mapping.
- * putc_raw() does not.
- *
- * @param c The character to write to the terminal
- * @return 0 on success, or -1 on failure.
- */
-int metal_tty_putc_raw(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
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#ifndef METAL__UART_H
-#define METAL__UART_H
-
-/*!
- * @file uart.h
- * @brief API for UART serial ports
- */
-
-#include <metal/interrupt.h>
-
-struct metal_uart;
-#undef getc
-#undef putc
-struct metal_uart_vtable {
- void (*init)(struct metal_uart *uart, int baud_rate);
- int (*putc)(struct metal_uart *uart, int c);
- int (*txready)(struct metal_uart *uart);
- int (*getc)(struct metal_uart *uart, int *c);
- int (*get_baud_rate)(struct metal_uart *uart);
- int (*set_baud_rate)(struct metal_uart *uart, int baud_rate);
- struct metal_interrupt* (*controller_interrupt)(struct metal_uart *uart);
- int (*get_interrupt_id)(struct metal_uart *uart);
-};
-
-/*!
- * @brief Handle for a UART serial device
- */
-struct metal_uart {
- const struct metal_uart_vtable *vtable;
-};
-
-/*!
- * @brief Initialize UART device
-
- * Initialize the UART device described by the UART handle. This function must 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 baud_rate the baud rate to set the UART to
- */
-__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
- * @param uart The UART device handle
- * @param c The character to send over the UART
- * @return 0 upon success
- */
-__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
- * @param uart The UART device handle
- * @param c The varible to hold the read character
- * @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, int *c) { return uart->vtable->getc(uart, c); }
-
-/*!
- * @brief Get the baud rate of the UART peripheral
- * @param uart The UART device handle
- * @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); }
-
-/*!
- * @brief Set the baud rate of the UART peripheral
- * @param uart The UART device handle
- * @param baud_rate The baud rate to configure
- * @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); }
-
-/*!
- * @brief Get the interrupt controller of the UART peripheral
- *
- * Get the interrupt controller for the UART peripheral. The interrupt
- * controller must be initialized before any interrupts can be registered
- * or enabled with it.
- *
- * @param uart The UART device handle
- * @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); }
-
-/*!
- * @brief Get the interrupt ID of the UART controller
- * @param uart The UART device handle
- * @return The UART interrupt id
- */
-__inline__ int metal_uart_get_interrupt_id(struct metal_uart *uart) { return uart->vtable->get_interrupt_id(uart); }
-
-#endif
+++ /dev/null
-/* 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 */
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/button.h>
-#include <metal/machine.h>
-
-struct metal_button* metal_button_get (char *label)
-{
- int i;
- struct metal_button *button;
-
- if ((__METAL_DT_MAX_BUTTONS == 0) || (label == NULL)) {
- return NULL;
- }
-
- for (i = 0; i < __METAL_DT_MAX_BUTTONS; i++) {
- button = (struct metal_button*)__metal_button_table[i];
- if (button->vtable->button_exist(button, label)) {
- return button;
- }
- }
- return NULL;
-}
-
-extern __inline__ struct metal_interrupt*
- metal_button_interrupt_controller(struct metal_button *button);
-extern __inline__ int metal_button_get_interrupt_id(struct metal_button *button);
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/cache.h>
-#include <metal/machine.h>
-
-extern __inline__ void metal_cache_init(struct metal_cache *cache, int ways);
-extern __inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache);
-extern __inline__ int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways);
-
-int metal_dcache_l1_available(int hartid) {
- switch (hartid) {
- case 0:
-#ifdef __METAL_CPU_0_DCACHE_HANDLE
- return __METAL_CPU_0_DCACHE_HANDLE;
-#endif
- break;
- case 1:
-#ifdef __METAL_CPU_1_DCACHE_HANDLE
- return __METAL_CPU_1_DCACHE_HANDLE;
-#endif
- break;
- case 2:
-#ifdef __METAL_CPU_2_DCACHE_HANDLE
- return __METAL_CPU_2_DCACHE_HANDLE;
-#endif
- break;
- case 3:
-#ifdef __METAL_CPU_3_DCACHE_HANDLE
- return __METAL_CPU_3_DCACHE_HANDLE;
-#endif
- break;
- case 4:
-#ifdef __METAL_CPU_4_DCACHE_HANDLE
- return __METAL_CPU_4_DCACHE_HANDLE;
-#endif
- break;
- case 5:
-#ifdef __METAL_CPU_5_DCACHE_HANDLE
- return __METAL_CPU_5_DCACHE_HANDLE;
-#endif
- break;
- case 6:
-#ifdef __METAL_CPU_6_DCACHE_HANDLE
- return __METAL_CPU_6_DCACHE_HANDLE;
-#endif
- break;
- case 7:
-#ifdef __METAL_CPU_7_DCACHE_HANDLE
- return __METAL_CPU_7_DCACHE_HANDLE;
-#endif
- break;
- case 8:
-#ifdef __METAL_CPU_8_DCACHE_HANDLE
- return __METAL_CPU_8_DCACHE_HANDLE;
-#endif
- break;
- }
- return 0;
-}
-
-int metal_icache_l1_available(int hartid) {
- switch (hartid) {
- case 0:
-#ifdef __METAL_CPU_0_ICACHE_HANDLE
- return __METAL_CPU_0_ICACHE_HANDLE;
-#endif
- break;
- case 1:
-#ifdef __METAL_CPU_1_ICACHE_HANDLE
- return __METAL_CPU_1_ICACHE_HANDLE;
-#endif
- break;
- case 2:
-#ifdef __METAL_CPU_2_ICACHE_HANDLE
- return __METAL_CPU_2_ICACHE_HANDLE;
-#endif
- break;
- case 3:
-#ifdef __METAL_CPU_3_ICACHE_HANDLE
- return __METAL_CPU_3_ICACHE_HANDLE;
-#endif
- break;
- case 4:
-#ifdef __METAL_CPU_4_ICACHE_HANDLE
- return __METAL_CPU_4_ICACHE_HANDLE;
-#endif
- break;
- case 5:
-#ifdef __METAL_CPU_5_ICACHE_HANDLE
- return __METAL_CPU_5_ICACHE_HANDLE;
-#endif
- break;
- case 6:
-#ifdef __METAL_CPU_6_ICACHE_HANDLE
- return __METAL_CPU_6_ICACHE_HANDLE;
-#endif
- break;
- case 7:
-#ifdef __METAL_CPU_7_ICACHE_HANDLE
- return __METAL_CPU_7_ICACHE_HANDLE;
-#endif
- break;
- case 8:
-#ifdef __METAL_CPU_8_ICACHE_HANDLE
- return __METAL_CPU_8_ICACHE_HANDLE;
-#endif
- break;
- }
- return 0;
-}
-
-/*!
- * @brief CFlush.D.L1 instruction is a custom instruction implemented as a
- * state machine in L1 Data Cache (D$) with funct3=0, (for core with data caches)
- * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
- * 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0
- * |--------|--------|--------|--------|--------|--------|--------|--------|
- * +-------------+------------+----------+------+--------+-----------------+
- * |sign immediate12b (simm12)| rs1 | func3| rd | opcode |
- * |-1-1-1-1 -1-1-0-0 -0-0-0-0|-x-x-x-x-x|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1|
- * +--------------------------+----------+------+--------+-----------------+
- * 31 -0x40 20 15 0 12 x0 7 0x73 0
- * +--------+--------+--------+----------+------+--------+--------+--------+
- * where,
- * rs1 = 0x0, CFLUSH.D.L1 writes back and invalidates all lines in the L1 D$
- * rs1 != x0, CFLUSH.D.L1 writes back and invalidates the L1 D$ line containing
- * the virtual address in integer register rs1.
- */
-void metal_dcache_l1_flush(int hartid, uintptr_t address)
-{
- if (metal_dcache_l1_available(hartid)) {
- // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
- __asm__ __volatile__ (".insn i 0x73, 0, x0, %0, -0x40" : : "r" (address));
- __asm__ __volatile__ ("fence.i"); // FENCE
- }
-}
-
-/*!
- * @brief CDiscard.D.L1 instruction is a custom instruction implemented as a
- * state machine in L1 Data Cache (D$) with funct3=0, (for core with data caches)
- * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
- * 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0
- * |--------|--------|--------|--------|--------|--------|--------|--------|
- * +-------------+------------+----------+------+--------+-----------------+
- * |sign immediate12b (simm12)| rs1 | func3| rd | opcode |
- * |-1-1-1-1 -1-1-0-0 -0-0-0-0|-x-x-x-x-x|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1|
- * +--------------------------+----------+------+--------+-----------------+
- * 31 -0x3E 20 15 0 12 x0 7 0x73 0
- * +--------+--------+--------+----------+------+--------+--------+--------+
- * where,
- * rs1 = 0x0, CDISCARD.D.L1 invalidates all lines in the L1 D$ with no writes back.
- * rs1 != x0, CDISCARD.D.L1 invalidates the L1 D$ line containing the virtual address
- * in integer register rs1, with no writes back.
- */
-void metal_dcache_l1_discard(int hartid, uintptr_t address)
-{
- if (metal_dcache_l1_available(hartid)) {
- // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
- __asm__ __volatile__ (".insn i 0x73, 0, x0, %0, -0x3E" : : "r" (address));
- __asm__ __volatile__ ("fence.i"); // FENCE
- }
-}
-
-/*!
- * @brief CFlush.I.L1 instruction is a custom instruction implemented as a state
- * machine in L1 Instruction Cache (I$) with funct3=0, (for core with data caches)
- * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
- * 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0
- * |--------|--------|--------|--------|--------|--------|--------|--------|
- * +-------------+------------+----------+------+--------+-----------------+
- * |sign immediate12b (simm12)| rs1 | func3| rd | opcode |
- * |-1-1-1-1 -1-1-0-0 -0-0-0-0|-0-0-0-0-0|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1|
- * +--------------------------+----------+------+--------+-----------------+
- * 31 -0x3F 20 15 0 12 x0 7 0x73 0
- * +--------+--------+--------+----------+------+--------+--------+--------+
- * CFLUSH.I.L1 invalidates all lines in the L1 I$.
- */
-void metal_icache_l1_flush(int hartid)
-{
- if (metal_icache_l1_available(hartid)) {
- // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
- __asm__ __volatile__ (".insn i 0x73, 0, x0, x0, -0x3F" : : );
- __asm__ __volatile__ ("fence.i"); // FENCE
- }
-}
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/clock.h>
-
-extern __inline__ void _metal_clock_call_all_callbacks(const metal_clock_callback *const list);
-extern __inline__ metal_clock_callback *_metal_clock_append_to_callbacks(metal_clock_callback *list, metal_clock_callback *const cb);
-
-extern __inline__ long metal_clock_get_rate_hz(const struct metal_clock *clk);
-extern __inline__ long metal_clock_set_rate_hz(struct metal_clock *clk, long hz);
-extern __inline__ void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb);
-extern __inline__ void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb);
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/cpu.h>
-#include <metal/machine.h>
-
-struct metal_cpu* metal_cpu_get(unsigned int hartid)
-{
- if (hartid < __METAL_DT_MAX_HARTS) {
- return (struct metal_cpu *)__metal_cpu_table[hartid];
- }
- return NULL;
-}
-
-int metal_cpu_get_current_hartid()
-{
-#ifdef __riscv
- int mhartid;
- __asm__ volatile("csrr %0, mhartid" : "=r" (mhartid));
- return mhartid;
-#endif
-}
-
-int metal_cpu_get_num_harts()
-{
- return __METAL_DT_MAX_HARTS;
-}
-
-extern __inline__ unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu);
-
-extern __inline__ unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu);
-
-extern __inline__ unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu);
-
-extern __inline__ int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time);
-
-extern __inline__ struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu);
-
-extern __inline__ int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu);
-
-extern __inline__ struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu);
-
-extern __inline__ int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu);
-
-extern __inline__ int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid);
-
-extern __inline__ int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid);
-
-extern __inline__ int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid);
-
-extern __inline__ struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu);
-
-extern __inline__ int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler);
-
-extern __inline__ int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc);
-
-extern __inline__ uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu);
-
-extern __inline__ int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc);
+++ /dev/null
-/* Copyright 2018 SiFive, Inc. */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_FIXED_CLOCK
-
-#include <metal/drivers/fixed-clock.h>
-#include <stddef.h>
-#include <metal/machine.h>
-
-long __metal_driver_fixed_clock_get_rate_hz(const struct metal_clock *gclk)
-{
- return __metal_driver_fixed_clock_rate(gclk);
-}
-
-long __metal_driver_fixed_clock_set_rate_hz(struct metal_clock *gclk, long target_hz)
-{
- return __metal_driver_fixed_clock_get_rate_hz(gclk);
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_fixed_clock) = {
- .clock.get_rate_hz = __metal_driver_fixed_clock_get_rate_hz,
- .clock.set_rate_hz = __metal_driver_fixed_clock_set_rate_hz,
-};
-
-#endif /* METAL_FIXED_CLOCK */
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc. */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_FIXED_FACTOR_CLOCK
-
-#include <metal/drivers/fixed-factor-clock.h>
-#include <stddef.h>
-#include <metal/machine.h>
-
-long __metal_driver_fixed_factor_clock_get_rate_hz(const struct metal_clock *gclk)
-{
- struct metal_clock *parent = __metal_driver_fixed_factor_clock_parent(gclk);
- long parent_rate = 1;
- if(parent) {
- parent_rate = parent->vtable->get_rate_hz(parent);
- }
-
- return __metal_driver_fixed_factor_clock_mult(gclk) * parent_rate / __metal_driver_fixed_factor_clock_div(gclk);
-}
-
-long __metal_driver_fixed_factor_clock_set_rate_hz(struct metal_clock *gclk, long target_hz)
-{
- return __metal_driver_fixed_factor_clock_get_rate_hz(gclk);
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_fixed_factor_clock) = {
- .clock.get_rate_hz = __metal_driver_fixed_factor_clock_get_rate_hz,
- .clock.set_rate_hz = __metal_driver_fixed_factor_clock_set_rate_hz,
-};
-#endif /* METAL_FIXED_FACTOR_CLOCK */
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/inline.h>
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_RISCV_CLINT0
-
-#include <metal/io.h>
-#include <metal/cpu.h>
-#include <metal/drivers/riscv_clint0.h>
-#include <metal/machine.h>
-
-unsigned long long __metal_clint0_mtime_get (struct __metal_driver_riscv_clint0 *clint)
-{
- __metal_io_u32 lo, hi;
- unsigned long control_base = __metal_driver_sifive_clint0_control_base(&clint->controller);
-
- /* Guard against rollover when reading */
- do {
- hi = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_RISCV_CLINT0_MTIME + 4));
- lo = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_RISCV_CLINT0_MTIME));
- } while (__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_RISCV_CLINT0_MTIME + 4)) != hi);
-
- return (((unsigned long long)hi) << 32) | lo;
-}
-
-int __metal_driver_riscv_clint0_mtimecmp_set(struct metal_interrupt *controller,
- int hartid,
- unsigned long long time)
-{
- struct __metal_driver_riscv_clint0 *clint =
- (struct __metal_driver_riscv_clint0 *)(controller);
- unsigned long control_base = __metal_driver_sifive_clint0_control_base(&clint->controller);
- /* Per spec, the RISC-V MTIME/MTIMECMP registers are 64 bit,
- * and are NOT internally latched for multiword transfers.
- * Need to be careful about sequencing to avoid triggering
- * spurious interrupts: For that set the high word to a max
- * value first.
- */
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_RISCV_CLINT0_MTIMECMP_BASE + 4)) = 0xFFFFFFFF;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_RISCV_CLINT0_MTIMECMP_BASE)) = (__metal_io_u32)time;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_RISCV_CLINT0_MTIMECMP_BASE + 4)) = (__metal_io_u32)(time >> 32);
- return 0;
-}
-
-static struct metal_interrupt *_get_cpu_intc()
-{
- int hartid = 0;
- __asm__ volatile("csrr %[hartid], mhartid"
- : [hartid] "=r" (hartid) :: "memory");
-
- struct metal_cpu *cpu = metal_cpu_get(hartid);
-
- return metal_cpu_interrupt_controller(cpu);
-}
-
-void __metal_driver_riscv_clint0_init (struct metal_interrupt *controller)
-{
- int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller);
- struct __metal_driver_riscv_clint0 *clint =
- (struct __metal_driver_riscv_clint0 *)(controller);
-
- if ( !clint->init_done ) {
- /* Register its interrupts with with parent controller, aka sw and timerto its default isr */
- for (int i = 0; i < num_interrupts; i++) {
- struct metal_interrupt *intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i);
- int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i);
- intc->vtable->interrupt_register(intc, line, NULL, controller);
- }
- clint->init_done = 1;
- }
-}
-
-int __metal_driver_riscv_clint0_register (struct metal_interrupt *controller,
- int id, metal_interrupt_handler_t isr,
- void *priv)
-{
- int rc = -1;
- metal_vector_mode mode = __metal_controller_interrupt_vector_mode();
- struct metal_interrupt *intc = NULL;
- struct metal_interrupt *cpu_intc = _get_cpu_intc();
- int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller);
-
- if ( (mode != METAL_VECTOR_MODE) && (mode != METAL_DIRECT_MODE) ) {
- return rc;
- }
-
- for(int i = 0; i < num_interrupts; i++) {
- int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i);
- intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i);
- if (cpu_intc == intc && id == line) {
- break;
- }
- intc = NULL;
- }
-
- /* Register its interrupts with parent controller */
- if (intc) {
- rc = intc->vtable->interrupt_register(intc, id, isr, priv);
- }
- return rc;
-}
-
-int __metal_driver_riscv_clint0_vector_register (struct metal_interrupt *controller,
- int id, metal_interrupt_vector_handler_t isr,
- void *priv)
-{
- /* Not supported. User can override the 'weak' handler with their own */
- int rc = -1;
- return rc;
-}
-
-metal_vector_mode __metal_driver_riscv_clint0_get_vector_mode (struct metal_interrupt *controller)
-{
- return __metal_controller_interrupt_vector_mode();
-}
-
-int __metal_driver_riscv_clint0_set_vector_mode (struct metal_interrupt *controller, metal_vector_mode mode)
-{
- int rc = -1;
- struct metal_interrupt *intc = _get_cpu_intc();
-
- if (intc) {
- /* Valid vector modes are VECTOR and DIRECT, anything else is invalid (-1) */
- switch (mode) {
- case METAL_VECTOR_MODE:
- case METAL_DIRECT_MODE:
- rc = intc->vtable->interrupt_set_vector_mode(intc, mode);
- break;
- case METAL_HARDWARE_VECTOR_MODE:
- case METAL_SELECTIVE_NONVECTOR_MODE:
- case METAL_SELECTIVE_VECTOR_MODE:
- break;
- }
- }
- return rc;
-}
-
-int __metal_driver_riscv_clint0_enable (struct metal_interrupt *controller, int id)
-{
- int rc = -1;
-
- if ( id ) {
- struct metal_interrupt *intc = NULL;
- struct metal_interrupt *cpu_intc = _get_cpu_intc();
- int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller);
-
- for(int i = 0; i < num_interrupts; i++) {
- int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i);
- intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i);
- if(cpu_intc == intc && id == line) {
- break;
- }
- intc = NULL;
- }
-
- /* Enable its interrupts with parent controller */
- if (intc) {
- rc = intc->vtable->interrupt_enable(intc, id);
- }
- }
-
- return rc;
-}
-
-int __metal_driver_riscv_clint0_disable (struct metal_interrupt *controller, int id)
-{
- int rc = -1;
-
- if ( id ) {
- struct metal_interrupt *intc = NULL;
- struct metal_interrupt *cpu_intc = _get_cpu_intc();
- int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller);
-
- for(int i = 0; i < num_interrupts; i++) {
- int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i);
- intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i);
- if(cpu_intc == intc && id == line) {
- break;
- }
- intc = NULL;
- }
-
- /* Disable its interrupts with parent controller */
- if (intc) {
- rc = intc->vtable->interrupt_disable(intc, id);
- }
- }
-
- return rc;
-}
-
-int __metal_driver_riscv_clint0_command_request (struct metal_interrupt *controller,
- int command, void *data)
-{
- int hartid;
- int rc = -1;
- struct __metal_driver_riscv_clint0 *clint =
- (struct __metal_driver_riscv_clint0 *)(controller);
- unsigned long control_base = __metal_driver_sifive_clint0_control_base(controller);
-
- switch (command) {
- case METAL_TIMER_MTIME_GET:
- if (data) {
- *(unsigned long long *)data = __metal_clint0_mtime_get(clint);
- rc = 0;
- }
- break;
- case METAL_SOFTWARE_IPI_CLEAR:
- if (data) {
- hartid = *(int *)data;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- (hartid * 4))) = METAL_DISABLE;
- rc = 0;
- }
- break;
- case METAL_SOFTWARE_IPI_SET:
- if (data) {
- hartid = *(int *)data;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- (hartid * 4))) = METAL_ENABLE;
- /* Callers of this function assume it's blocking, in the sense that
- * the IPI is guarnteed to have been delivered before the function
- * returns. We can't really guarnteed it's delivered, but we can
- * read back the control register after writing it in at least an
- * attempt to provide some semblence of ordering here. The fence
- * ensures the read is order after the write -- it wouldn't be
- * necessary under RVWMO because this is the same address, but we
- * don't have an IO memory model so I'm being a bit overkill here.
- */
- __METAL_IO_FENCE(o,i);
- rc = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- (hartid * 4)));
- rc = 0;
- }
- break;
- case METAL_SOFTWARE_MSIP_GET:
- rc = 0;
- if (data) {
- hartid = *(int *)data;
- rc = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- (hartid * 4)));
- }
- break;
- default:
- break;
- }
-
- return rc;
-}
-
-int __metal_driver_riscv_clint0_clear_interrupt (struct metal_interrupt *controller, int id)
-{
- int hartid = metal_cpu_get_current_hartid();
- return __metal_driver_riscv_clint0_command_request(controller,
- METAL_SOFTWARE_IPI_CLEAR, &hartid);
-}
-
-int __metal_driver_riscv_clint0_set_interrupt (struct metal_interrupt *controller, int id)
-{
- int hartid = metal_cpu_get_current_hartid();
- return __metal_driver_riscv_clint0_command_request(controller,
- METAL_SOFTWARE_IPI_SET, &hartid);
-}
-
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_clint0) = {
- .clint_vtable.interrupt_init = __metal_driver_riscv_clint0_init,
- .clint_vtable.interrupt_register = __metal_driver_riscv_clint0_register,
- .clint_vtable.interrupt_vector_register = __metal_driver_riscv_clint0_vector_register,
- .clint_vtable.interrupt_enable = __metal_driver_riscv_clint0_enable,
- .clint_vtable.interrupt_disable = __metal_driver_riscv_clint0_disable,
- .clint_vtable.interrupt_get_vector_mode = __metal_driver_riscv_clint0_get_vector_mode,
- .clint_vtable.interrupt_set_vector_mode = __metal_driver_riscv_clint0_set_vector_mode,
- .clint_vtable.interrupt_clear = __metal_driver_riscv_clint0_clear_interrupt,
- .clint_vtable.interrupt_set = __metal_driver_riscv_clint0_set_interrupt,
- .clint_vtable.command_request = __metal_driver_riscv_clint0_command_request,
- .clint_vtable.mtimecmp_set = __metal_driver_riscv_clint0_mtimecmp_set,
-};
-
-#endif /* METAL_RISCV_CLINT0 */
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <stdint.h>
-#include <metal/io.h>
-#include <metal/shutdown.h>
-#include <metal/machine.h>
-
-extern void __metal_vector_table();
-unsigned long long __metal_driver_cpu_mtime_get(struct metal_cpu *cpu);
-int __metal_driver_cpu_mtimecmp_set(struct metal_cpu *cpu, unsigned long long time);
-
-struct metal_cpu *__metal_driver_cpu_get(int hartid)
-{
- if (hartid < __METAL_DT_MAX_HARTS) {
- return &(__metal_cpu_table[hartid]->cpu);
- }
- return (struct metal_cpu *)NULL;
-}
-
-uintptr_t __metal_myhart_id (void)
-{
- uintptr_t myhart;
- __asm__ volatile ("csrr %0, mhartid" : "=r"(myhart));
- return myhart;
-}
-
-void __metal_zero_memory (unsigned char *base, unsigned int size)
-{
- volatile unsigned char *ptr;
- for (ptr = base; ptr < (base + size); ptr++){
- *ptr = 0;
- }
-}
-
-void __metal_interrupt_global_enable (void) {
- uintptr_t m;
- __asm__ volatile ("csrrs %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT));
-}
-
-void __metal_interrupt_global_disable (void) {
- uintptr_t m;
- __asm__ volatile ("csrrc %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT));
-}
-
-void __metal_interrupt_software_enable (void) {
- uintptr_t m;
- __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW));
-}
-
-void __metal_interrupt_software_disable (void) {
- uintptr_t m;
- __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW));
-}
-
-void __metal_interrupt_timer_enable (void) {
- uintptr_t m;
- __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR));
-}
-
-void __metal_interrupt_timer_disable (void) {
- uintptr_t m;
- __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR));
-}
-
-void __metal_interrupt_external_enable (void) {
- uintptr_t m;
- __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT));
-}
-
-void __metal_interrupt_external_disable (void) {
- unsigned long m;
- __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT));
-}
-
-void __metal_interrupt_local_enable (int id) {
- uintptr_t b = 1 << id;
- uintptr_t m;
- __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(b));
-}
-
-void __metal_interrupt_local_disable (int id) {
- uintptr_t b = 1 << id;
- uintptr_t m;
- __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(b));
-}
-
-void __metal_default_exception_handler (struct metal_cpu *cpu, int ecode) {
- metal_shutdown(100);
-}
-
-void __metal_default_interrupt_handler (int id, void *priv) {
- metal_shutdown(200);
-}
-
-/* The metal_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_interrupt_vector_handler (void) {
- metal_shutdown(300);
-}
-
-/* The metal_software_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_software_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_SW].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_SW].handler(METAL_INTERRUPT_ID_SW, priv);
- }
-}
-
-void __metal_default_sw_handler (int id, void *priv) {
- uintptr_t mcause;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- __asm__ volatile ("csrr %0, mcause" : "=r"(mcause));
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- intc->metal_exception_table[mcause & METAL_MCAUSE_CAUSE]((struct metal_cpu *)cpu, id);
- }
-}
-
-/* The metal_timer_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_timer_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_TMR].handler(METAL_INTERRUPT_ID_TMR, priv);
- }
-}
-
-void __metal_default_timer_handler (int id, void *priv) {
- struct metal_cpu *cpu = __metal_driver_cpu_get(__metal_myhart_id());
- unsigned long long time = __metal_driver_cpu_mtime_get(cpu);
-
- /* Set a 10 cycle timer */
- __metal_driver_cpu_mtimecmp_set(cpu, time + 10);
-}
-
-/* The metal_external_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_external_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_EXT].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_EXT].handler(METAL_INTERRUPT_ID_EXT, priv);
- }
-}
-
-void __metal_exception_handler(void) __attribute__((interrupt, aligned(128)));
-void __metal_exception_handler (void) {
- int id;
- void *priv;
- uintptr_t mcause, mepc, mtval, mtvec;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- __asm__ volatile ("csrr %0, mcause" : "=r"(mcause));
- __asm__ volatile ("csrr %0, mepc" : "=r"(mepc));
- __asm__ volatile ("csrr %0, mtval" : "=r"(mtval));
- __asm__ volatile ("csrr %0, mtvec" : "=r"(mtvec));
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- id = mcause & METAL_MCAUSE_CAUSE;
- if (mcause & METAL_MCAUSE_INTR) {
- if ((id < METAL_INTERRUPT_ID_CSW) ||
- ((mtvec & METAL_MTVEC_MASK) == METAL_MTVEC_DIRECT)) {
- priv = intc->metal_int_table[id].exint_data;
- intc->metal_int_table[id].handler(id, priv);
- return;
- }
- if ((mtvec & METAL_MTVEC_MASK) == METAL_MTVEC_CLIC) {
- uintptr_t mtvt;
- metal_interrupt_handler_t mtvt_handler;
-
- __asm__ volatile ("csrr %0, 0x307" : "=r"(mtvt));
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
- mtvt_handler = (metal_interrupt_handler_t)*(uintptr_t *)mtvt;
- mtvt_handler(id, priv);
- return;
- }
- } else {
- intc->metal_exception_table[id]((struct metal_cpu *)cpu, id);
- }
- }
-}
-
-/* The metal_lc0_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc0_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC0].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC0].handler(METAL_INTERRUPT_ID_LC0, priv);
- }
-}
-
-/* The metal_lc1_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc1_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC1].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC1].handler(METAL_INTERRUPT_ID_LC1, priv);
- }
-}
-
-/* The metal_lc2_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc2_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC2].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC2].handler(METAL_INTERRUPT_ID_LC2, priv);
- }
-}
-
-/* The metal_lc3_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc3_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC3].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC3].handler(METAL_INTERRUPT_ID_LC3, priv);
- }
-}
-
-/* The metal_lc4_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc4_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC4].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC4].handler(METAL_INTERRUPT_ID_LC4, priv);
- }
-}
-
-/* The metal_lc5_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc5_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC5].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC5].handler(METAL_INTERRUPT_ID_LC5, priv);
- }
-}
-
-/* The metal_lc6_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc6_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC6].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC6].handler(METAL_INTERRUPT_ID_LC6, priv);
- }
-}
-
-/* The metal_lc7_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc7_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC7].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC7].handler(METAL_INTERRUPT_ID_LC7, priv);
- }
-}
-
-/* The metal_lc8_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc8_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC8].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC8].handler(METAL_INTERRUPT_ID_LC8, priv);
- }
-}
-
-/* The metal_lc9_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc9_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC9].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC9].handler(METAL_INTERRUPT_ID_LC9, priv);
- }
-}
-
-/* The metal_lc10_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc10_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC10].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC10].handler(METAL_INTERRUPT_ID_LC10, priv);
- }
-}
-
-/* The metal_lc11_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc11_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC11].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC11].handler(METAL_INTERRUPT_ID_LC11, priv);
- }
-}
-
-/* The metal_lc12_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc12_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC12].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC12].handler(METAL_INTERRUPT_ID_LC12, priv);
- }
-}
-
-/* The metal_lc13_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc13_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC13].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC13].handler(METAL_INTERRUPT_ID_LC13, priv);
- }
-}
-
-/* The metal_lc14_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc14_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC14].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC14].handler(METAL_INTERRUPT_ID_LC14, priv);
- }
-}
-
-/* The metal_lc15_interrupt_vector_handler() function can be redefined. */
-void __attribute__((weak, interrupt)) metal_lc15_interrupt_vector_handler (void) {
- void *priv;
- struct __metal_driver_riscv_cpu_intc *intc;
- struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
-
- if ( cpu ) {
- intc = (struct __metal_driver_riscv_cpu_intc *)
- __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
- priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC15].exint_data;
- intc->metal_int_table[METAL_INTERRUPT_ID_LC15].handler(METAL_INTERRUPT_ID_LC15, priv);
- }
-}
-
-metal_vector_mode __metal_controller_interrupt_vector_mode (void)
-{
- uintptr_t val;
-
- asm volatile ("csrr %0, mtvec" : "=r"(val));
- val &= METAL_MTVEC_MASK;
-
- switch (val) {
- case METAL_MTVEC_CLIC:
- return METAL_SELECTIVE_VECTOR_MODE;
- case METAL_MTVEC_CLIC_VECTORED:
- return METAL_HARDWARE_VECTOR_MODE;
- case METAL_MTVEC_VECTORED:
- return METAL_VECTOR_MODE;
- }
- return METAL_DIRECT_MODE;
-}
-
-void __metal_controller_interrupt_vector (metal_vector_mode mode, void *vec_table)
-{
- uintptr_t trap_entry, val;
-
- __asm__ volatile ("csrr %0, mtvec" : "=r"(val));
- val &= ~(METAL_MTVEC_CLIC_VECTORED | METAL_MTVEC_CLIC_RESERVED);
- trap_entry = (uintptr_t)vec_table;
-
- switch (mode) {
- case METAL_SELECTIVE_NONVECTOR_MODE:
- case METAL_SELECTIVE_VECTOR_MODE:
- __asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry));
- __asm__ volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC));
- break;
- case METAL_HARDWARE_VECTOR_MODE:
- __asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry));
- __asm__ volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC_VECTORED));
- break;
- case METAL_VECTOR_MODE:
- __asm__ volatile ("csrw mtvec, %0" :: "r"(trap_entry | METAL_MTVEC_VECTORED));
- break;
- case METAL_DIRECT_MODE:
- __asm__ volatile ("csrw mtvec, %0" :: "r"(trap_entry & ~METAL_MTVEC_CLIC_VECTORED));
- break;
- }
-}
-
-int __metal_valid_interrupt_id (int id)
-{
- switch (id) {
- case METAL_INTERRUPT_ID_SW:
- case METAL_INTERRUPT_ID_TMR:
- case METAL_INTERRUPT_ID_EXT:
- case METAL_INTERRUPT_ID_LC0:
- case METAL_INTERRUPT_ID_LC1:
- case METAL_INTERRUPT_ID_LC2:
- case METAL_INTERRUPT_ID_LC3:
- case METAL_INTERRUPT_ID_LC4:
- case METAL_INTERRUPT_ID_LC5:
- case METAL_INTERRUPT_ID_LC6:
- case METAL_INTERRUPT_ID_LC7:
- case METAL_INTERRUPT_ID_LC8:
- case METAL_INTERRUPT_ID_LC9:
- case METAL_INTERRUPT_ID_LC10:
- case METAL_INTERRUPT_ID_LC11:
- case METAL_INTERRUPT_ID_LC12:
- case METAL_INTERRUPT_ID_LC13:
- case METAL_INTERRUPT_ID_LC14:
- case METAL_INTERRUPT_ID_LC15:
- return 1;
- default:
- break;
- }
-
- return 0;
-}
-
-
-int __metal_local_interrupt_enable (struct metal_interrupt *controller,
- metal_interrupt_id_e id, int enable)
-{
- int rc = 0;
-
- if ( !controller) {
- return -1;
- }
-
- switch (id) {
- case METAL_INTERRUPT_ID_BASE:
- if (enable) {
- __metal_interrupt_global_enable();
- } else {
- __metal_interrupt_global_disable();
- }
- break;
- case METAL_INTERRUPT_ID_SW:
- if (enable) {
- __metal_interrupt_software_enable();
- } else {
- __metal_interrupt_software_disable();
- }
- break;
- case METAL_INTERRUPT_ID_TMR:
- if (enable) {
- __metal_interrupt_timer_enable();
- } else {
- __metal_interrupt_timer_disable();
- }
- break;
- case METAL_INTERRUPT_ID_EXT:
- if (enable) {
- __metal_interrupt_external_enable();
- } else {
- __metal_interrupt_external_disable();
- }
- break;
- case METAL_INTERRUPT_ID_LC0:
- case METAL_INTERRUPT_ID_LC1:
- case METAL_INTERRUPT_ID_LC2:
- case METAL_INTERRUPT_ID_LC3:
- case METAL_INTERRUPT_ID_LC4:
- case METAL_INTERRUPT_ID_LC5:
- case METAL_INTERRUPT_ID_LC6:
- case METAL_INTERRUPT_ID_LC7:
- case METAL_INTERRUPT_ID_LC8:
- case METAL_INTERRUPT_ID_LC9:
- case METAL_INTERRUPT_ID_LC10:
- case METAL_INTERRUPT_ID_LC11:
- case METAL_INTERRUPT_ID_LC12:
- case METAL_INTERRUPT_ID_LC13:
- case METAL_INTERRUPT_ID_LC14:
- case METAL_INTERRUPT_ID_LC15:
- if (enable) {
- __metal_interrupt_local_enable(id);
- } else {
- __metal_interrupt_local_disable(id);
- }
- break;
- default:
- rc = -1;
- }
- return rc;
-}
-
-int __metal_exception_register (struct metal_interrupt *controller,
- int ecode, metal_exception_handler_t isr)
-{
- struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
-
- if ((ecode < METAL_MAX_EXCEPTION_CODE) && isr) {
- intc->metal_exception_table[ecode] = isr;
- return 0;
- }
- return -1;
-}
-
-void __metal_driver_riscv_cpu_controller_interrupt_init (struct metal_interrupt *controller)
-{
- struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
- uintptr_t val;
-
- if ( !intc->init_done ) {
- /* Disable and clear all interrupt sources */
- __asm__ volatile ("csrc mie, %0" :: "r"(-1));
- __asm__ volatile ("csrc mip, %0" :: "r"(-1));
-
- /* Read the misa CSR to determine if the delegation registers exist */
- uintptr_t misa;
- __asm__ volatile ("csrr %0, misa" : "=r" (misa));
-
- /* The delegation CSRs exist if user mode interrupts (N extension) or
- * supervisor mode (S extension) are supported */
- if((misa & METAL_ISA_N_EXTENSIONS) || (misa & METAL_ISA_S_EXTENSIONS)) {
- /* Disable interrupt and exception delegation */
- __asm__ volatile ("csrc mideleg, %0" :: "r"(-1));
- __asm__ volatile ("csrc medeleg, %0" :: "r"(-1));
- }
-
- /* The satp CSR exists if supervisor mode (S extension) is supported */
- if(misa & METAL_ISA_S_EXTENSIONS) {
- /* Clear the entire CSR to make sure that satp.MODE = 0 */
- __asm__ volatile ("csrc satp, %0" :: "r"(-1));
- }
-
- /* Default to use direct interrupt, setup sw cb table*/
- for (int i = 0; i < METAL_MAX_MI; i++) {
- intc->metal_int_table[i].handler = NULL;
- intc->metal_int_table[i].sub_int = NULL;
- intc->metal_int_table[i].exint_data = NULL;
- }
- for (int i = 0; i < METAL_MAX_ME; i++) {
- intc->metal_exception_table[i] = __metal_default_exception_handler;
- }
- __metal_controller_interrupt_vector(METAL_DIRECT_MODE, (void *)(uintptr_t)&__metal_exception_handler);
- __asm__ volatile ("csrr %0, misa" : "=r"(val));
- if (val & (METAL_ISA_D_EXTENSIONS | METAL_ISA_F_EXTENSIONS | METAL_ISA_Q_EXTENSIONS)) {
- /* Floating point architecture, so turn on FP register saving*/
- __asm__ volatile ("csrr %0, mstatus" : "=r"(val));
- __asm__ volatile ("csrw mstatus, %0" :: "r"(val | METAL_MSTATUS_FS_INIT));
- }
- intc->init_done = 1;
- }
-}
-
-int __metal_driver_riscv_cpu_controller_interrupt_register(struct metal_interrupt *controller,
- int id, metal_interrupt_handler_t isr,
- void *priv)
-{
- int rc = 0;
- struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
-
- if ( !__metal_valid_interrupt_id(id) ) {
- return -11;
- }
-
- if (isr) {
- intc->metal_int_table[id].handler = isr;
- intc->metal_int_table[id].exint_data = priv;
- } else {
- switch (id) {
- case METAL_INTERRUPT_ID_SW:
- intc->metal_int_table[id].handler = __metal_default_sw_handler;
- intc->metal_int_table[id].sub_int = priv;
- break;
- case METAL_INTERRUPT_ID_TMR:
- intc->metal_int_table[id].handler = __metal_default_timer_handler;
- intc->metal_int_table[id].sub_int = priv;
- break;
- case METAL_INTERRUPT_ID_EXT:
- case METAL_INTERRUPT_ID_LC0:
- case METAL_INTERRUPT_ID_LC1:
- case METAL_INTERRUPT_ID_LC2:
- case METAL_INTERRUPT_ID_LC3:
- case METAL_INTERRUPT_ID_LC4:
- case METAL_INTERRUPT_ID_LC5:
- case METAL_INTERRUPT_ID_LC6:
- case METAL_INTERRUPT_ID_LC7:
- case METAL_INTERRUPT_ID_LC8:
- case METAL_INTERRUPT_ID_LC9:
- case METAL_INTERRUPT_ID_LC10:
- case METAL_INTERRUPT_ID_LC11:
- case METAL_INTERRUPT_ID_LC12:
- case METAL_INTERRUPT_ID_LC13:
- case METAL_INTERRUPT_ID_LC14:
- case METAL_INTERRUPT_ID_LC15:
- intc->metal_int_table[id].handler = __metal_default_interrupt_handler;
- intc->metal_int_table[id].sub_int = priv;
- break;
- default:
- rc = -12;
- }
- }
- return rc;
-}
-
-int __metal_driver_riscv_cpu_controller_interrupt_enable (struct metal_interrupt *controller,
- int id)
-{
- return __metal_local_interrupt_enable(controller, id, METAL_ENABLE);
-}
-
-int __metal_driver_riscv_cpu_controller_interrupt_disable (struct metal_interrupt *controller,
- int id)
-{
- return __metal_local_interrupt_enable(controller, id, METAL_DISABLE);
-}
-
-int __metal_driver_riscv_cpu_controller_interrupt_enable_vector(struct metal_interrupt *controller,
- int id, metal_vector_mode mode)
-{
- struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
-
- if (id == METAL_INTERRUPT_ID_BASE) {
- if (mode == METAL_DIRECT_MODE) {
- __metal_controller_interrupt_vector(mode, (void *)(uintptr_t)&__metal_exception_handler);
- return 0;
- }
- if (mode == METAL_VECTOR_MODE) {
- __metal_controller_interrupt_vector(mode, (void *)&intc->metal_mtvec_table);
- return 0;
- }
- }
- return -1;
-}
-
-int __metal_driver_riscv_cpu_controller_interrupt_disable_vector(struct metal_interrupt *controller,
- int id)
-{
- if (id == METAL_INTERRUPT_ID_BASE) {
- __metal_controller_interrupt_vector(METAL_DIRECT_MODE, (void *)(uintptr_t)&__metal_exception_handler);
- return 0;
- }
- return -1;
-}
-
-metal_vector_mode __metal_driver_riscv_cpu_controller_get_vector_mode (struct metal_interrupt *controller)
-{
- return __metal_controller_interrupt_vector_mode();
-}
-
-int __metal_driver_riscv_cpu_controller_set_vector_mode (struct metal_interrupt *controller,
- metal_vector_mode mode)
-{
- struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
- ( void ) intc;
-
- if (mode == METAL_DIRECT_MODE) {
- __metal_controller_interrupt_vector(mode, (void *)(uintptr_t)&__metal_exception_handler);
- return 0;
- }
- if (mode == METAL_VECTOR_MODE) {
- __metal_controller_interrupt_vector(mode, (void *)__metal_vector_table);
- return 0;
- }
- return -1;
-}
-
-int __metal_driver_riscv_cpu_controller_command_request (struct metal_interrupt *controller,
- int cmd, void *data)
-{
- /* NOP for now, unless local interrupt lines the like of clic, clint, plic */
- return 0;
-}
-
-/* CPU driver !!! */
-
-unsigned long long __metal_driver_cpu_mcycle_get(struct metal_cpu *cpu)
-{
- unsigned long long val = 0;
-
-#if __riscv_xlen == 32
- unsigned long hi, hi1, lo;
-
- __asm__ volatile ("csrr %0, mcycleh" : "=r"(hi));
- __asm__ volatile ("csrr %0, mcycle" : "=r"(lo));
- __asm__ volatile ("csrr %0, mcycleh" : "=r"(hi1));
- if (hi == hi1) {
- val = ((unsigned long long)hi << 32) | lo;
- }
-#else
- __asm__ volatile ("csrr %0, mcycle" : "=r"(val));
-#endif
-
- return val;
-}
-
-unsigned long long __metal_driver_cpu_timebase_get(struct metal_cpu *cpu)
-{
- int timebase;
- if (!cpu) {
- return 0;
- }
-
- timebase = __metal_driver_cpu_timebase((struct metal_cpu *)cpu);
- return timebase;
-}
-
-unsigned long long __metal_driver_cpu_mtime_get (struct metal_cpu *cpu)
-{
- unsigned long long time = 0;
- struct metal_interrupt *tmr_intc;
- struct __metal_driver_riscv_cpu_intc *intc =
- (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
-
- if (intc) {
- tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int;
- if (tmr_intc) {
- tmr_intc->vtable->command_request(tmr_intc,
- METAL_TIMER_MTIME_GET, &time);
- }
- }
- return time;
-}
-
-int __metal_driver_cpu_mtimecmp_set (struct metal_cpu *cpu, unsigned long long time)
-{
- int rc = -1;
- struct metal_interrupt *tmr_intc;
- struct __metal_driver_riscv_cpu_intc *intc =
- (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
-
- if (intc) {
- tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int;
- if (tmr_intc) {
- rc = tmr_intc->vtable->mtimecmp_set(tmr_intc,
- __metal_driver_cpu_hartid(cpu),
- time);
- }
- }
- return rc;
-}
-
-struct metal_interrupt *
-__metal_driver_cpu_timer_controller_interrupt(struct metal_cpu *cpu)
-{
-#ifdef __METAL_DT_RISCV_CLINT0_HANDLE
- return __METAL_DT_RISCV_CLINT0_HANDLE;
-#else
-#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
- return __METAL_DT_SIFIVE_CLIC0_HANDLE;
-#else
-#pragma message("There is no interrupt controller for Timer interrupt")
- return NULL;
-#endif
-#endif
-}
-
-int __metal_driver_cpu_get_timer_interrupt_id(struct metal_cpu *cpu)
-{
- return METAL_INTERRUPT_ID_TMR;
-}
-
-struct metal_interrupt *
-__metal_driver_cpu_sw_controller_interrupt(struct metal_cpu *cpu)
-{
-#ifdef __METAL_DT_RISCV_CLINT0_HANDLE
- return __METAL_DT_RISCV_CLINT0_HANDLE;
-#else
-#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
- return __METAL_DT_SIFIVE_CLIC0_HANDLE;
-#else
-#pragma message("There is no interrupt controller for Software interrupt")
- return NULL;
-#endif
-#endif
-}
-
-int __metal_driver_cpu_get_sw_interrupt_id(struct metal_cpu *cpu)
-{
- return METAL_INTERRUPT_ID_SW;
-}
-
-int __metal_driver_cpu_set_sw_ipi (struct metal_cpu *cpu, int hartid)
-{
- int rc = -1;
- struct metal_interrupt *sw_intc;
- struct __metal_driver_riscv_cpu_intc *intc =
- (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
-
- if (intc) {
- sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
- if (sw_intc) {
- rc = sw_intc->vtable->command_request(sw_intc,
- METAL_SOFTWARE_IPI_SET, &hartid);
- }
- }
- return rc;
-}
-
-int __metal_driver_cpu_clear_sw_ipi (struct metal_cpu *cpu, int hartid)
-{
- int rc = -1;
- struct metal_interrupt *sw_intc;
- struct __metal_driver_riscv_cpu_intc *intc =
- (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
-
- if (intc) {
- sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
- if (sw_intc) {
- rc = sw_intc->vtable->command_request(sw_intc,
- METAL_SOFTWARE_IPI_CLEAR, &hartid);
- }
- }
- return rc;
-}
-
-int __metal_driver_cpu_get_msip (struct metal_cpu *cpu, int hartid)
-{
- int rc = 0;
- struct metal_interrupt *sw_intc;
- struct __metal_driver_riscv_cpu_intc *intc =
- (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
-
- if (intc) {
- sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
- if (sw_intc) {
- rc = sw_intc->vtable->command_request(sw_intc,
- METAL_SOFTWARE_MSIP_GET, &hartid);
- }
- }
- return rc;
-}
-
-struct metal_interrupt *
-__metal_driver_cpu_controller_interrupt(struct metal_cpu *cpu)
-{
- return __metal_driver_cpu_interrupt_controller(cpu);
-}
-
-int __metal_driver_cpu_enable_interrupt(struct metal_cpu *cpu, void *priv)
-{
- if ( __metal_driver_cpu_interrupt_controller(cpu) ) {
- /* Only support machine mode for now */
- __metal_interrupt_global_enable();
- return 0;
- }
- return -1;
-}
-
-int __metal_driver_cpu_disable_interrupt(struct metal_cpu *cpu, void *priv)
-{
- if ( __metal_driver_cpu_interrupt_controller(cpu) ) {
- /* Only support machine mode for now */
- __metal_interrupt_global_disable();
- return 0;
- }
- return -1;
-}
-
-int __metal_driver_cpu_exception_register(struct metal_cpu *cpu, int ecode,
- metal_exception_handler_t isr)
-{
- struct __metal_driver_riscv_cpu_intc *intc =
- (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
-
- if (intc) {
- return __metal_exception_register((struct metal_interrupt *)intc, ecode, isr);
- }
- return -1;
-}
-
-int __metal_driver_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
-{
- /**
- * Per ISA compressed instruction has last two bits of opcode set.
- * The encoding '00' '01' '10' are used for compressed instruction.
- * Only enconding '11' isn't regarded as compressed instruction (>16b).
- */
- return ((*(unsigned short*)epc & METAL_INSN_LENGTH_MASK)
- == METAL_INSN_NOT_COMPRESSED) ? 4 : 2;
-}
-
-uintptr_t __metal_driver_cpu_get_exception_pc(struct metal_cpu *cpu)
-{
- uintptr_t mepc;
- __asm__ volatile ("csrr %0, mepc" : "=r"(mepc));
- return mepc;
-}
-
-int __metal_driver_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t mepc)
-{
- __asm__ volatile ("csrw mepc, %0" :: "r"(mepc));
- return 0;
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_cpu_intc) = {
- .controller_vtable.interrupt_init = __metal_driver_riscv_cpu_controller_interrupt_init,
- .controller_vtable.interrupt_register = __metal_driver_riscv_cpu_controller_interrupt_register,
- .controller_vtable.interrupt_enable = __metal_driver_riscv_cpu_controller_interrupt_enable,
- .controller_vtable.interrupt_disable = __metal_driver_riscv_cpu_controller_interrupt_disable,
- .controller_vtable.interrupt_get_vector_mode = __metal_driver_riscv_cpu_controller_get_vector_mode,
- .controller_vtable.interrupt_set_vector_mode = __metal_driver_riscv_cpu_controller_set_vector_mode,
- .controller_vtable.command_request = __metal_driver_riscv_cpu_controller_command_request,
-};
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_cpu) = {
- .cpu_vtable.mcycle_get = __metal_driver_cpu_mcycle_get,
- .cpu_vtable.timebase_get = __metal_driver_cpu_timebase_get,
- .cpu_vtable.mtime_get = __metal_driver_cpu_mtime_get,
- .cpu_vtable.mtimecmp_set = __metal_driver_cpu_mtimecmp_set,
- .cpu_vtable.tmr_controller_interrupt = __metal_driver_cpu_timer_controller_interrupt,
- .cpu_vtable.get_tmr_interrupt_id = __metal_driver_cpu_get_timer_interrupt_id,
- .cpu_vtable.sw_controller_interrupt = __metal_driver_cpu_sw_controller_interrupt,
- .cpu_vtable.get_sw_interrupt_id = __metal_driver_cpu_get_sw_interrupt_id,
- .cpu_vtable.set_sw_ipi = __metal_driver_cpu_set_sw_ipi,
- .cpu_vtable.clear_sw_ipi = __metal_driver_cpu_clear_sw_ipi,
- .cpu_vtable.get_msip = __metal_driver_cpu_get_msip,
- .cpu_vtable.controller_interrupt = __metal_driver_cpu_controller_interrupt,
- .cpu_vtable.exception_register = __metal_driver_cpu_exception_register,
- .cpu_vtable.get_ilen = __metal_driver_cpu_get_instruction_length,
- .cpu_vtable.get_epc = __metal_driver_cpu_get_exception_pc,
- .cpu_vtable.set_epc = __metal_driver_cpu_set_exception_pc,
-};
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_RISCV_PLIC0
-
-#include <metal/io.h>
-#include <metal/shutdown.h>
-#include <metal/drivers/riscv_plic0.h>
-#include <metal/machine.h>
-
-unsigned int __metal_plic0_claim_interrupt (struct __metal_driver_riscv_plic0 *plic)
-{
- unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
- return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- METAL_RISCV_PLIC0_CLAIM));
-}
-
-void __metal_plic0_complete_interrupt(struct __metal_driver_riscv_plic0 *plic,
- unsigned int id)
-{
- unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- METAL_RISCV_PLIC0_CLAIM)) = id;
-}
-
-int __metal_plic0_set_threshold(struct metal_interrupt *controller, unsigned int threshold)
-{
- unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller);
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- METAL_RISCV_PLIC0_THRESHOLD)) = threshold;
- return 0;
-}
-
-unsigned int __metal_plic0_get_threshold(struct metal_interrupt *controller)
-{
- unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller);
-
- return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- METAL_RISCV_PLIC0_THRESHOLD));
-}
-
-int __metal_plic0_set_priority(struct metal_interrupt *controller, int id, unsigned int priority)
-{
- unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)controller);
- unsigned int max_priority = __metal_driver_sifive_plic0_max_priority((struct metal_interrupt *)controller);
- if ( (max_priority) && (priority < max_priority) ) {
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- METAL_RISCV_PLIC0_PRIORITY_BASE +
- (id << METAL_PLIC_SOURCE_PRIORITY_SHIFT))) = priority;
- return 0;
- }
- return -1;
-}
-
-unsigned int __metal_plic0_get_priority(struct metal_interrupt *controller, int id)
-{
- unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller);
-
- return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- METAL_RISCV_PLIC0_PRIORITY_BASE +
- (id << METAL_PLIC_SOURCE_PRIORITY_SHIFT)));
-}
-
-void __metal_plic0_enable(struct __metal_driver_riscv_plic0 *plic, int id, int enable)
-{
- unsigned int current;
- unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
-
- current = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- METAL_RISCV_PLIC0_ENABLE_BASE +
- (id >> METAL_PLIC_SOURCE_SHIFT) * 4));
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- METAL_RISCV_PLIC0_ENABLE_BASE +
- ((id >> METAL_PLIC_SOURCE_SHIFT) * 4))) =
- enable ? (current | (1 << (id & METAL_PLIC_SOURCE_MASK)))
- : (current & ~(1 << (id & METAL_PLIC_SOURCE_MASK)));
-}
-
-void __metal_plic0_default_handler (int id, void *priv) {
- metal_shutdown(300);
-}
-
-void __metal_plic0_handler (int id, void *priv)
-{
- struct __metal_driver_riscv_plic0 *plic = priv;
- unsigned int idx = __metal_plic0_claim_interrupt(plic);
- unsigned int num_interrupts = __metal_driver_sifive_plic0_num_interrupts((struct metal_interrupt *)plic);
-
- if ( (idx < num_interrupts) && (plic->metal_exint_table[idx]) ) {
- plic->metal_exint_table[idx](idx,
- plic->metal_exdata_table[idx].exint_data);
- }
-
- __metal_plic0_complete_interrupt(plic, idx);
-}
-
-void __metal_driver_riscv_plic0_init (struct metal_interrupt *controller)
-{
- struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
-
- if ( !plic->init_done ) {
- int num_interrupts, line;
- struct metal_interrupt *intc;
-
- for(int parent = 0; parent < __METAL_PLIC_NUM_PARENTS; parent++) {
- num_interrupts = __metal_driver_sifive_plic0_num_interrupts(controller);
- intc = __metal_driver_sifive_plic0_interrupt_parents(controller, parent);
- line = __metal_driver_sifive_plic0_interrupt_lines(controller, parent);
-
- /* Initialize ist parent controller, aka cpu_intc. */
- intc->vtable->interrupt_init(intc);
-
- for (int i = 0; i < num_interrupts; i++) {
- __metal_plic0_enable(plic, i, METAL_DISABLE);
- __metal_plic0_set_priority(controller, i, 0);
- plic->metal_exint_table[i] = NULL;
- plic->metal_exdata_table[i].sub_int = NULL;
- plic->metal_exdata_table[i].exint_data = NULL;
- }
-
- __metal_plic0_set_threshold(controller, 0);
-
- /* Register plic (ext) interrupt with with parent controller */
- intc->vtable->interrupt_register(intc, line, NULL, plic);
- /* Register plic handler for dispatching its device interrupts */
- intc->vtable->interrupt_register(intc, line, __metal_plic0_handler, plic);
- /* Enable plic (ext) interrupt with with parent controller */
- intc->vtable->interrupt_enable(intc, line);
- }
- plic->init_done = 1;
- }
-}
-
-int __metal_driver_riscv_plic0_register (struct metal_interrupt *controller,
- int id, metal_interrupt_handler_t isr,
- void *priv)
-{
- struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
-
- if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
- return -1;
- }
-
- if (isr) {
- __metal_plic0_set_priority(controller, id, 2);
- plic->metal_exint_table[id] = isr;
- plic->metal_exdata_table[id].exint_data = priv;
- } else {
- __metal_plic0_set_priority(controller, id, 1);
- plic->metal_exint_table[id] = __metal_plic0_default_handler;
- plic->metal_exdata_table[id].sub_int = priv;
- }
-
- return 0;
-}
-
-int __metal_driver_riscv_plic0_enable (struct metal_interrupt *controller, int id)
-{
- struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
-
- if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
- return -1;
- }
-
- __metal_plic0_enable(plic, id, METAL_ENABLE);
- return 0;
-}
-
-int __metal_driver_riscv_plic0_disable (struct metal_interrupt *controller, int id)
-{
- struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
-
- if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
- return -1;
- }
- __metal_plic0_enable(plic, id, METAL_DISABLE);
- return 0;
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_plic0) = {
- .plic_vtable.interrupt_init = __metal_driver_riscv_plic0_init,
- .plic_vtable.interrupt_register = __metal_driver_riscv_plic0_register,
- .plic_vtable.interrupt_enable = __metal_driver_riscv_plic0_enable,
- .plic_vtable.interrupt_disable = __metal_driver_riscv_plic0_disable,
- .plic_vtable.interrupt_get_threshold = __metal_plic0_get_threshold,
- .plic_vtable.interrupt_set_threshold = __metal_plic0_set_threshold,
- .plic_vtable.interrupt_get_priority = __metal_plic0_get_priority,
- .plic_vtable.interrupt_set_priority = __metal_plic0_set_priority,
-};
-
-#endif /* METAL_RISCV_PLIC0 */
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_CCACHE0
-
-#include <stdint.h>
-#include <metal/io.h>
-#include <metal/drivers/sifive_ccache0.h>
-#include <metal/machine.h>
-
-#define L2_CONFIG_WAYS_SHIFT 8
-#define L2_CONFIG_WAYS_MASK (0xFF << L2_CONFIG_WAYS_SHIFT)
-
-void __metal_driver_sifive_ccache0_init(struct metal_cache *l2, int ways);
-
-static void metal_driver_sifive_ccache0_init(void) __attribute__((constructor));
-static void metal_driver_sifive_ccache0_init(void)
-{
-#ifdef __METAL_DT_SIFIVE_CCACHE0_HANDLE
- /* Get the handle for the L2 cache controller */
- struct metal_cache *l2 = __METAL_DT_SIFIVE_CCACHE0_HANDLE;
- if(!l2) {
- return;
- }
-
- /* Get the number of available ways per bank */
- unsigned long control_base = __metal_driver_sifive_ccache0_control_base(l2);
- uint32_t ways = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_CONFIG));
- ways = ((ways & L2_CONFIG_WAYS_MASK) >> L2_CONFIG_WAYS_SHIFT);
-
- /* Enable all the ways */
- __metal_driver_sifive_ccache0_init(l2, ways);
-#endif
-}
-
-void __metal_driver_sifive_ccache0_init(struct metal_cache *l2, int ways)
-{
- metal_cache_set_enabled_ways(l2, ways);
-}
-
-int __metal_driver_sifive_ccache0_get_enabled_ways(struct metal_cache *cache)
-{
- unsigned long control_base = __metal_driver_sifive_ccache0_control_base(cache);
-
- uint32_t way_enable = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_WAYENABLE));
-
- /* The stored number is the index, so add one */
- return (0xFF & way_enable) + 1;
-}
-
-int __metal_driver_sifive_ccache0_set_enabled_ways(struct metal_cache *cache, int ways)
-{
- unsigned long control_base = __metal_driver_sifive_ccache0_control_base(cache);
-
- /* We can't decrease the number of enabled ways */
- if(metal_cache_get_enabled_ways(cache) > ways) {
- return -2;
- }
-
- /* The stored value is the index, so subtract one */
- uint32_t value = 0xFF & (ways - 1);
-
- /* Set the number of enabled ways */
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_WAYENABLE)) = value;
-
- /* Make sure the number of ways was set correctly */
- if(metal_cache_get_enabled_ways(cache) != ways) {
- return -3;
- }
-
- return 0;
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_ccache0) = {
- .cache.init = __metal_driver_sifive_ccache0_init,
- .cache.get_enabled_ways = __metal_driver_sifive_ccache0_get_enabled_ways,
- .cache.set_enabled_ways = __metal_driver_sifive_ccache0_set_enabled_ways,
-};
-
-#endif
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_CLIC0
-
-#include <stdint.h>
-#include <metal/io.h>
-#include <metal/shutdown.h>
-#include <metal/drivers/sifive_clic0.h>
-#include <metal/machine.h>
-
-typedef enum metal_clic_vector_{
- METAL_CLIC_NONVECTOR = 0,
- METAL_CLIC_VECTORED = 1
-} metal_clic_vector;
-
-struct __metal_clic_cfg {
- unsigned char : 1,
- nmbits : 2,
- nlbits : 4,
- nvbit : 1;
-};
-
-const struct __metal_clic_cfg __metal_clic_defaultcfg = {
- .nmbits = METAL_INTR_PRIV_M_MODE,
- .nlbits = 0,
- .nvbit = METAL_CLIC_NONVECTOR
- };
-
-void __metal_clic0_handler(int id, void *priv) __attribute__((aligned(64)));
-
-void __metal_clic0_default_vector_handler (void) __attribute__((interrupt, aligned(64)));
-
-struct __metal_clic_cfg __metal_clic0_configuration (struct __metal_driver_sifive_clic0 *clic,
- struct __metal_clic_cfg *cfg)
-{
- volatile unsigned char val;
- struct __metal_clic_cfg cliccfg;
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
-
- if ( cfg ) {
- val = cfg->nmbits << 5 | cfg->nlbits << 1 | cfg->nvbit;
- __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICCFG)) = val;
- }
- val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICCFG));
- cliccfg.nmbits = (val & METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MASK) >> 5;
- cliccfg.nlbits = (val & METAL_SIFIVE_CLIC0_CLICCFG_NLBITS_MASK) >> 1;
- cliccfg.nvbit = val & METAL_SIFIVE_CLIC0_CLICCFG_NVBIT_MASK;
- return cliccfg;
-}
-
-int __metal_clic0_interrupt_set_mode (struct __metal_driver_sifive_clic0 *clic, int id, int mode)
-{
- uint8_t mask, val;
- struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
-
- if (mode >= (cfg.nmbits << 1)) {
- /* Do nothing, mode request same or exceed what configured in CLIC */
- return 0;
- }
-
- /* Mask out nmbits and retain other values */
- mask = ((uint8_t)(-1)) >> cfg.nmbits;
- val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) & mask;
- __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = val | (mode << (8 - cfg.nmbits));
- return 0;
-}
-
-int __metal_clic0_interrupt_set_level (struct __metal_driver_sifive_clic0 *clic, int id, unsigned int level)
-{
- uint8_t mask, nmmask, nlmask, val;
- struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
-
- /* Drop the LSBs that don't fit in nlbits */
- level = level >> (METAL_CLIC_MAX_NLBITS - cfg.nlbits);
-
- nmmask = ~( ((uint8_t)(-1)) >> (cfg.nmbits) );
- nlmask = ((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits);
- mask = ~(nlmask | nmmask);
-
- val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
- __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, level);
- return 0;
-}
-
-unsigned int __metal_clic0_interrupt_get_level (struct __metal_driver_sifive_clic0 *clic, int id)
-{
- int level;
- uint8_t mask, val, freebits, nlbits;
- struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
- int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
-
- if ((cfg.nmbits + cfg.nlbits) >= num_intbits) {
- nlbits = num_intbits - cfg.nmbits;
- } else {
- nlbits = cfg.nlbits;
- }
-
- mask = ((1 << nlbits) - 1) << (8 - (cfg.nmbits + nlbits));
- freebits = ((1 << METAL_CLIC_MAX_NLBITS) - 1) >> nlbits;
-
- if (mask == 0) {
- level = (1 << METAL_CLIC_MAX_NLBITS) - 1;
- } else {
- val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
- val = __METAL_GET_FIELD(val, mask);
- level = (val << (METAL_CLIC_MAX_NLBITS - nlbits)) | freebits;
- }
-
- return level;
-}
-
-int __metal_clic0_interrupt_set_priority (struct __metal_driver_sifive_clic0 *clic, int id, int priority)
-{
- uint8_t mask, npmask, val, npbits;
- struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
- int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
-
- if ((cfg.nmbits + cfg.nlbits) < num_intbits) {
- npbits = num_intbits - (cfg.nmbits + cfg.nlbits);
- priority = priority >> (8 - npbits);
-
- mask = ((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits + npbits);
- npmask = ~(((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits));
- mask = ~(mask | npmask);
-
- val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
- __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, priority);
- }
- return 0;
-}
-
-int __metal_clic0_interrupt_get_priority (struct __metal_driver_sifive_clic0 *clic, int id)
-{
- int priority;
- uint8_t mask, val, freebits, nlbits;
- struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
- int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
-
- if ((cfg.nmbits + cfg.nlbits) >= num_intbits) {
- nlbits = num_intbits - cfg.nmbits;
- } else {
- nlbits = cfg.nlbits;
- }
-
- mask = ((1 << nlbits) - 1) << (8 - (cfg.nmbits + nlbits));
- freebits = ((1 << METAL_CLIC_MAX_NLBITS) - 1) >> nlbits;
-
- if (mask == 0) {
- priority = (1 << METAL_CLIC_MAX_NLBITS) - 1;
- } else {
- val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
- priority = __METAL_GET_FIELD(val, freebits);
- }
- return priority;
-}
-
-int __metal_clic0_interrupt_set_vector_mode (struct __metal_driver_sifive_clic0 *clic, int id, int enable)
-{
- uint8_t mask, val;
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
- int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
-
- mask = 1 << (8 - num_intbits);
- val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
- /* Ensure its value is 1 bit wide */
- enable &= 0x1;
- __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, enable);
- return 0;
-}
-
-int __metal_clic0_interrupt_is_vectored (struct __metal_driver_sifive_clic0 *clic, int id)
-{
- uint8_t mask, val;
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
- int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
-
- mask = 1 << (8 - num_intbits);
- val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
- return __METAL_GET_FIELD(val, mask);
-}
-
-int __metal_clic0_interrupt_enable (struct __metal_driver_sifive_clic0 *clic, int id)
-{
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
- int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
-
- if (id >= num_subinterrupts) {
- return -1;
- }
- __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id)) = METAL_ENABLE;
- return 0;
-}
-
-int __metal_clic0_interrupt_disable (struct __metal_driver_sifive_clic0 *clic, int id)
-{
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
- int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
-
- if (id >= num_subinterrupts) {
- return -1;
- }
- __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id)) = METAL_DISABLE;
- return 0;
-}
-
-int __metal_clic0_interrupt_is_enabled (struct __metal_driver_sifive_clic0 *clic, int id)
-{
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
- int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
-
- if (id >= num_subinterrupts) {
- return 0;
- }
- return __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id));
-}
-
-int __metal_clic0_interrupt_is_pending (struct __metal_driver_sifive_clic0 *clic, int id)
-{
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
- int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
-
- if (id >= num_subinterrupts) {
- return 0;
- }
- return __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id));
-}
-
-int __metal_clic0_interrupt_set (struct __metal_driver_sifive_clic0 *clic, int id)
-{
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
- int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
-
- if (id < num_subinterrupts) {
- __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id)) = METAL_ENABLE;
- return 0;
- }
- return -1;
-}
-
-int __metal_clic0_interrupt_clear (struct __metal_driver_sifive_clic0 *clic, int id)
-{
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
- int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
-
- if (id < num_subinterrupts) {
- __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id)) = METAL_DISABLE;
- return 0;
- }
- return -1;
-}
-
-int __metal_clic0_configure_set_vector_mode (struct __metal_driver_sifive_clic0 *clic, metal_vector_mode mode)
-{
- struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
-
- switch (mode) {
- case METAL_SELECTIVE_NONVECTOR_MODE:
- cfg.nvbit = METAL_CLIC_NONVECTOR;
- __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
- break;
- case METAL_SELECTIVE_VECTOR_MODE:
- cfg.nvbit = METAL_CLIC_VECTORED;
- __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
- break;
- case METAL_HARDWARE_VECTOR_MODE:
- cfg.nvbit = METAL_CLIC_VECTORED;
- __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
- break;
- default:
- return -1;
- }
- __metal_clic0_configuration(clic, &cfg);
- return 0;
-}
-
-metal_vector_mode __metal_clic0_configure_get_vector_mode (struct __metal_driver_sifive_clic0 *clic)
-{
- struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
- metal_vector_mode mode = __metal_controller_interrupt_vector_mode();
-
- if (mode == METAL_SELECTIVE_VECTOR_MODE) {
- if (cfg.nvbit) {
- return METAL_SELECTIVE_VECTOR_MODE;
- } else {
- return METAL_SELECTIVE_NONVECTOR_MODE;
- }
- } else {
- return mode;
- }
-}
-
-int __metal_clic0_configure_set_privilege (struct __metal_driver_sifive_clic0 *clic, metal_intr_priv_mode priv)
-{
- struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
-
- cfg.nmbits = priv;
- __metal_clic0_configuration(clic, &cfg);
- return 0;
-}
-
-metal_intr_priv_mode __metal_clic0_configure_get_privilege (struct __metal_driver_sifive_clic0 *clic)
-{
- struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
-
- return cfg.nmbits;
-}
-
-int __metal_clic0_configure_set_level (struct __metal_driver_sifive_clic0 *clic, int level)
-{
- struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
-
- cfg.nlbits = level & 0xF;
- __metal_clic0_configuration(clic, &cfg);
- return 0;
-}
-
-int __metal_clic0_configure_get_level (struct __metal_driver_sifive_clic0 *clic)
-{
- struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
-
- return cfg.nlbits;
-}
-
-unsigned long long __metal_clic0_mtime_get (struct __metal_driver_sifive_clic0 *clic)
-{
- __metal_io_u32 lo, hi;
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
-
- /* Guard against rollover when reading */
- do {
- hi = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME + 4));
- lo = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME));
- } while (__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME + 4)) != hi);
-
- return (((unsigned long long)hi) << 32) | lo;
-}
-
-int __metal_driver_sifive_clic0_mtimecmp_set(struct metal_interrupt *controller,
- int hartid,
- unsigned long long time)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
-
- unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
- /* Per spec, the RISC-V MTIME/MTIMECMP registers are 64 bit,
- * and are NOT internally latched for multiword transfers.
- * Need to be careful about sequencing to avoid triggering
- * spurious interrupts: For that set the high word to a max
- * value first.
- */
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE + 4)) = 0xFFFFFFFF;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE)) = (__metal_io_u32)time;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE + 4)) = (__metal_io_u32)(time >> 32);
- return 0;
-}
-
-void __metal_clic0_handler (int id, void *priv)
-{
- struct __metal_driver_sifive_clic0 *clic = priv;
- int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
-
- if ( (id < num_subinterrupts) && (clic->metal_exint_table[id].handler) ) {
- clic->metal_exint_table[id].handler(id, clic->metal_exint_table[id].exint_data);
- }
-}
-
-void __metal_clic0_default_handler (int id, void *priv) {
- metal_shutdown(300);
-}
-
-void __metal_clic0_default_vector_handler (void) {
- metal_shutdown(400);
-}
-
-void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
-
- if ( !clic->init_done ) {
- int level, max_levels, line, num_interrupts, num_subinterrupts;
- struct __metal_clic_cfg cfg = __metal_clic_defaultcfg;
- struct metal_interrupt *intc =
- __metal_driver_sifive_clic0_interrupt_parent(controller);
-
- /* Initialize ist parent controller, aka cpu_intc. */
- intc->vtable->interrupt_init(intc);
- __metal_controller_interrupt_vector(METAL_SELECTIVE_NONVECTOR_MODE,
- &clic->metal_mtvt_table);
-
- /*
- * Register its interrupts with with parent controller,
- * aka sw, timer and ext to its default isr
- */
- num_interrupts = __metal_driver_sifive_clic0_num_interrupts(controller);
- for (int i = 0; i < num_interrupts; i++) {
- line = __metal_driver_sifive_clic0_interrupt_lines(controller, i);
- intc->vtable->interrupt_register(intc, line, NULL, clic);
- }
-
- /* Default CLIC mode to per dts */
- max_levels = __metal_driver_sifive_clic0_max_levels(controller);
- cfg.nlbits = (max_levels > METAL_CLIC_MAX_NLBITS) ?
- METAL_CLIC_MAX_NLBITS : max_levels;
- __metal_clic0_configuration(clic, &cfg);
-
- level = (1 << cfg.nlbits) - 1;
- num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
- clic->metal_mtvt_table[0] = &__metal_clic0_handler;
- for (int i = 1; i < num_subinterrupts; i++) {
- clic->metal_mtvt_table[i] = NULL;
- clic->metal_exint_table[i].handler = NULL;
- clic->metal_exint_table[i].sub_int = NULL;
- clic->metal_exint_table[i].exint_data = NULL;
- __metal_clic0_interrupt_disable(clic, i);
- __metal_clic0_interrupt_set_level(clic, i, level);
- }
- clic->init_done = 1;
- }
-}
-
-int __metal_driver_sifive_clic0_register (struct metal_interrupt *controller,
- int id, metal_interrupt_handler_t isr,
- void *priv)
-{
- int rc = -1;
- int num_subinterrupts;
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- struct metal_interrupt *intc =
- __metal_driver_sifive_clic0_interrupt_parent(controller);
- metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic);
-
- if ( ( (mode == METAL_SELECTIVE_VECTOR_MODE) &&
- (__metal_clic0_interrupt_is_vectored(clic, id)) ) ||
- (mode == METAL_HARDWARE_VECTOR_MODE) ||
- (mode == METAL_VECTOR_MODE) ||
- (mode == METAL_DIRECT_MODE) ) {
- return rc;
- }
-
- /* Register its interrupts with parent controller */
- if (id < METAL_INTERRUPT_ID_CSW) {
- return intc->vtable->interrupt_register(intc, id, isr, priv);
- }
-
- /*
- * CLIC (sub-interrupts) devices interrupts start at 16 but offset from 0
- * Reset the IDs to reflects this.
- */
- num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
- if (id < num_subinterrupts) {
- if ( isr) {
- clic->metal_exint_table[id].handler = isr;
- clic->metal_exint_table[id].exint_data = priv;
- } else {
- clic->metal_exint_table[id].handler = __metal_clic0_default_handler;
- clic->metal_exint_table[id].sub_int = priv;
- }
- rc = 0;
- }
- return rc;
-}
-
-int __metal_driver_sifive_clic0_vector_register (struct metal_interrupt *controller,
- int id, metal_interrupt_vector_handler_t isr,
- void *priv)
-{
- int rc = -1;
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- struct metal_interrupt *intc =
- __metal_driver_sifive_clic0_interrupt_parent(controller);
- int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
- metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic);
-
- if ((mode != METAL_SELECTIVE_VECTOR_MODE) && (mode != METAL_HARDWARE_VECTOR_MODE)) {
- return rc;
- }
- if ((mode == METAL_SELECTIVE_VECTOR_MODE) &&
- (__metal_clic0_interrupt_is_vectored(clic, id) == 0) ) {
- return rc;
- }
- if (id < num_subinterrupts) {
- if ( isr) {
- clic->metal_mtvt_table[id] = isr;
- clic->metal_exint_table[id].exint_data = priv;
- } else {
- clic->metal_mtvt_table[id] = __metal_clic0_default_vector_handler;
- clic->metal_exint_table[id].sub_int = priv;
- }
- rc = 0;
- }
- return rc;
-}
-
-int __metal_driver_sifive_clic0_enable (struct metal_interrupt *controller, int id)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- return __metal_clic0_interrupt_enable(clic, id);
-}
-
-int __metal_driver_sifive_clic0_disable (struct metal_interrupt *controller, int id)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- return __metal_clic0_interrupt_disable(clic, id);
-}
-
-int __metal_driver_sifive_clic0_enable_interrupt_vector(struct metal_interrupt *controller, int id)
-{
- int rc = -1;
- int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic);
-
- if ((mode != METAL_SELECTIVE_VECTOR_MODE) && (mode != METAL_HARDWARE_VECTOR_MODE)) {
- return rc;
- }
- if (id < num_subinterrupts) {
- __metal_clic0_interrupt_set_vector_mode(clic, id, METAL_ENABLE);
- return 0;
- }
- return -1;
-}
-
-int __metal_driver_sifive_clic0_disable_interrupt_vector(struct metal_interrupt *controller, int id)
-{
- int num_subinterrupts;
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
-
- num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
- if (id < num_subinterrupts) {
- __metal_clic0_interrupt_set_vector_mode(clic, id, METAL_DISABLE);
- return 0;
- }
- return -1;
-}
-
-metal_vector_mode __metal_driver_sifive_clic0_get_vector_mode (struct metal_interrupt *controller)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- return __metal_clic0_configure_get_vector_mode(clic);
-}
-
-int __metal_driver_sifive_clic0_set_vector_mode (struct metal_interrupt *controller, metal_vector_mode mode)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- return __metal_clic0_configure_set_vector_mode(clic, mode);
-}
-
-metal_intr_priv_mode __metal_driver_sifive_clic0_get_privilege (struct metal_interrupt *controller)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- return __metal_clic0_configure_get_privilege(clic);
-}
-
-int __metal_driver_sifive_clic0_set_privilege (struct metal_interrupt *controller, metal_intr_priv_mode priv)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- return __metal_clic0_configure_set_privilege(clic, priv);
-}
-
-unsigned int __metal_driver_sifive_clic0_get_threshold (struct metal_interrupt *controller)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- return __metal_clic0_configure_get_level(clic);
-}
-
-int __metal_driver_sifive_clic0_set_threshold (struct metal_interrupt *controller, unsigned int level)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- return __metal_clic0_configure_set_level(clic, level);
-}
-
-unsigned int __metal_driver_sifive_clic0_get_priority (struct metal_interrupt *controller, int id)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- return __metal_clic0_interrupt_get_priority(clic, id);
-}
-
-int __metal_driver_sifive_clic0_set_priority (struct metal_interrupt *controller, int id, unsigned int priority)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- return __metal_clic0_interrupt_set_priority(clic, id, priority);
-}
-
-int __metal_driver_sifive_clic0_clear_interrupt (struct metal_interrupt *controller, int id)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- return __metal_clic0_interrupt_clear(clic, id);
-}
-
-int __metal_driver_sifive_clic0_set_interrupt (struct metal_interrupt *controller, int id)
-{
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- return __metal_clic0_interrupt_set(clic, id);
-}
-
-int __metal_driver_sifive_clic0_command_request (struct metal_interrupt *controller,
- int command, void *data)
-{
- int hartid;
- int rc = -1;
- struct __metal_driver_sifive_clic0 *clic =
- (struct __metal_driver_sifive_clic0 *)(controller);
- unsigned long control_base = __metal_driver_sifive_clic0_control_base(controller);
-
- switch (command) {
- case METAL_TIMER_MTIME_GET:
- if (data) {
- *(unsigned long long *)data = __metal_clic0_mtime_get(clic);
- rc = 0;
- }
- break;
- case METAL_SOFTWARE_IPI_CLEAR:
- if (data) {
- hartid = *(int *)data;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- (hartid * 4))) = METAL_DISABLE;
- __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTIP_BASE)) = METAL_DISABLE;
- rc = 0;
- }
- break;
- case METAL_SOFTWARE_IPI_SET:
- if (data) {
- hartid = *(int *)data;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- (hartid * 4))) = METAL_ENABLE;
- __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
- METAL_SIFIVE_CLIC0_MMODE_APERTURE +
- METAL_SIFIVE_CLIC0_CLICINTIP_BASE)) = METAL_ENABLE;
- rc = 0;
- }
- break;
- case METAL_SOFTWARE_MSIP_GET:
- rc = 0;
- if (data) {
- hartid = *(int *)data;
- rc = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
- (hartid * 4)));
- }
- break;
- default:
- break;
- }
-
- return rc;
-}
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_clic0) = {
- .clic_vtable.interrupt_init = __metal_driver_sifive_clic0_init,
- .clic_vtable.interrupt_register = __metal_driver_sifive_clic0_register,
- .clic_vtable.interrupt_vector_register = __metal_driver_sifive_clic0_vector_register,
- .clic_vtable.interrupt_enable = __metal_driver_sifive_clic0_enable,
- .clic_vtable.interrupt_disable = __metal_driver_sifive_clic0_disable,
- .clic_vtable.interrupt_vector_enable = __metal_driver_sifive_clic0_enable_interrupt_vector,
- .clic_vtable.interrupt_vector_disable = __metal_driver_sifive_clic0_disable_interrupt_vector,
- .clic_vtable.interrupt_get_vector_mode = __metal_driver_sifive_clic0_get_vector_mode,
- .clic_vtable.interrupt_set_vector_mode = __metal_driver_sifive_clic0_set_vector_mode,
- .clic_vtable.interrupt_get_privilege = __metal_driver_sifive_clic0_get_privilege,
- .clic_vtable.interrupt_set_privilege = __metal_driver_sifive_clic0_set_privilege,
- .clic_vtable.interrupt_get_threshold = __metal_driver_sifive_clic0_get_threshold,
- .clic_vtable.interrupt_set_threshold = __metal_driver_sifive_clic0_set_threshold,
- .clic_vtable.interrupt_get_priority = __metal_driver_sifive_clic0_get_priority,
- .clic_vtable.interrupt_set_priority = __metal_driver_sifive_clic0_set_priority,
- .clic_vtable.interrupt_clear = __metal_driver_sifive_clic0_clear_interrupt,
- .clic_vtable.interrupt_set = __metal_driver_sifive_clic0_set_interrupt,
- .clic_vtable.command_request = __metal_driver_sifive_clic0_command_request,
- .clic_vtable.mtimecmp_set = __metal_driver_sifive_clic0_mtimecmp_set,
-};
-
-#endif /* METAL_SIFIVE_CLIC0 */
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_FE310_G000_HFROSC
-
-#include <metal/drivers/sifive_fe310-g000_hfrosc.h>
-#include <metal/machine.h>
-
-#define CONFIG_DIVIDER 0x0000003FUL
-#define CONFIG_TRIM 0x001F0000UL
-#define CONFIG_ENABLE 0x40000000UL
-#define CONFIG_READY 0x80000000UL
-
-long __metal_driver_sifive_fe310_g000_hfrosc_get_rate_hz(const struct metal_clock *clock)
-{
- struct metal_clock *ref = __metal_driver_sifive_fe310_g000_hfrosc_ref(clock);
- long config_offset = __metal_driver_sifive_fe310_g000_hfrosc_config_offset(clock);
- struct __metal_driver_sifive_fe310_g000_prci *config_base =
- __metal_driver_sifive_fe310_g000_hfrosc_config_base(clock);
- const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable =
- __metal_driver_sifive_fe310_g000_prci_vtable();
- long cfg = vtable->get_reg(config_base, config_offset);
-
- if ((cfg & CONFIG_ENABLE) == 0)
- return -1;
- if ((cfg & CONFIG_READY) == 0)
- return -1;
- return metal_clock_get_rate_hz(ref) / ((cfg & CONFIG_DIVIDER) + 1);
-}
-
-long __metal_driver_sifive_fe310_g000_hfrosc_set_rate_hz(struct metal_clock *clock, long rate)
-{
- return __metal_driver_sifive_fe310_g000_hfrosc_get_rate_hz(clock);
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfrosc) = {
- .clock.get_rate_hz = &__metal_driver_sifive_fe310_g000_hfrosc_get_rate_hz,
- .clock.set_rate_hz = &__metal_driver_sifive_fe310_g000_hfrosc_set_rate_hz,
-};
-#endif /* METAL_SIFIVE_FE310_G000_HFROSC */
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_FE310_G000_HFXOSC
-
-#include <metal/drivers/sifive_fe310-g000_hfxosc.h>
-#include <metal/machine.h>
-
-#define CONFIG_ENABLE 0x40000000UL
-#define CONFIG_READY 0x80000000UL
-
-long __metal_driver_sifive_fe310_g000_hfxosc_get_rate_hz(const struct metal_clock *clock)
-{
- struct metal_clock *ref = __metal_driver_sifive_fe310_g000_hfxosc_ref(clock);
- long config_offset = __metal_driver_sifive_fe310_g000_hfxosc_config_offset(clock);
- struct __metal_driver_sifive_fe310_g000_prci *config_base =
- __metal_driver_sifive_fe310_g000_hfxosc_config_base(clock);
- const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable =
- __metal_driver_sifive_fe310_g000_prci_vtable();
- long cfg = vtable->get_reg(config_base, config_offset);
-
- if ((cfg & CONFIG_ENABLE) == 0)
- return -1;
- if ((cfg & CONFIG_READY) == 0)
- return -1;
- return metal_clock_get_rate_hz(ref);
-}
-
-long __metal_driver_sifive_fe310_g000_hfxosc_set_rate_hz(struct metal_clock *clock, long rate)
-{
- return __metal_driver_sifive_fe310_g000_hfxosc_get_rate_hz(clock);
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfxosc) = {
- .clock.get_rate_hz = __metal_driver_sifive_fe310_g000_hfxosc_get_rate_hz,
- .clock.set_rate_hz = __metal_driver_sifive_fe310_g000_hfxosc_set_rate_hz,
-};
-
-#endif /* METAL_SIFIVE_FE310_G000_HFXOSC */
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_FE310_G000_LFROSC
-
-#include <metal/drivers/sifive_fe310-g000_lfrosc.h>
-#include <metal/machine.h>
-
-/* LFROSCCFG */
-#define METAL_LFROSCCFG_DIV_MASK 0x3F
-#define METAL_LFROSCCFG_TRIM_SHIFT 16
-#define METAL_LFROSCCFG_TRIM_MASK (0x1F << METAL_LFROSCCFG_TRIM_SHIFT)
-#define METAL_LFROSCCFG_EN (1 << 30)
-#define METAL_LFROSCCFG_RDY (1 << 31)
-
-/* LFCLKMUX */
-#define METAL_LFCLKMUX_SEL 1
-#define METAL_LFCLKMUX_EXT_MUX_STATUS (1 << 31)
-
-#define LFROSC_REGW(addr) (__METAL_ACCESS_ONCE((__metal_io_u32 *)addr))
-
-long __metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz(const struct metal_clock *clock)
-{
- struct metal_clock *internal_ref = __metal_driver_sifive_fe310_g000_lfrosc_lfrosc(clock);
- struct metal_clock *external_ref = __metal_driver_sifive_fe310_g000_lfrosc_psdlfaltclk(clock);
-
- unsigned long int cfg_reg = __metal_driver_sifive_fe310_g000_lfrosc_config_reg(clock);
- unsigned long int mux_reg = __metal_driver_sifive_fe310_g000_lfrosc_mux_reg(clock);
-
- if(LFROSC_REGW(mux_reg) & METAL_LFCLKMUX_EXT_MUX_STATUS) {
- return metal_clock_get_rate_hz(external_ref);
- }
-
- const unsigned long int div = (LFROSC_REGW(cfg_reg) & METAL_LFROSCCFG_DIV_MASK) + 1;
-
- return metal_clock_get_rate_hz(internal_ref) / div;
-}
-
-long __metal_driver_sifive_fe310_g000_lfrosc_set_rate_hz(struct metal_clock *clock, long rate)
-{
- return __metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz(clock);
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_lfrosc) = {
- .clock.get_rate_hz = &__metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz,
- .clock.set_rate_hz = &__metal_driver_sifive_fe310_g000_lfrosc_set_rate_hz,
-};
-#endif /* METAL_SIFIVE_FE310_G000_LFROSC */
-
-typedef int no_empty_translation_units;
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_FE310_G000_PLL
-
-#include <stdio.h>
-#include <limits.h>
-
-#include <metal/machine.h>
-#include <metal/drivers/sifive_fe310-g000_pll.h>
-#include <stdlib.h>
-
-#define PLL_R 0x00000007UL
-#define PLL_F 0x000003F0UL
-#define PLL_Q 0x00000C00UL
-#define PLL_SEL 0x00010000UL
-#define PLL_REFSEL 0x00020000UL
-#define PLL_BYPASS 0x00040000UL
-#define PLL_LOCK 0x80000000UL
-
-#define DIV_DIV 0x0000003FUL
-#define DIV_1 0x00000100UL
-
-#define PLL_R_SHIFT(r) ((r << 0) & PLL_R)
-#define PLL_F_SHIFT(f) ((f << 4) & PLL_F)
-#define PLL_Q_SHIFT(q) ((q << 10) & PLL_Q)
-#define PLL_DIV_SHIFT(d) ((d << 0) & DIV_DIV)
-
-struct pll_config_t {
- unsigned long multiplier;
- unsigned long divisor;
- unsigned long min_input_rate;
- unsigned long max_input_rate;
- unsigned long r;
- unsigned long f;
- unsigned long q;
- long d; /* < 0 if disabled */
-};
-
-static const struct pll_config_t pll_configs[] = {
- /*
- * multiplier
- * ^ divisor
- * | ^ min_input_rate
- * | | ^ max_input_rate
- * | | | ^ r
- * | | | | ^ f
- * | | | | | ^ q
- * | | | | | | ^ d
- * | | | | | | | ^
- * | | | | | | | | */
- { 1, 32, 12000000, 24000000, 1, 31, 3, 63},
- { 1, 32, 24000000, 48000000, 3, 31, 2, 63},
- { 1, 16, 6000000, 12000000, 0, 31, 3, 63},
- { 1, 16, 12000000, 24000000, 1, 31, 2, 63},
- { 1, 16, 24000000, 48000000, 3, 31, 2, 31},
- { 1, 8, 6000000, 12000000, 0, 31, 3, 31},
- { 1, 8, 12000000, 24000000, 1, 31, 2, 31},
- { 1, 8, 24000000, 48000000, 3, 31, 2, 15},
- { 1, 4, 6000000, 12000000, 0, 31, 3, 15},
- { 1, 4, 12000000, 24000000, 1, 31, 2, 15},
- { 1, 4, 24000000, 48000000, 3, 31, 2, 7},
- { 1, 2, 6000000, 12000000, 0, 31, 2, 15},
- { 1, 2, 12000000, 24000000, 1, 31, 1, 15},
- { 1, 2, 24000000, 48000000, 3, 31, 1, 7},
- { 2, 1, 6000000, 12000000, 0, 31, 1, 7},
- { 2, 1, 12000000, 24000000, 1, 31, 1, 3},
- { 2, 1, 24000000, 48000000, 3, 31, 3, -1},
- { 4, 1, 6000000, 12000000, 0, 31, 3, 0},
- { 4, 1, 12000000, 24000000, 1, 31, 3, -1},
- { 4, 1, 24000000, 48000000, 3, 31, 2, -1},
- { 6, 1, 6000000, 10666666, 0, 35, 1, 2},
- { 6, 1, 10666666, 12000000, 0, 23, 3, -1},
- { 6, 1, 12000000, 16000000, 1, 47, 3, -1},
- { 6, 1, 16000000, 18000000, 1, 23, 2, -1},
- { 6, 1, 18000000, 21333333, 2, 35, 2, -1},
- { 8, 1, 6000000, 12000000, 0, 31, 3, -1},
- { 8, 1, 12000000, 24000000, 1, 31, 2, -1},
- { 8, 1, 24000000, 48000000, 3, 31, 1, -1},
- {10, 1, 6000000, 9600000, 0, 39, 3, -1},
- {10, 1, 9600000, 12000000, 0, 19, 2, -1},
- {10, 1, 12000000, 19200000, 1, 39, 2, -1},
- {10, 1, 19200000, 24000000, 1, 19, 1, -1},
- {10, 1, 24000000, 38400000, 3, 39, 1, -1},
- {12, 1, 6000000, 8000000, 0, 47, 3, -1},
- {12, 1, 8000000, 12000000, 0, 23, 2, -1},
- {12, 1, 12000000, 16000000, 1, 47, 2, -1},
- {12, 1, 16000000, 24000000, 1, 23, 1, -1},
- {12, 1, 24000000, 30000000, 3, 47, 1, -1},
- {12, 1, 30000000, 32000000, 3, 47, 1, -1},
- {14, 1, 6000000, 6857142, 0, 55, 3, -1},
- {14, 1, 6857143, 12000000, 0, 27, 2, -1},
- {14, 1, 12000000, 13714285, 1, 55, 2, -1},
- {14, 1, 13714286, 24000000, 1, 27, 1, -1},
- {14, 1, 24000000, 27428571, 3, 55, 1, -1},
- {16, 1, 6000000, 12000000, 0, 31, 2, -1},
- {16, 1, 12000000, 24000000, 1, 31, 1, -1},
- {18, 1, 6000000, 10666666, 0, 35, 2, -1},
- {18, 1, 10666667, 12000000, 0, 17, 1, -1},
- {18, 1, 12000000, 21333333, 1, 35, 1, -1},
- {20, 1, 6000000, 9600000, 0, 39, 2, -1},
- {20, 1, 9600000, 12000000, 0, 19, 1, -1},
- {20, 1, 12000000, 19200000, 1, 39, 1, -1},
- {22, 1, 6000000, 8727272, 0, 43, 2, -1},
- {22, 1, 8727273, 12000000, 0, 21, 1, -1},
- {22, 1, 12000000, 17454545, 1, 43, 1, -1},
- {24, 1, 6000000, 8000000, 0, 47, 2, -1},
- {24, 1, 8000000, 12000000, 0, 23, 1, -1},
- {24, 1, 12000000, 16000000, 1, 47, 1, -1},
- {26, 1, 6000000, 7384615, 0, 51, 2, -1},
- {26, 1, 7384616, 12000000, 0, 25, 1, -1},
- {26, 1, 12000000, 14768230, 1, 51, 1, -1},
- {28, 1, 6000000, 6857142, 0, 55, 2, -1},
- {28, 1, 6857143, 12000000, 0, 27, 1, -1},
- {28, 1, 12000000, 13714285, 1, 55, 1, -1},
- {30, 1, 6000000, 6400000, 0, 59, 2, -1},
- {30, 1, 6400000, 12000000, 0, 29, 1, -1},
- {30, 1, 12000000, 12800000, 1, 59, 1, -1},
- {32, 1, 6000000, 12000000, 0, 31, 1, -1}
-};
-
-#define PLL_CONFIG_NOT_VALID -1
-
-void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe310_g000_pll *pll);
-
-/* Given the rate of the PLL input frequency and a PLL configuration, what
- * will the resulting PLL output frequency be?
- * Arguments:
- * - pll_input_rate the PLL input frequency in hertz
- * - config the PLL configuration
- * Returns:
- * - PLL_CONFIG_NOT_VALID if the configuration is not valid for the input frequency
- * - the output frequency, in hertz */
-static long get_pll_config_freq(unsigned long pll_input_rate, const struct pll_config_t *config)
-{
- if(pll_input_rate < config->min_input_rate || pll_input_rate > config->max_input_rate)
- return PLL_CONFIG_NOT_VALID;
-
- return pll_input_rate * config->multiplier / config->divisor;
-}
-
-#ifdef __METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE
-
-static void metal_sifive_fe310_g000_pll_init(void) __attribute__((constructor));
-static void metal_sifive_fe310_g000_pll_init(void) {
- long init_rate = __metal_driver_sifive_fe310_g000_pll_init_rate();
- /* If the PLL init_rate is zero, don't initialize the PLL */
- if(init_rate != 0)
- __metal_driver_sifive_fe310_g000_pll_init(__METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE);
-}
-
-#endif /* __METAL_DT_SIFIVE_FE310_G000__PLL_HANDLE */
-
-void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe310_g000_pll *pll) {
- struct metal_clock *pllref = __metal_driver_sifive_fe310_g000_pll_pllref(&(pll->clock));
- long init_rate = __metal_driver_sifive_fe310_g000_pll_init_rate();
- long config_offset = __metal_driver_sifive_fe310_g000_pll_config_offset();
- long base = __metal_driver_sifive_fe310_g000_prci_base();
-
- __metal_io_u32 *pllcfg = (__metal_io_u32 *) (base + config_offset);
-
- /* If the PLL clock has had a _pre_rate_change_callback configured, call it */
- _metal_clock_call_all_callbacks(pll->clock._pre_rate_change_callback);
-
- /* If we're running off of the PLL, switch off before we start configuring it*/
- if((__METAL_ACCESS_ONCE(pllcfg) & PLL_SEL) == 0)
- __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_SEL);
-
- /* Make sure we're running off of the external oscillator for stability */
- if(pllref != NULL)
- __METAL_ACCESS_ONCE(pllcfg) |= PLL_REFSEL;
-
- /* Configure the PLL to run at the requested init frequency.
- * Using the vtable instead of the user API because we want to control
- * when the callbacks occur. */
- pll->clock.vtable->set_rate_hz(&(pll->clock), init_rate);
-
- /* If the PLL clock has had a rate_change_callback configured, call it */
- _metal_clock_call_all_callbacks(pll->clock._post_rate_change_callback);
-}
-
-long __metal_driver_sifive_fe310_g000_pll_get_rate_hz(const struct metal_clock *clock)
-{
- struct metal_clock *pllref = __metal_driver_sifive_fe310_g000_pll_pllref(clock);
- struct metal_clock *pllsel0 = __metal_driver_sifive_fe310_g000_pll_pllsel0(clock);
- long config_offset = __metal_driver_sifive_fe310_g000_pll_config_offset(clock);
- struct __metal_driver_sifive_fe310_g000_prci *config_base =
- __metal_driver_sifive_fe310_g000_pll_config_base(clock);
- long divider_offset = __metal_driver_sifive_fe310_g000_pll_divider_offset(clock);
- struct __metal_driver_sifive_fe310_g000_prci *divider_base =
- __metal_driver_sifive_fe310_g000_pll_divider_base(clock);
- const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable =
- __metal_driver_sifive_fe310_g000_prci_vtable();
-
- long cfg = vtable->get_reg(config_base, config_offset);
- long div = vtable->get_reg(divider_base, divider_offset);
-
- /* At the end of the PLL there's one big mux: it either selects the HFROSC
- * (bypassing the PLL entirely) or uses the PLL. */
- if (__METAL_GET_FIELD(cfg, PLL_SEL) == 0)
- return metal_clock_get_rate_hz(pllsel0);
-
- /* There's a clock mux before the PLL that selects between the HFROSC adn
- * the HFXOSC as the PLL's input clock. */
- long ref_hz = metal_clock_get_rate_hz(__METAL_GET_FIELD(cfg, PLL_REFSEL) ? pllref : pllsel0);
-
- /* It's possible to bypass the PLL, which is an internal bpyass. This
- * still obays the PLL's input clock mu. */
- if (__METAL_GET_FIELD(cfg, PLL_BYPASS))
- return ref_hz;
-
- /* Logically the PLL is a three stage div-mul-div. */
- long div_r = __METAL_GET_FIELD(cfg, PLL_R) + 1;
- long mul_f = 2 * (__METAL_GET_FIELD(cfg, PLL_F) + 1);
- if (__METAL_GET_FIELD(cfg, PLL_Q) == 0)
- return -1;
- long div_q = 1 << __METAL_GET_FIELD(cfg, PLL_Q);
-
- /* In addition to the dividers inherent in the PLL, there's an additional
- * clock divider that lives after the PLL and lets us pick a more
- * interesting range of frequencies. */
- long pllout = (((ref_hz / div_r) * mul_f) / div_q);
- if (__METAL_GET_FIELD(div, DIV_1))
- return pllout;
-
- return pllout / (2 * (__METAL_GET_FIELD(div, DIV_DIV) + 1));
-}
-
-/* Find a valid configuration for the PLL which is closest to the desired
- * output frequency.
- * Arguments:
- * - ref_hz PLL input frequency
- * - rate desired PLL output frequency
- * Returns:
- * -1 if no valid configuration is available
- * the index into pll_configs of a valid configuration */
-static int find_closest_config(long ref_hz, long rate)
-{
- int closest_index = -1;
- long closest_diff = LONG_MAX;
-
- /* We're probably trying for a fast output frequency, so start from
- * the high end of the configs. */
- for(int i = (sizeof(pll_configs) / sizeof(pll_configs[0])) - 1; i >= 0; i--)
- {
- long config_freq = get_pll_config_freq(ref_hz, &(pll_configs[i]));
- if(config_freq != PLL_CONFIG_NOT_VALID)
- {
- long freq_diff = abs(config_freq - rate);
- if(freq_diff < closest_diff)
- {
- closest_index = i;
- closest_diff = freq_diff;
- }
- }
- }
-
- return closest_index;
-}
-
-/* Configure the PLL and wait for it to lock */
-static void configure_pll(__metal_io_u32 *pllcfg, __metal_io_u32 *plloutdiv, const struct pll_config_t *config)
-{
- __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_R);
- __METAL_ACCESS_ONCE(pllcfg) |= PLL_R_SHIFT(config->r);
-
- __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_F);
- __METAL_ACCESS_ONCE(pllcfg) |= PLL_F_SHIFT(config->f);
-
- __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_Q);
- __METAL_ACCESS_ONCE(pllcfg) |= PLL_Q_SHIFT(config->q);
-
- if(config->d < 0)
- {
- /* disable final divider */
- __METAL_ACCESS_ONCE(plloutdiv) |= DIV_1;
-
- __METAL_ACCESS_ONCE(plloutdiv) &= ~(DIV_DIV);
- __METAL_ACCESS_ONCE(plloutdiv) |= PLL_DIV_SHIFT(1);
- }
- else
- {
- __METAL_ACCESS_ONCE(plloutdiv) &= ~(DIV_1);
-
- __METAL_ACCESS_ONCE(plloutdiv) &= ~(DIV_DIV);
- __METAL_ACCESS_ONCE(plloutdiv) |= PLL_DIV_SHIFT(config->d);
- }
-
- __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_BYPASS);
-
- /* Wait for PLL to lock */
- while((__METAL_ACCESS_ONCE(pllcfg) & PLL_LOCK) == 0) ;
-}
-
-long __metal_driver_sifive_fe310_g000_pll_set_rate_hz(struct metal_clock *clock, long rate)
-{
- struct metal_clock *pllref = __metal_driver_sifive_fe310_g000_pll_pllref(clock);
- struct metal_clock *pllsel0 = __metal_driver_sifive_fe310_g000_pll_pllsel0(clock);
- long config_offset = __metal_driver_sifive_fe310_g000_pll_config_offset(clock);
- long divider_offset = __metal_driver_sifive_fe310_g000_pll_divider_offset(clock);
- long base = __metal_driver_sifive_fe310_g000_prci_base();
-
- __metal_io_u32 *pllcfg = (__metal_io_u32 *) (base + config_offset);
- __metal_io_u32 *plloutdiv = (__metal_io_u32 *) (base + divider_offset);
-
- /* We can't modify the PLL if coreclk is driven by it, so switch it off */
- if (__METAL_ACCESS_ONCE(pllcfg) & PLL_SEL)
- __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_SEL);
-
- /* There's a clock mux before the PLL that selects between the HFROSC and
- * the HFXOSC as the PLL's input clock. */
- long ref_hz = metal_clock_get_rate_hz(__METAL_ACCESS_ONCE(pllcfg) & PLL_REFSEL ? pllref : pllsel0);
-
- /* if the desired rate is within 75%-125% of the input clock, bypass the PLL */
- if((ref_hz * 3 / 4) <= rate && (ref_hz * 5 / 4) >= rate)
- {
- __METAL_ACCESS_ONCE(pllcfg) |= PLL_BYPASS;
- }
- else
- {
- int config_index = find_closest_config(ref_hz, rate);
- if(config_index != -1)
- {
- configure_pll(pllcfg, plloutdiv, &(pll_configs[config_index]));
- }
- else
- {
- /* unable to find a valid configuration */
- __METAL_ACCESS_ONCE(pllcfg) |= PLL_BYPASS;
- }
- }
-
- /* Enable the PLL */
- __METAL_ACCESS_ONCE(pllcfg) |= PLL_SEL;
-
- return __metal_driver_sifive_fe310_g000_pll_get_rate_hz(clock);
-}
-
-#ifdef __METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE
-static void use_hfxosc(void) __attribute__((constructor));
-static void use_hfxosc(void)
-{
- long init_rate = __metal_driver_sifive_fe310_g000_pll_init_rate();
- metal_clock_set_rate_hz(
- &__METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE->clock, init_rate
- );
-}
-#endif
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_pll) = {
- .init = __metal_driver_sifive_fe310_g000_pll_init,
- .clock.get_rate_hz = __metal_driver_sifive_fe310_g000_pll_get_rate_hz,
- .clock.set_rate_hz = __metal_driver_sifive_fe310_g000_pll_set_rate_hz,
-};
-
-#endif /* METAL_SIFIVE_FE310_G000_PLL */
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_FE310_G000_PRCI
-
-#include <metal/drivers/sifive_fe310-g000_prci.h>
-#include <metal/machine.h>
-
-long __metal_driver_sifive_fe310_g000_prci_get_reg(const struct __metal_driver_sifive_fe310_g000_prci *prci, long offset) {
- unsigned long base = __metal_driver_sifive_fe310_g000_prci_base();
- return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + offset));
-}
-
-long __metal_driver_sifive_fe310_g000_prci_set_reg(const struct __metal_driver_sifive_fe310_g000_prci *prci, long offset, long value) {
- unsigned long base = __metal_driver_sifive_fe310_g000_prci_base();
- return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + offset)) = value;
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci) = {
- .get_reg = __metal_driver_sifive_fe310_g000_prci_get_reg,
- .set_reg = __metal_driver_sifive_fe310_g000_prci_set_reg,
-};
-
-#endif /* METAL_SIFIVE_FE310_G000_PRCI */
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_FU540_C000_L2
-
-#include <stdint.h>
-#include <metal/io.h>
-#include <metal/drivers/sifive_fu540-c000_l2.h>
-#include <metal/machine.h>
-
-#define L2_CONFIG_WAYS_SHIFT 8
-#define L2_CONFIG_WAYS_MASK (0xFF << L2_CONFIG_WAYS_SHIFT)
-
-void __metal_driver_sifive_fu540_c000_l2_init(struct metal_cache *l2, int ways);
-
-static void metal_driver_sifive_fu540_c000_l2_init(void) __attribute__((constructor));
-static void metal_driver_sifive_fu540_c000_l2_init(void)
-{
-#ifdef __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE
- /* Get the handle for the L2 cache controller */
- struct metal_cache *l2 = __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE;
- if(!l2) {
- return;
- }
-
- /* Get the number of available ways per bank */
- unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(l2);
- uint32_t ways = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_CONFIG));
- ways = ((ways & L2_CONFIG_WAYS_MASK) >> L2_CONFIG_WAYS_SHIFT);
-
- /* Enable all the ways */
- __metal_driver_sifive_fu540_c000_l2_init(l2, ways);
-#endif
-}
-
-void __metal_driver_sifive_fu540_c000_l2_init(struct metal_cache *l2, int ways)
-{
- metal_cache_set_enabled_ways(l2, ways);
-}
-
-int __metal_driver_sifive_fu540_c000_l2_get_enabled_ways(struct metal_cache *cache)
-{
- unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(cache);
-
- uint32_t way_enable = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_WAYENABLE));
-
- /* The stored number is the index, so add one */
- return (0xFF & way_enable) + 1;
-}
-
-int __metal_driver_sifive_fu540_c000_l2_set_enabled_ways(struct metal_cache *cache, int ways)
-{
- unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(cache);
-
- /* We can't decrease the number of enabled ways */
- if(metal_cache_get_enabled_ways(cache) > ways) {
- return -2;
- }
-
- /* The stored value is the index, so subtract one */
- uint32_t value = 0xFF & (ways - 1);
-
- /* Set the number of enabled ways */
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_WAYENABLE)) = value;
-
- /* Make sure the number of ways was set correctly */
- if(metal_cache_get_enabled_ways(cache) != ways) {
- return -3;
- }
-
- return 0;
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2) = {
- .cache.init = __metal_driver_sifive_fu540_c000_l2_init,
- .cache.get_enabled_ways = __metal_driver_sifive_fu540_c000_l2_get_enabled_ways,
- .cache.set_enabled_ways = __metal_driver_sifive_fu540_c000_l2_set_enabled_ways,
-};
-
-#endif
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0
-
-#include <metal/io.h>
-#include <metal/shutdown.h>
-#include <metal/drivers/sifive_global-external-interrupts0.h>
-#include <metal/machine.h>
-
-void __metal_driver_sifive_global_external_interrupt_init(struct metal_interrupt *controller)
-{
- struct __metal_driver_sifive_global_external_interrupts0 *global0;
-
- global0 = (struct __metal_driver_sifive_global_external_interrupts0 *)(controller);
- if ( !global0->init_done ) {
- struct metal_interrupt *intc =
- __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
-
- if (intc) {
- intc->vtable->interrupt_init(intc);
- /* Register its interrupts with with parent controller */
- for (int i = 0;
- i < __metal_driver_sifive_global_external_interrupts0_num_interrupts(controller);
- i++) {
- intc->vtable->interrupt_register(intc,
- __metal_driver_sifive_global_external_interrupts0_interrupt_lines(controller, i),
- NULL, controller);
- }
- global0->init_done = 1;
- }
- }
-}
-
-int __metal_driver_sifive_global_external_interrupt_register(struct metal_interrupt *controller,
- int id, metal_interrupt_handler_t isr,
- void *priv)
-{
- int rc = -1;
-
- if (id != 0) {
- struct metal_interrupt *intc =
- __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
-
- /* Enable its interrupts with parent controller */
- if (intc) {
- rc = intc->vtable->interrupt_register(intc, id, isr, priv);
- }
- }
- return rc;
-}
-
-int __metal_driver_sifive_global_external_interrupt_enable(struct metal_interrupt *controller, int id)
-{
- int rc = -1;
-
- if (id != 0) {
- struct metal_interrupt *intc =
- __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
-
- /* Enable its interrupts with parent controller */
- if (intc) {
- rc = intc->vtable->interrupt_enable(intc, id);
- }
- }
- return rc;
-}
-
-int __metal_driver_sifive_global_external_interrupt_disable(struct metal_interrupt *controller, int id)
-{
- int rc = -1;
-
- if (id != 0) {
- struct metal_interrupt *intc =
- __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
-
- /* Enable its interrupts with parent controller */
- if (intc) {
- rc = intc->vtable->interrupt_disable(intc, id);
- }
- }
- return rc;
-}
-
-int __metal_driver_sifive_global_external_interrupt_set_threshold(struct metal_interrupt *controller,
- unsigned int threshold)
-{
- struct metal_interrupt *intc =
- __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
- if (intc) {
- return intc->vtable->interrupt_set_threshold(intc, threshold);
- }
- return -1;
-}
-
-unsigned int __metal_driver_sifive_global_external_interrupt_get_threshold(struct metal_interrupt *controller)
-{
- struct metal_interrupt *intc =
- __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
-
- if (intc) {
- return intc->vtable->interrupt_get_threshold(intc);
- }
- return 0;
-}
-
-int __metal_driver_sifive_global_external_interrupt_set_priority(struct metal_interrupt *controller,
- int id, unsigned int priority)
-{
- struct metal_interrupt *intc =
- __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
- if (intc) {
- return intc->vtable->interrupt_set_priority(intc, id, priority);
- }
- return -1;
-}
-
-unsigned int __metal_driver_sifive_global_external_interrupt_get_priority(struct metal_interrupt *controller, int id)
-{
- struct metal_interrupt *intc =
- __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
-
- if (intc) {
- return intc->vtable->interrupt_get_priority(intc, id);
- }
- return 0;
-}
-
-int __metal_driver_sifive_global_external_command_request (struct metal_interrupt *controller,
- int command, void *data)
-{
- int idx;
- int rc = -1;
-
- switch (command) {
- case METAL_MAX_INTERRUPT_GET:
- rc = __metal_driver_sifive_global_external_interrupts0_num_interrupts(controller);
- break;
- case METAL_INDEX_INTERRUPT_GET:
- rc = 0;
- if (data) {
- idx = *(int *)data;
- rc = __metal_driver_sifive_global_external_interrupts0_interrupt_lines(controller, idx);
- }
- break;
- default:
- break;
- }
-
- return rc;
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_global_external_interrupts0) = {
- .global0_vtable.interrupt_init = __metal_driver_sifive_global_external_interrupt_init,
- .global0_vtable.interrupt_register = __metal_driver_sifive_global_external_interrupt_register,
- .global0_vtable.interrupt_enable = __metal_driver_sifive_global_external_interrupt_enable,
- .global0_vtable.interrupt_disable = __metal_driver_sifive_global_external_interrupt_disable,
- .global0_vtable.interrupt_get_threshold = __metal_driver_sifive_global_external_interrupt_get_threshold,
- .global0_vtable.interrupt_set_threshold = __metal_driver_sifive_global_external_interrupt_set_threshold,
- .global0_vtable.interrupt_get_priority = __metal_driver_sifive_global_external_interrupt_get_priority,
- .global0_vtable.interrupt_set_priority = __metal_driver_sifive_global_external_interrupt_set_priority,
- .global0_vtable.command_request = __metal_driver_sifive_global_external_command_request,
-};
-
-#endif
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_GPIO_BUTTONS
-
-#include <string.h>
-#include <metal/drivers/riscv_cpu.h>
-#include <metal/drivers/sifive_gpio-buttons.h>
-#include <metal/machine.h>
-
-int __metal_driver_button_exist (struct metal_button *button, char *label)
-{
- if (strcmp(__metal_driver_sifive_gpio_button_label(button), label) == 0) {
- return 1;
- }
- return 0;
-}
-
-struct metal_interrupt *
-__metal_driver_button_interrupt_controller(struct metal_button *button)
-{
- return __metal_driver_sifive_gpio_button_interrupt_controller(button);
-}
-
-int __metal_driver_button_get_interrupt_id(struct metal_button *button)
-{
- int irq, max_irq;
- struct metal_interrupt *irc;
-
- irq = __metal_driver_sifive_gpio_button_interrupt_line(button);
- irc = __metal_driver_sifive_gpio_button_interrupt_controller(button);
-
- if (irc != NULL) {
- max_irq = _metal_interrupt_command_request(irc,
- METAL_MAX_INTERRUPT_GET,
- NULL);
-
- if (irq < max_irq) {
- return _metal_interrupt_command_request(irc,
- METAL_INDEX_INTERRUPT_GET,
- (void *)&irq);
- }
- }
- return METAL_INTERRUPT_ID_LCMX;
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_button) = {
- .button_vtable.button_exist = __metal_driver_button_exist,
- .button_vtable.interrupt_controller = __metal_driver_button_interrupt_controller,
- .button_vtable.get_interrupt_id = __metal_driver_button_get_interrupt_id,
-};
-
-#endif
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_GPIO_LEDS
-
-#include <string.h>
-#include <metal/gpio.h>
-#include <metal/drivers/sifive_gpio-leds.h>
-#include <metal/machine.h>
-
-int __metal_driver_led_exist (struct metal_led *led, char *label)
-{
- if (strcmp(__metal_driver_sifive_gpio_led_label(led), label) == 0) {
- return 1;
- }
- return 0;
-}
-
-void __metal_driver_led_enable (struct metal_led *led)
-{
- int pin;
- struct metal_gpio *gpio;
-
- pin = __metal_driver_sifive_gpio_led_pin(led);
- gpio = __metal_driver_sifive_gpio_led_gpio(led);
-
- if (gpio != NULL) {
- /* Configure LED as output */
- metal_gpio_disable_input((struct metal_gpio *) gpio, pin);
- metal_gpio_enable_output((struct metal_gpio *) gpio, pin);
- }
-}
-
-void __metal_driver_led_on (struct metal_led *led)
-{
- int pin;
- struct metal_gpio *gpio;
-
- pin = __metal_driver_sifive_gpio_led_pin(led);
- gpio = __metal_driver_sifive_gpio_led_gpio(led);
-
- if (gpio != NULL) {
- metal_gpio_set_pin((struct metal_gpio *) gpio, pin, 1);
- }
-}
-
-void __metal_driver_led_off (struct metal_led *led)
-{
- int pin;
- struct metal_gpio *gpio;
-
- pin = __metal_driver_sifive_gpio_led_pin(led);
- gpio = __metal_driver_sifive_gpio_led_gpio(led);
-
- if (gpio != NULL) {
- metal_gpio_set_pin((struct metal_gpio *) gpio, pin, 0);
- }
-}
-
-void __metal_driver_led_toggle (struct metal_led *led)
-{
- int pin;
- struct metal_gpio *gpio;
-
- pin = __metal_driver_sifive_gpio_led_pin(led);
- gpio = __metal_driver_sifive_gpio_led_gpio(led);
-
- if (gpio != NULL) {
- metal_gpio_toggle_pin((struct metal_gpio *) gpio, pin);
- }
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_led) = {
- .led_vtable.led_exist = __metal_driver_led_exist,
- .led_vtable.led_enable = __metal_driver_led_enable,
- .led_vtable.led_on = __metal_driver_led_on,
- .led_vtable.led_off = __metal_driver_led_off,
- .led_vtable.led_toggle = __metal_driver_led_toggle,
-};
-
-#endif
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_GPIO_SWITCHES
-
-#include <string.h>
-#include <metal/drivers/riscv_cpu.h>
-#include <metal/drivers/sifive_gpio-switches.h>
-#include <metal/machine.h>
-
-int __metal_driver_switch_exist (struct metal_switch *flip, char *label)
-{
- if (strcmp(__metal_driver_sifive_gpio_switch_label(flip), label) == 0) {
- return 1;
- }
- return 0;
-}
-
-struct metal_interrupt *
-__metal_driver_switch_interrupt_controller(struct metal_switch *flip)
-{
- return __metal_driver_sifive_gpio_switch_interrupt_controller(flip);
-}
-
-int __metal_driver_switch_get_interrupt_id(struct metal_switch *flip)
-{
- int irq, max_irq;
- struct metal_interrupt *irc;
-
- irq = __metal_driver_sifive_gpio_switch_interrupt_line(flip);
- irc = __metal_driver_sifive_gpio_switch_interrupt_controller(flip);
- if (irc != NULL) {
- max_irq = _metal_interrupt_command_request(irc,
- METAL_MAX_INTERRUPT_GET,
- NULL);
-
- if (irq < max_irq) {
- return _metal_interrupt_command_request(irc,
- METAL_INDEX_INTERRUPT_GET,
- (void *)&irq);
- }
- }
- return METAL_INTERRUPT_ID_LCMX;
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_switch) = {
- .switch_vtable.switch_exist = __metal_driver_switch_exist,
- .switch_vtable.interrupt_controller = __metal_driver_switch_interrupt_controller,
- .switch_vtable.get_interrupt_id = __metal_driver_switch_get_interrupt_id,
-};
-
-#endif
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_GPIO0
-
-#include <metal/drivers/sifive_gpio0.h>
-#include <metal/io.h>
-#include <metal/machine.h>
-
-int __metal_driver_sifive_gpio0_enable_input(struct metal_gpio *ggpio, long source)
-{
- long base = __metal_driver_sifive_gpio0_base(ggpio);
-
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_INPUT_EN)) |= source;
-
- return 0;
-}
-
-int __metal_driver_sifive_gpio0_disable_input(struct metal_gpio *ggpio, long source)
-{
- long base = __metal_driver_sifive_gpio0_base(ggpio);
-
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_INPUT_EN)) &= ~source;
-
- return 0;
-}
-
-long __metal_driver_sifive_gpio0_input(struct metal_gpio *ggpio)
-{
- long base = __metal_driver_sifive_gpio0_base(ggpio);
-
- return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_VALUE));
-}
-
-long __metal_driver_sifive_gpio0_output(struct metal_gpio *ggpio)
-{
- long base = __metal_driver_sifive_gpio0_base(ggpio);
-
- return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT));
-}
-
-
-int __metal_driver_sifive_gpio0_disable_output(struct metal_gpio *ggpio, long source)
-{
- long base = __metal_driver_sifive_gpio0_base(ggpio);
-
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_OUTPUT_EN)) &= ~source;
-
- return 0;
-}
-
-int __metal_driver_sifive_gpio0_enable_output(struct metal_gpio *ggpio, long source)
-{
- long base = __metal_driver_sifive_gpio0_base(ggpio);
-
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_OUTPUT_EN)) |= source;
-
- return 0;
-}
-
-int __metal_driver_sifive_gpio0_output_set(struct metal_gpio *ggpio, long value)
-{
- long base = __metal_driver_sifive_gpio0_base(ggpio);
-
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)) |= value;
-
- return 0;
-}
-
-int __metal_driver_sifive_gpio0_output_clear(struct metal_gpio *ggpio, long value)
-{
- long base = __metal_driver_sifive_gpio0_base(ggpio);
-
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)) &= ~value;
-
- return 0;
-}
-
-int __metal_driver_sifive_gpio0_output_toggle(struct metal_gpio *ggpio, long value)
-{
- long base = __metal_driver_sifive_gpio0_base(ggpio);
-
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)) =
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)) ^ value;
-
- return 0;
-}
-
-int __metal_driver_sifive_gpio0_enable_io(struct metal_gpio *ggpio, long source, long dest)
-{
- long base = __metal_driver_sifive_gpio0_base(ggpio);
-
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_SEL)) &= ~source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_EN)) |= dest;
-
- return 0;
-}
-
-int __metal_driver_sifive_gpio0_disable_io(struct metal_gpio *ggpio, long source)
-{
- long base = __metal_driver_sifive_gpio0_base(ggpio);
-
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_EN)) &= ~source;
-
- return 0;
-}
-
-int __metal_driver_sifive_gpio0_config_int(struct metal_gpio *ggpio, long source, int intr_type)
-{
- long base = __metal_driver_sifive_gpio0_base(ggpio);
-
- switch (intr_type)
- {
- case METAL_GPIO_INT_DISABLE:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) &= ~source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) &= ~source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) &= ~source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) &= ~source;
- break;
- case METAL_GPIO_INT_RISING:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source;
- break;
- case METAL_GPIO_INT_FALLING:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source;
- break;
- case METAL_GPIO_INT_BOTH_EDGE:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source;
- break;
- case METAL_GPIO_INT_HIGH:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source;
- break;
- case METAL_GPIO_INT_LOW:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source;
- break;
- case METAL_GPIO_INT_BOTH_LEVEL:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source;
- break;
- case METAL_GPIO_INT_MAX:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source;
- break;
- }
- return 0;
-}
-
-int __metal_driver_sifive_gpio0_clear_int(struct metal_gpio *ggpio, long source, int intr_type)
-{
- long base = __metal_driver_sifive_gpio0_base(ggpio);
-
- switch (intr_type)
- {
- case METAL_GPIO_INT_RISING:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source;
- break;
- case METAL_GPIO_INT_FALLING:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source;
- break;
- case METAL_GPIO_INT_BOTH_EDGE:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source;
- break;
- case METAL_GPIO_INT_HIGH:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source;
- break;
- case METAL_GPIO_INT_LOW:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source;
- break;
- case METAL_GPIO_INT_BOTH_LEVEL:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source;
- break;
- case METAL_GPIO_INT_MAX:
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source;
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source;
- break;
- }
- return 0;
-}
-
-struct metal_interrupt *
-__metal_driver_gpio_interrupt_controller(struct metal_gpio *gpio)
-{
- return __metal_driver_sifive_gpio0_interrupt_parent(gpio);
-}
-
-int __metal_driver_gpio_get_interrupt_id(struct metal_gpio *gpio, int pin)
-{
- int irq;
- irq = __metal_driver_sifive_gpio0_interrupt_lines(gpio, pin);
- return irq;
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_gpio0) = {
- .gpio.disable_input = __metal_driver_sifive_gpio0_disable_input,
- .gpio.enable_input = __metal_driver_sifive_gpio0_enable_input,
- .gpio.input = __metal_driver_sifive_gpio0_input,
- .gpio.output = __metal_driver_sifive_gpio0_output,
- .gpio.disable_output = __metal_driver_sifive_gpio0_disable_output,
- .gpio.enable_output = __metal_driver_sifive_gpio0_enable_output,
- .gpio.output_set = __metal_driver_sifive_gpio0_output_set,
- .gpio.output_clear = __metal_driver_sifive_gpio0_output_clear,
- .gpio.output_toggle = __metal_driver_sifive_gpio0_output_toggle,
- .gpio.enable_io = __metal_driver_sifive_gpio0_enable_io,
- .gpio.disable_io = __metal_driver_sifive_gpio0_disable_io,
- .gpio.config_int = __metal_driver_sifive_gpio0_config_int,
- .gpio.clear_int = __metal_driver_sifive_gpio0_clear_int,
- .gpio.interrupt_controller = __metal_driver_gpio_interrupt_controller,
- .gpio.get_interrupt_id = __metal_driver_gpio_get_interrupt_id,
-};
-
-#endif /* METAL_SIFIVE_GPIO0 */
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_LOCAL_EXTERNAL_INTERRUPTS0
-
-#include <metal/io.h>
-#include <metal/drivers/sifive_local-external-interrupts0.h>
-#include <metal/machine.h>
-
-void __metal_driver_sifive_local_external_interrupt_init(struct metal_interrupt *controller)
-{
- struct __metal_driver_sifive_local_external_interrupts0 *local0;
-
- local0 = (struct __metal_driver_sifive_local_external_interrupts0 *)(controller);
- if ( !local0->init_done ) {
- struct metal_interrupt *intc =
- __metal_driver_sifive_local_external_interrupts0_interrupt_parent(controller);
-
- if (intc) {
- /* Register its interruptswith with parent controller, aka all external to default isr */
- for (int i = 0;
- i < __metal_driver_sifive_local_external_interrupts0_num_interrupts(controller);
- i++) {
- intc->vtable->interrupt_register(intc,
- __metal_driver_sifive_local_external_interrupts0_interrupt_lines(controller, i),
- NULL, controller);
- }
- local0->init_done = 1;
- }
- }
-}
-
-int __metal_driver_sifive_local_external_interrupt_register(struct metal_interrupt *controller,
- int id, metal_interrupt_handler_t isr,
- void *priv)
-{
- int rc = -1;
-
- if (id != 0) {
- struct metal_interrupt *intc =
- __metal_driver_sifive_local_external_interrupts0_interrupt_parent(controller);
-
- /* Enable its interrupts with parent controller */
- if (intc) {
- rc = intc->vtable->interrupt_register(intc, id, isr, priv);
- }
- }
- return rc;
-}
-
-int __metal_driver_sifive_local_external_interrupt_enable(struct metal_interrupt *controller, int id)
-{
- int rc = -1;
-
- if (id != 0) {
- struct metal_interrupt *intc =
- __metal_driver_sifive_local_external_interrupts0_interrupt_parent(controller);
-
- /* Enable its interrupts with parent controller */
- if (intc) {
- rc = intc->vtable->interrupt_enable(intc, id);
- }
- }
- return rc;
-}
-
-int __metal_driver_sifive_local_external_interrupt_disable(struct metal_interrupt *controller, int id)
-{
- int rc = -1;
-
- if (id != 0) {
- struct metal_interrupt *intc =
- __metal_driver_sifive_local_external_interrupts0_interrupt_parent(controller);
-
- /* Enable its interrupts with parent controller */
- if (intc) {
- rc = intc->vtable->interrupt_disable(intc, id);
- }
- }
- return rc;
-}
-
-int __metal_driver_sifive_local_external_interrupt_set_threshold(struct metal_interrupt *controller,
- unsigned int threshold)
-{
- /* Core controller does not support threshold configuration */
- return -1;
-}
-
-unsigned int __metal_driver_sifive_local_external_interrupt_get_threshold(struct metal_interrupt *controller)
-{
- /* Core controller does not support threshold configuration */
- return 0;
-}
-
-
-int __metal_driver_sifive_local_external_interrupt_set_priority(struct metal_interrupt *controller,
- int id, unsigned int priority)
-{
- /* Core controller does not support priority configuration */
- return -1;
-}
-
-unsigned int __metal_driver_sifive_local_external_interrupt_get_priority(struct metal_interrupt *controller, int id)
-{
- /* Core controller does not support priority configuration */
- return 0;
-}
-
-int __metal_driver_sifive_local_external_command_request (struct metal_interrupt *controller,
- int command, void *data)
-{
- int idx;
- int rc = -1;
-
- switch (command) {
- case METAL_MAX_INTERRUPT_GET:
- rc = __metal_driver_sifive_local_external_interrupts0_num_interrupts(controller);
- break;
- case METAL_INDEX_INTERRUPT_GET:
- rc = 0;
- if (data) {
- idx = *(int *)data;
- rc = __metal_driver_sifive_local_external_interrupts0_interrupt_lines(controller, idx);
- }
- break;
- default:
- break;
- }
-
- return rc;
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_local_external_interrupts0) = {
- .local0_vtable.interrupt_init = __metal_driver_sifive_local_external_interrupt_init,
- .local0_vtable.interrupt_register = __metal_driver_sifive_local_external_interrupt_register,
- .local0_vtable.interrupt_enable = __metal_driver_sifive_local_external_interrupt_enable,
- .local0_vtable.interrupt_disable = __metal_driver_sifive_local_external_interrupt_disable,
- .local0_vtable.interrupt_get_threshold = __metal_driver_sifive_local_external_interrupt_get_threshold,
- .local0_vtable.interrupt_set_threshold = __metal_driver_sifive_local_external_interrupt_set_threshold,
- .local0_vtable.interrupt_get_priority = __metal_driver_sifive_local_external_interrupt_get_priority,
- .local0_vtable.interrupt_set_priority = __metal_driver_sifive_local_external_interrupt_set_priority,
- .local0_vtable.command_request = __metal_driver_sifive_local_external_command_request,
-};
-
-#endif
-
-typedef int no_empty_translation_units;
-
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_RTC0
-
-#include <metal/drivers/sifive_rtc0.h>
-#include <metal/machine.h>
-
-#include <limits.h>
-
-/* RTCCFG */
-#define METAL_RTCCFG_RTCSCALE_MASK 0xF
-#define METAL_RTCCFG_ENALWAYS (1 << 12)
-#define METAL_RTCCFG_IP0 (1 << 28)
-
-/* RTCCMP0 */
-#define METAL_RTCCMP0_MAX UINT32_MAX
-
-#define RTC_REG(base, offset) (((unsigned long)base + offset))
-#define RTC_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)RTC_REG(base, offset)))
-
-uint64_t __metal_driver_sifive_rtc0_get_rate(const struct metal_rtc *const rtc) {
- const struct metal_clock *const clock = __metal_driver_sifive_rtc0_clock(rtc);
- return metal_clock_get_rate_hz(clock);
-}
-
-uint64_t __metal_driver_sifive_rtc0_set_rate(const struct metal_rtc *const rtc, const uint64_t rate) {
- const struct metal_clock *const clock = __metal_driver_sifive_rtc0_clock(rtc);
- return metal_clock_get_rate_hz(clock);
-}
-
-uint64_t __metal_driver_sifive_rtc0_get_compare(const struct metal_rtc *const rtc) {
- const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
-
- const uint32_t shift = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) & METAL_RTCCFG_RTCSCALE_MASK;
-
- return ((uint64_t)RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) << shift);
-}
-
-uint64_t __metal_driver_sifive_rtc0_set_compare(const struct metal_rtc *const rtc, const uint64_t compare) {
- const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
-
- /* Determine the bit shift and shifted value to store in rtccmp0/rtccfg.scale */
- uint32_t shift = 0;
- uint64_t comp_shifted = compare;
- while (comp_shifted > METAL_RTCCMP0_MAX) {
- shift += 1;
- comp_shifted = comp_shifted >> shift;
- }
-
- /* Set the value of rtccfg.scale */
- uint32_t cfg = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG);
- cfg &= ~(METAL_RTCCFG_RTCSCALE_MASK);
- cfg |= (METAL_RTCCFG_RTCSCALE_MASK & shift);
- RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) = cfg;
-
- /* Set the value of rtccmp0 */
- RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) = (uint32_t) comp_shifted;
-
- return __metal_driver_sifive_rtc0_get_compare(rtc);
-}
-
-uint64_t __metal_driver_sifive_rtc0_get_count(const struct metal_rtc *const rtc) {
- const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
-
- uint64_t count = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI);
- count <<= 32;
- count |= RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO);
-
- return count;
-}
-
-uint64_t __metal_driver_sifive_rtc0_set_count(const struct metal_rtc *const rtc, const uint64_t count) {
- const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
-
- RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI) = (UINT_MAX & (count >> 32));
- RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO) = (UINT_MAX & count);
-
- return __metal_driver_sifive_rtc0_get_count(rtc);
-}
-
-int __metal_driver_sifive_rtc0_run(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option) {
- const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
-
- switch (option) {
- default:
- case METAL_RTC_STOP:
- RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) &= ~(METAL_RTCCFG_ENALWAYS);
- break;
- case METAL_RTC_RUN:
- RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) |= METAL_RTCCFG_ENALWAYS;
- break;
- }
-
- return 0;
-}
-
-struct metal_interrupt *__metal_driver_sifive_rtc0_get_interrupt(const struct metal_rtc *const rtc) {
- return __metal_driver_sifive_rtc0_interrupt_parent(rtc);
-}
-
-int __metal_driver_sifive_rtc0_get_interrupt_id(const struct metal_rtc *const rtc) {
- return __metal_driver_sifive_rtc0_interrupt_line(rtc);
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_rtc0) = {
- .rtc.get_rate = __metal_driver_sifive_rtc0_get_rate,
- .rtc.set_rate = __metal_driver_sifive_rtc0_set_rate,
- .rtc.get_compare = __metal_driver_sifive_rtc0_get_compare,
- .rtc.set_compare = __metal_driver_sifive_rtc0_set_compare,
- .rtc.get_count = __metal_driver_sifive_rtc0_get_count,
- .rtc.set_count = __metal_driver_sifive_rtc0_set_count,
- .rtc.run = __metal_driver_sifive_rtc0_run,
- .rtc.get_interrupt = __metal_driver_sifive_rtc0_get_interrupt,
- .rtc.get_interrupt_id = __metal_driver_sifive_rtc0_get_interrupt_id,
-};
-
-#endif
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_SPI0
-#include <metal/drivers/sifive_spi0.h>
-#include <metal/io.h>
-#include <metal/machine.h>
-#include <metal/time.h>
-#include <time.h>
-
-/* Register fields */
-#define METAL_SPI_SCKDIV_MASK 0xFFF
-
-#define METAL_SPI_SCKMODE_PHA_SHIFT 0
-#define METAL_SPI_SCKMODE_POL_SHIFT 1
-
-#define METAL_SPI_CSMODE_MASK 3
-#define METAL_SPI_CSMODE_AUTO 0
-#define METAL_SPI_CSMODE_HOLD 2
-#define METAL_SPI_CSMODE_OFF 3
-
-#define METAL_SPI_PROTO_MASK 3
-#define METAL_SPI_PROTO_SINGLE 0
-#define METAL_SPI_PROTO_DUAL 1
-#define METAL_SPI_PROTO_QUAD 2
-
-#define METAL_SPI_ENDIAN_LSB 4
-
-#define METAL_SPI_DISABLE_RX 8
-
-#define METAL_SPI_FRAME_LEN_SHIFT 16
-#define METAL_SPI_FRAME_LEN_MASK (0xF << METAL_SPI_FRAME_LEN_SHIFT)
-
-#define METAL_SPI_TXDATA_FULL (1 << 31)
-#define METAL_SPI_RXDATA_EMPTY (1 << 31)
-#define METAL_SPI_TXMARK_MASK 7
-#define METAL_SPI_TXWM 1
-#define METAL_SPI_TXRXDATA_MASK (0xFF)
-
-#define METAL_SPI_INTERVAL_SHIFT 16
-
-#define METAL_SPI_CONTROL_IO 0
-#define METAL_SPI_CONTROL_MAPPED 1
-
-#define METAL_SPI_REG(offset) (((unsigned long)control_base + offset))
-#define METAL_SPI_REGB(offset) (__METAL_ACCESS_ONCE((__metal_io_u8 *)METAL_SPI_REG(offset)))
-#define METAL_SPI_REGW(offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)METAL_SPI_REG(offset)))
-
-#define METAL_SPI_RXDATA_TIMEOUT 1
-
-static int configure_spi(struct __metal_driver_sifive_spi0 *spi, struct metal_spi_config *config)
-{
- long control_base = __metal_driver_sifive_spi0_control_base((struct metal_spi *)spi);
- /* Set protocol */
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_PROTO_MASK);
- switch (config->protocol) {
- case METAL_SPI_SINGLE:
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE;
- break;
- case METAL_SPI_DUAL:
- if (config->multi_wire == MULTI_WIRE_ALL)
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_DUAL;
- else
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE;
- break;
- case METAL_SPI_QUAD:
- if (config->multi_wire == MULTI_WIRE_ALL)
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_QUAD;
- else
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE;
- break;
- default:
- /* Unsupported value */
- return -1;
- }
-
- /* Set Polarity */
- if(config->polarity) {
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKMODE) |= (1 << METAL_SPI_SCKMODE_PHA_SHIFT);
- } else {
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKMODE) &= ~(1 << METAL_SPI_SCKMODE_PHA_SHIFT);
- }
-
- /* Set Phase */
- if(config->phase) {
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKMODE) |= (1 << METAL_SPI_SCKMODE_POL_SHIFT);
- } else {
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKMODE) &= ~(1 << METAL_SPI_SCKMODE_POL_SHIFT);
- }
-
- /* Set Endianness */
- if(config->little_endian) {
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_ENDIAN_LSB;
- } else {
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_ENDIAN_LSB);
- }
-
- /* Always populate receive FIFO */
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_DISABLE_RX);
-
- /* Set CS Active */
- if(config->cs_active_high) {
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSDEF) = 0;
- } else {
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSDEF) = 1;
- }
-
- /* Set frame length */
- if((METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) & METAL_SPI_FRAME_LEN_MASK) != (8 << METAL_SPI_FRAME_LEN_SHIFT)) {
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_FRAME_LEN_MASK);
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= (8 << METAL_SPI_FRAME_LEN_SHIFT);
- }
-
- /* Set CS line */
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSID) = 1 << (config->csid);
-
- /* Toggle off memory-mapped SPI flash mode, toggle on programmable IO mode
- * It seems that with this line uncommented, the debugger cannot have access
- * to the chip at all because it assumes the chip is in memory-mapped mode.
- * I have to compile the code with this line commented and launch gdb,
- * reset cores, reset $pc, set *((int *) 0x20004060) = 0, (set the flash
- * interface control register to programmable I/O mode) and then continue
- * Alternative, comment out the "flash" line in openocd.cfg */
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FCTRL) = METAL_SPI_CONTROL_IO;
-
- return 0;
-}
-
-static void spi_mode_switch(struct __metal_driver_sifive_spi0 *spi,
- struct metal_spi_config *config,
- unsigned int trans_stage) {
- long control_base =
- __metal_driver_sifive_spi0_control_base((struct metal_spi *)spi);
-
- if (config->multi_wire == trans_stage) {
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_PROTO_MASK);
- switch (config->protocol) {
- case METAL_SPI_DUAL:
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_DUAL;
- break;
- case METAL_SPI_QUAD:
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_QUAD;
- break;
- default:
- /* Unsupported value */
- return;
- }
- }
-}
-
-int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi,
- struct metal_spi_config *config,
- size_t len,
- char *tx_buf,
- char *rx_buf)
-{
- struct __metal_driver_sifive_spi0 *spi = (void *)gspi;
- long control_base = __metal_driver_sifive_spi0_control_base(gspi);
- int rc = 0;
- size_t i = 0;
-
- rc = configure_spi(spi, config);
- if(rc != 0) {
- return rc;
- }
-
- /* Hold the chip select line for all len transferred */
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= ~(METAL_SPI_CSMODE_MASK);
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) |= METAL_SPI_CSMODE_HOLD;
-
- unsigned long rxdata;
-
- /* Declare time_t variables to break out of infinite while loop */
- time_t endwait;
-
- for (i = 0; i < config->cmd_num; i++) {
-
- while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL)
- ;
-
- if (tx_buf) {
- METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i];
- } else {
- METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0;
- }
-
- endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT;
-
- while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) &
- METAL_SPI_RXDATA_EMPTY) {
- if (metal_time() > endwait) {
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &=
- ~(METAL_SPI_CSMODE_MASK);
-
- return 1;
- }
- }
-
- if (rx_buf) {
- rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK);
- }
- }
-
- /* switch to Dual/Quad mode */
- spi_mode_switch(spi, config, MULTI_WIRE_ADDR_DATA);
-
- /* Send Addr data */
- for (; i < (config->cmd_num + config->addr_num); i++) {
-
- while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL)
- ;
-
- if (tx_buf) {
- METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i];
- } else {
- METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0;
- }
-
- endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT;
-
- while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) &
- METAL_SPI_RXDATA_EMPTY) {
- if (metal_time() > endwait) {
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &=
- ~(METAL_SPI_CSMODE_MASK);
-
- return 1;
- }
- }
-
- if (rx_buf) {
- rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK);
- }
- }
-
- /* Send Dummy data */
- for (; i < (config->cmd_num + config->addr_num + config->dummy_num); i++) {
-
- while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL)
- ;
-
- if (tx_buf) {
- METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i];
- } else {
- METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0;
- }
-
- endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT;
-
- while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) &
- METAL_SPI_RXDATA_EMPTY) {
- if (metal_time() > endwait) {
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &=
- ~(METAL_SPI_CSMODE_MASK);
- return 1;
- }
- }
- if (rx_buf) {
- rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK);
- }
- }
-
- /* switch to Dual/Quad mode */
- spi_mode_switch(spi, config, MULTI_WIRE_DATA_ONLY);
-
- for (; i < len; i++) {
- /* Master send bytes to the slave */
-
- /* Wait for TXFIFO to not be full */
- while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL);
-
- /* Transfer byte by modifying the least significant byte in the TXDATA register */
- if (tx_buf) {
- METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i];
- } else {
- /* Transfer a 0 byte if the sending buffer is NULL */
- METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0;
- }
-
- /* Master receives bytes from the RX FIFO */
-
- /* Wait for RXFIFO to not be empty, but break the nested loops if timeout
- * this timeout method needs refining, preferably taking into account
- * the device specs */
- endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT;
-
- while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) & METAL_SPI_RXDATA_EMPTY) {
- if (metal_time() > endwait) {
- /* If timeout, deassert the CS */
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= ~(METAL_SPI_CSMODE_MASK);
-
- /* If timeout, return error code 1 immediately */
- return 1;
- }
- }
-
- /* Only store the dequeued byte if the receive_buffer is not NULL */
- if (rx_buf) {
- rx_buf[i] = (char) (rxdata & METAL_SPI_TXRXDATA_MASK);
- }
- }
-
- /* On the last byte, set CSMODE to auto so that the chip select transitions back to high
- * The reason that CS pin is not deasserted after transmitting out the byte buffer is timing.
- * The code on the host side likely executes faster than the ability of FIFO to send out bytes.
- * After the host iterates through the array, fifo is likely not cleared yet. If host deasserts
- * the CS pin immediately, the following bytes in the output FIFO will not be sent consecutively.
- * There needs to be a better way to handle this. */
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= ~(METAL_SPI_CSMODE_MASK);
-
- return 0;
-}
-
-int __metal_driver_sifive_spi0_get_baud_rate(struct metal_spi *gspi)
-{
- struct __metal_driver_sifive_spi0 *spi = (void *)gspi;
- return spi->baud_rate;
-}
-
-int __metal_driver_sifive_spi0_set_baud_rate(struct metal_spi *gspi, int baud_rate)
-{
- long control_base = __metal_driver_sifive_spi0_control_base(gspi);
- struct metal_clock *clock = __metal_driver_sifive_spi0_clock(gspi);
- struct __metal_driver_sifive_spi0 *spi = (void *)gspi;
-
- spi->baud_rate = baud_rate;
-
- if (clock != NULL) {
- long clock_rate = clock->vtable->get_rate_hz(clock);
-
- /* Calculate divider */
- long div = (clock_rate / (2 * baud_rate)) - 1;
-
- if(div > METAL_SPI_SCKDIV_MASK) {
- /* The requested baud rate is lower than we can support at
- * the current clock rate */
- return -1;
- }
-
- /* Set divider */
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKDIV) &= ~METAL_SPI_SCKDIV_MASK;
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_SCKDIV) |= (div & METAL_SPI_SCKDIV_MASK);
- }
-
- return 0;
-}
-
-static void pre_rate_change_callback_func(void *priv)
-{
- long control_base = __metal_driver_sifive_spi0_control_base((struct metal_spi *)priv);
-
- /* Detect when the TXDATA is empty by setting the transmit watermark count
- * to one and waiting until an interrupt is pending (indicating an empty TXFIFO) */
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXMARK) &= ~(METAL_SPI_TXMARK_MASK);
- METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXMARK) |= (METAL_SPI_TXMARK_MASK & 1);
-
- while((METAL_SPI_REGW(METAL_SIFIVE_SPI0_IP) & METAL_SPI_TXWM) == 0) ;
-}
-
-static void post_rate_change_callback_func(void *priv)
-{
- struct __metal_driver_sifive_spi0 *spi = priv;
- metal_spi_set_baud_rate(&spi->spi, spi->baud_rate);
-}
-
-void __metal_driver_sifive_spi0_init(struct metal_spi *gspi, int baud_rate)
-{
- struct __metal_driver_sifive_spi0 *spi = (void *)(gspi);
- struct metal_clock *clock = __metal_driver_sifive_spi0_clock(gspi);
- struct __metal_driver_sifive_gpio0 *pinmux = __metal_driver_sifive_spi0_pinmux(gspi);
-
- if(clock != NULL) {
- spi->pre_rate_change_callback.callback = &pre_rate_change_callback_func;
- spi->pre_rate_change_callback.priv = spi;
- metal_clock_register_pre_rate_change_callback(clock, &(spi->pre_rate_change_callback));
-
- spi->post_rate_change_callback.callback = &post_rate_change_callback_func;
- spi->post_rate_change_callback.priv = spi;
- metal_clock_register_post_rate_change_callback(clock, &(spi->post_rate_change_callback));
- }
-
- metal_spi_set_baud_rate(&(spi->spi), baud_rate);
-
- if (pinmux != NULL) {
- long pinmux_output_selector = __metal_driver_sifive_spi0_pinmux_output_selector(gspi);
- long pinmux_source_selector = __metal_driver_sifive_spi0_pinmux_source_selector(gspi);
- pinmux->gpio.vtable->enable_io(
- (struct metal_gpio *) pinmux,
- pinmux_output_selector,
- pinmux_source_selector
- );
- }
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_spi0) = {
- .spi.init = __metal_driver_sifive_spi0_init,
- .spi.transfer = __metal_driver_sifive_spi0_transfer,
- .spi.get_baud_rate = __metal_driver_sifive_spi0_get_baud_rate,
- .spi.set_baud_rate = __metal_driver_sifive_spi0_set_baud_rate,
-};
-#endif /* METAL_SIFIVE_SPI0 */
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_TEST0
-
-#include <metal/machine.h>
-
-#include <stdint.h>
-
-#include <metal/drivers/sifive_test0.h>
-#include <metal/io.h>
-
-void __metal_driver_sifive_test0_exit(const struct __metal_shutdown *sd, int code) __attribute__((noreturn));
-void __metal_driver_sifive_test0_exit(const struct __metal_shutdown *sd, int code)
-{
- long base = __metal_driver_sifive_test0_base(sd);
- uint32_t out = (code << 16) + (code == 0 ? 0x5555 : 0x3333);
- while (1) {
- __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_TEST0_FINISHER_OFFSET)) = out;
- }
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_test0) = {
- .shutdown.exit = &__metal_driver_sifive_test0_exit,
-};
-#endif /* METAL_SIFIVE_TEST0 */
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_TRACE
-
-#include <metal/drivers/sifive_trace.h>
-#include <metal/machine.h>
-
-#define TRACE_REG(offset) (((unsigned long)base + (offset)))
-#define TRACE_REG8(offset) \
- (__METAL_ACCESS_ONCE((__metal_io_u8 *)TRACE_REG(offset)))
-#define TRACE_REG16(offset) \
- (__METAL_ACCESS_ONCE((__metal_io_u16 *)TRACE_REG(offset)))
-#define TRACE_REG32(offset) \
- (__METAL_ACCESS_ONCE((__metal_io_u32 *)TRACE_REG(offset)))
-
-static void write_itc_uint32(struct metal_uart *trace, uint32_t data) {
- long base = __metal_driver_sifive_trace_base(trace);
-
- TRACE_REG32(METAL_SIFIVE_TRACE_ITCSTIMULUS) = data;
-}
-
-static void write_itc_uint16(struct metal_uart *trace, uint16_t data) {
- long base = __metal_driver_sifive_trace_base(trace);
-
- TRACE_REG16(METAL_SIFIVE_TRACE_ITCSTIMULUS + 2) = data;
-}
-
-static void write_itc_uint8(struct metal_uart *trace, uint8_t data) {
- long base = __metal_driver_sifive_trace_base(trace);
-
- TRACE_REG8(METAL_SIFIVE_TRACE_ITCSTIMULUS + 3) = data;
-}
-
-int __metal_driver_sifive_trace_putc(struct metal_uart *trace,
- unsigned char c) {
- static uint32_t buffer = 0;
- static int bytes_in_buffer = 0;
-
- buffer |= (((uint32_t)c) << (bytes_in_buffer * 8));
-
- bytes_in_buffer += 1;
-
- if (bytes_in_buffer >= 4) {
- write_itc_uint32(trace, buffer);
-
- buffer = 0;
- bytes_in_buffer = 0;
- } else if ((c == '\n') || (c == '\r')) { // partial write
- switch (bytes_in_buffer) {
- case 3: // do a full word write
- write_itc_uint16(trace, (uint16_t)(buffer));
- write_itc_uint8(trace, (uint8_t)(buffer >> 16));
- break;
- case 2: // do a 16 bit write
- write_itc_uint16(trace, (uint16_t)buffer);
- break;
- case 1: // do a 1 byte write
- write_itc_uint8(trace, (uint8_t)buffer);
- break;
- }
-
- buffer = 0;
- bytes_in_buffer = 0;
- }
-
- return (int)c;
-}
-
-void __metal_driver_sifive_trace_init(struct metal_uart *trace, int baud_rate) {
- // The only init we do here is to make sure ITC 0 is enabled. It is up to
- // Freedom Studio or other mechanisms to make sure tracing is enabled. If we
- // try to enable tracing here, it will likely conflict with Freedom Studio,
- // and they will just fight with each other.
-
- long base = __metal_driver_sifive_trace_base(trace);
-
- TRACE_REG32(METAL_SIFIVE_TRACE_ITCTRACEENABLE) |= 0x00000001;
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_trace) = {
- .uart.init = __metal_driver_sifive_trace_init,
- .uart.putc = __metal_driver_sifive_trace_putc,
- .uart.getc = NULL,
-
- .uart.get_baud_rate = NULL,
- .uart.set_baud_rate = NULL,
-
- .uart.controller_interrupt = NULL,
- .uart.get_interrupt_id = NULL,
-};
-
-#endif /* METAL_SIFIVE_TRACE */
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_UART0
-
-#include <metal/drivers/sifive_uart0.h>
-#include <metal/machine.h>
-
-/* TXDATA Fields */
-#define UART_TXEN (1 << 0)
-#define UART_TXFULL (1 << 31)
-
-/* RXDATA Fields */
-#define UART_RXEN (1 << 0)
-#define UART_RXEMPTY (1 << 31)
-
-/* TXCTRL Fields */
-#define UART_NSTOP (1 << 1)
-#define UART_TXCNT(count) ((0x7 & count) << 16)
-
-/* IP Fields */
-#define UART_TXWM (1 << 0)
-
-#define UART_REG(offset) (((unsigned long)control_base + offset))
-#define UART_REGB(offset) (__METAL_ACCESS_ONCE((__metal_io_u8 *)UART_REG(offset)))
-#define UART_REGW(offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)UART_REG(offset)))
-
-struct metal_interrupt *
-__metal_driver_sifive_uart0_interrupt_controller(struct metal_uart *uart)
-{
- return __metal_driver_sifive_uart0_interrupt_parent(uart);
-}
-
-int __metal_driver_sifive_uart0_get_interrupt_id(struct metal_uart *uart)
-{
- return (__metal_driver_sifive_uart0_interrupt_line(uart) + METAL_INTERRUPT_ID_GL0);
-}
-
-
-int __metal_driver_sifive_uart0_txready(struct metal_uart *uart)
-{
- long control_base = __metal_driver_sifive_uart0_control_base(uart);
-
- return !((UART_REGW(METAL_SIFIVE_UART0_TXDATA) & UART_TXFULL));
-}
-
-
-int __metal_driver_sifive_uart0_putc(struct metal_uart *uart, int c)
-{
- long control_base = __metal_driver_sifive_uart0_control_base(uart);
-
- while (!__metal_driver_sifive_uart0_txready(uart)) {
- /* wait */
- }
- UART_REGW(METAL_SIFIVE_UART0_TXDATA) = c;
- return 0;
-}
-
-
-int __metal_driver_sifive_uart0_getc(struct metal_uart *uart, int *c)
-{
- uint32_t ch;
- long control_base = __metal_driver_sifive_uart0_control_base(uart);
- /* No seperate status register, we get status and the byte at same time */
- ch = UART_REGW(METAL_SIFIVE_UART0_RXDATA);;
- if( ch & UART_RXEMPTY ){
- *c = -1; /* aka: EOF in most of the world */
- } else {
- *c = ch & 0x0ff;
- }
- return 0;
-}
-
-
-int __metal_driver_sifive_uart0_get_baud_rate(struct metal_uart *guart)
-{
- struct __metal_driver_sifive_uart0 *uart = (void *)guart;
- return uart->baud_rate;
-}
-
-int __metal_driver_sifive_uart0_set_baud_rate(struct metal_uart *guart, int baud_rate)
-{
- struct __metal_driver_sifive_uart0 *uart = (void *)guart;
- long control_base = __metal_driver_sifive_uart0_control_base(guart);
- struct metal_clock *clock = __metal_driver_sifive_uart0_clock(guart);
-
- uart->baud_rate = baud_rate;
-
- if (clock != NULL) {
- long clock_rate = clock->vtable->get_rate_hz(clock);
- UART_REGW(METAL_SIFIVE_UART0_DIV) = clock_rate / baud_rate - 1;
- UART_REGW(METAL_SIFIVE_UART0_TXCTRL) |= UART_TXEN;
- UART_REGW(METAL_SIFIVE_UART0_RXCTRL) |= UART_RXEN;
- }
- return 0;
-}
-
-static void pre_rate_change_callback_func(void *priv)
-{
- struct __metal_driver_sifive_uart0 *uart = priv;
- long control_base = __metal_driver_sifive_uart0_control_base((struct metal_uart *)priv);
- struct metal_clock *clock = __metal_driver_sifive_uart0_clock((struct metal_uart *)priv);
-
- /* Detect when the TXDATA is empty by setting the transmit watermark count
- * to one and waiting until an interrupt is pending */
-
- UART_REGW(METAL_SIFIVE_UART0_TXCTRL) &= ~(UART_TXCNT(0x7));
- UART_REGW(METAL_SIFIVE_UART0_TXCTRL) |= UART_TXCNT(1);
-
- while((UART_REGW(METAL_SIFIVE_UART0_IP) & UART_TXWM) == 0) ;
-
- /* When the TXDATA clears, the UART is still shifting out the last byte.
- * Calculate the time we must drain to finish transmitting and then wait
- * that long. */
-
- long bits_per_symbol = (UART_REGW(METAL_SIFIVE_UART0_TXCTRL) & (1 << 1)) ? 9 : 10;
- long clk_freq = clock->vtable->get_rate_hz(clock);
- long cycles_to_wait = bits_per_symbol * clk_freq / uart->baud_rate;
-
- for(volatile long x = 0; x < cycles_to_wait; x++)
- __asm__("nop");
-}
-
-static void post_rate_change_callback_func(void *priv)
-{
- struct __metal_driver_sifive_uart0 *uart = priv;
- metal_uart_set_baud_rate(&uart->uart, uart->baud_rate);
-}
-
-void __metal_driver_sifive_uart0_init(struct metal_uart *guart, int baud_rate)
-{
- struct __metal_driver_sifive_uart0 *uart = (void *)(guart);
- struct metal_clock *clock = __metal_driver_sifive_uart0_clock(guart);
- struct __metal_driver_sifive_gpio0 *pinmux = __metal_driver_sifive_uart0_pinmux(guart);
-
- if(clock != NULL) {
- uart->pre_rate_change_callback.callback = &pre_rate_change_callback_func;
- uart->pre_rate_change_callback.priv = guart;
- metal_clock_register_pre_rate_change_callback(clock, &(uart->pre_rate_change_callback));
-
- uart->post_rate_change_callback.callback = &post_rate_change_callback_func;
- uart->post_rate_change_callback.priv = guart;
- metal_clock_register_post_rate_change_callback(clock, &(uart->post_rate_change_callback));
- }
-
- metal_uart_set_baud_rate(&(uart->uart), baud_rate);
-
- if (pinmux != NULL) {
- long pinmux_output_selector = __metal_driver_sifive_uart0_pinmux_output_selector(guart);
- long pinmux_source_selector = __metal_driver_sifive_uart0_pinmux_source_selector(guart);
- pinmux->gpio.vtable->enable_io(
- (struct metal_gpio *) pinmux,
- pinmux_output_selector,
- pinmux_source_selector
- );
- }
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_uart0) = {
- .uart.init = __metal_driver_sifive_uart0_init,
- .uart.putc = __metal_driver_sifive_uart0_putc,
- .uart.getc = __metal_driver_sifive_uart0_getc,
- .uart.get_baud_rate = __metal_driver_sifive_uart0_get_baud_rate,
- .uart.set_baud_rate = __metal_driver_sifive_uart0_set_baud_rate,
- .uart.controller_interrupt = __metal_driver_sifive_uart0_interrupt_controller,
- .uart.get_interrupt_id = __metal_driver_sifive_uart0_get_interrupt_id,
-};
-
-#endif /* METAL_SIFIVE_UART0 */
-
-typedef int no_empty_translation_units;
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_WDOG0
-
-#include <metal/drivers/sifive_uart0.h>
-#include <metal/machine.h>
-
-#include <limits.h>
-
-/* WDOGCFG */
-#define METAL_WDOGCFG_SCALE_MASK 7
-#define METAL_WDOGCFG_RSTEN (1 << 8)
-#define METAL_WDOGCFG_ZEROCMP (1 << 9)
-#define METAL_WDOGCFG_ENALWAYS (1 << 12)
-#define METAL_WDOGCFG_COREAWAKE (1 << 13)
-#define METAL_WDOGCFG_IP (1 << 28)
-
-/* WDOGCMP */
-#define METAL_WDOGCMP_MASK 0xFFFF
-
-#define WDOG_REG(base, offset) (((unsigned long)base + offset))
-#define WDOG_REGB(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u8 *)WDOG_REG(base, offset)))
-#define WDOG_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)WDOG_REG(base, offset)))
-
-/* All writes to watchdog registers must be precedded by a write of
- * a magic number to WDOGKEY */
-#define WDOG_UNLOCK(base) (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGKEY) = METAL_SIFIVE_WDOG0_MAGIC_KEY)
-
-/* Unlock the watchdog and then perform a register access */
-#define WDOG_UNLOCK_REGW(base, offset) \
- WDOG_UNLOCK(base);\
- WDOG_REGW(base, offset)
-
-int __metal_driver_sifive_wdog0_feed(const struct metal_watchdog *const wdog)
-{
- const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
-
- WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGFEED) = METAL_SIFIVE_WDOG0_MAGIC_FOOD;
-
- return 0;
-}
-
-long int __metal_driver_sifive_wdog0_get_rate(const struct metal_watchdog *const wdog)
-{
- const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
- const struct metal_clock *const clock = __metal_driver_sifive_wdog0_clock(wdog);
-
- const long int clock_rate = metal_clock_get_rate_hz(clock);
-
- if (clock_rate == 0)
- return -1;
-
- const unsigned int scale = (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) & METAL_WDOGCFG_SCALE_MASK);
-
- return clock_rate / (1 << scale);
-}
-
-long int __metal_driver_sifive_wdog0_set_rate(const struct metal_watchdog *const wdog, const long int rate)
-{
- const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
- const struct metal_clock *const clock = __metal_driver_sifive_wdog0_clock(wdog);
-
- const long int clock_rate = metal_clock_get_rate_hz(clock);
-
- if (rate >= clock_rate) {
- /* We can't scale the rate above the driving clock. Clear the scale
- * field and return the driving clock rate */
- WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_SCALE_MASK);
- return clock_rate;
- }
-
- /* Look for the closest scale value */
- long min_diff = LONG_MAX;
- unsigned int min_scale = 0;
- for (int i = 0; i < METAL_WDOGCFG_SCALE_MASK; i++) {
- const long int new_rate = clock_rate / (1 << i);
-
- long int diff = rate - new_rate;
- if (diff < 0)
- diff *= -1;
-
- if (diff < min_diff) {
- min_diff = diff;
- min_scale = i;
- }
- }
-
- WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_SCALE_MASK);
- WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= (METAL_WDOGCFG_SCALE_MASK & min_scale);
-
- return clock_rate / (1 << min_scale);
-}
-
-long int __metal_driver_sifive_wdog0_get_timeout(const struct metal_watchdog *const wdog)
-{
- const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
-
- return (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP) & METAL_WDOGCMP_MASK);
-}
-
-long int __metal_driver_sifive_wdog0_set_timeout(const struct metal_watchdog *const wdog, const long int timeout)
-{
- const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
-
- /* Cap the timeout at the max value */
- const long int set_timeout = timeout > METAL_WDOGCMP_MASK ? METAL_WDOGCMP_MASK : timeout;
-
- /* If we edit the timeout value in-place by masking the compare value to 0 and
- * then writing it, we cause a spurious interrupt because the compare value
- * is temporarily 0. Instead, read the value into a local variable, modify it
- * there, and then write the whole register back */
- uint32_t wdogcmp = WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP);
-
- wdogcmp &= ~(METAL_WDOGCMP_MASK);
- wdogcmp |= set_timeout;
-
- WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP) = wdogcmp;
-
- return set_timeout;
-}
-
-int __metal_driver_sifive_wdog0_set_result(const struct metal_watchdog *const wdog,
- const enum metal_watchdog_result result)
-{
- const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
-
- /* Turn off reset enable and counter reset */
- WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_RSTEN | METAL_WDOGCFG_ZEROCMP);
-
- switch (result) {
- default:
- case METAL_WATCHDOG_NO_RESULT:
- break;
- case METAL_WATCHDOG_INTERRUPT:
- /* Reset counter to zero after match */
- WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_ZEROCMP;
- break;
- case METAL_WATCHDOG_FULL_RESET:
- WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_RSTEN;
- break;
- }
-
- return 0;
-}
-
-int __metal_driver_sifive_wdog0_run(const struct metal_watchdog *const wdog,
- const enum metal_watchdog_run_option option)
-{
- const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
-
- WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_ENALWAYS | METAL_WDOGCFG_COREAWAKE);
-
- switch (option) {
- default:
- case METAL_WATCHDOG_STOP:
- break;
- case METAL_WATCHDOG_RUN_ALWAYS:
- /* Feed the watchdog before starting to reset counter */
- __metal_driver_sifive_wdog0_feed(wdog);
-
- WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_ENALWAYS;
- break;
- case METAL_WATCHDOG_RUN_AWAKE:
- /* Feed the watchdog before starting to reset counter */
- __metal_driver_sifive_wdog0_feed(wdog);
-
- WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_COREAWAKE;
- break;
- }
-
- return 0;
-}
-
-struct metal_interrupt *__metal_driver_sifive_wdog0_get_interrupt(const struct metal_watchdog *const wdog)
-{
- return __metal_driver_sifive_wdog0_interrupt_parent(wdog);
-}
-
-int __metal_driver_sifive_wdog0_get_interrupt_id(const struct metal_watchdog *const wdog)
-{
- return __metal_driver_sifive_wdog0_interrupt_line(wdog);
-}
-
-int __metal_driver_sifive_wdog0_clear_interrupt(const struct metal_watchdog *const wdog)
-{
- const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
-
- /* Clear the interrupt pending bit */
- WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_IP);
-
- return 0;
-}
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_wdog0) = {
- .watchdog.feed = __metal_driver_sifive_wdog0_feed,
- .watchdog.get_rate = __metal_driver_sifive_wdog0_get_rate,
- .watchdog.set_rate = __metal_driver_sifive_wdog0_set_rate,
- .watchdog.get_timeout = __metal_driver_sifive_wdog0_get_timeout,
- .watchdog.set_timeout = __metal_driver_sifive_wdog0_set_timeout,
- .watchdog.set_result = __metal_driver_sifive_wdog0_set_result,
- .watchdog.run = __metal_driver_sifive_wdog0_run,
- .watchdog.get_interrupt = __metal_driver_sifive_wdog0_get_interrupt,
- .watchdog.get_interrupt_id = __metal_driver_sifive_wdog0_get_interrupt_id,
- .watchdog.clear_interrupt = __metal_driver_sifive_wdog0_clear_interrupt,
-};
-
-#endif /* METAL_SIFIVE_WDOG0 */
-
-typedef int no_empty_translation_units;
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-/* This code executes before _start, which is contained inside the C library.
- * In embedded systems we want to ensure that _enter, which contains the first
- * code to be executed, can be loaded at a specific address. To enable this
- * feature we provide the '.text.metal.init.enter' section, which is
- * defined to have the first address being where execution should start. */
-.section .text.metal.init.enter
-.global _enter
-_enter:
- .cfi_startproc
-
- /* Inform the debugger that there is nowhere to backtrace past _enter. */
- .cfi_undefined ra
-
- /* The absolute first thing that must happen is configuring the global
- * pointer register, which must be done with relaxation disabled because
- * it's not valid to obtain the address of any symbol without GP
- * configured. The C environment might go ahead and do this again, but
- * that's safe as it's a fixed register. */
-.option push
-.option norelax
- la gp, __global_pointer$
-.option pop
-
- /* Set up a simple trap vector to catch anything that goes wrong early in
- * the boot process. */
- la t0, early_trap_vector
- csrw mtvec, t0
- /* enable chicken bit if core is bullet series*/
- la t0, __metal_chicken_bit
- beqz t0, 1f
- csrwi 0x7C1, 0
-1:
-
- /* There may be pre-initialization routines inside the MBI code that run in
- * C, so here we set up a C environment. First we set up a stack pointer,
- * which is left as a weak reference in order to allow initialization
- * routines that do not need a stack to be set up to transparently be
- * called. */
- .weak __metal_stack_pointer
- la sp, __metal_stack_pointer
-
- /* Check for an initialization routine and call it if one exists, otherwise
- * just skip over the call entirely. Note that __metal_initialize isn't
- * actually a full C function, as it doesn't end up with the .bss or .data
- * segments having been initialized. This is done to avoid putting a
- * burden on systems that can be initialized without having a C environment
- * set up. */
- .weak __metal_before_start
- la ra, __metal_before_start
- beqz ra, 1f
- jalr ra
-1:
-
- /* At this point we can enter the C runtime's startup file. The arguments
- * to this function are designed to match those provided to the SEE, just
- * so we don't have to write another ABI. */
- csrr a0, mhartid
- li a1, 0
- li a2, 0
- call _start
-
- /* If we've made it back here then there's probably something wrong. We
- * allow the METAL to register a handler here. */
- .weak __metal_after_main
- la ra, __metal_after_main
- beqz ra, 1f
- jalr ra
-1:
-
- /* If that handler returns then there's not a whole lot we can do. Just
- * try to make some noise. */
- la t0, 1f
- csrw mtvec, t0
-1:
- lw t1, 0(x0)
- j 1b
-
- .cfi_endproc
-
-/* For sanity's sake we set up an early trap vector that just does nothing. If
- * you end up here then there's a bug in the early boot code somewhere. */
-.section .text.metal.init.trapvec
-.align 2
-early_trap_vector:
- .cfi_startproc
- csrr t0, mcause
- csrr t1, mepc
- csrr t2, mtval
- j early_trap_vector
- .cfi_endproc
-
-/* The GCC port might not emit a __register_frame_info symbol, which eventually
- * results in a weak undefined reference that eventually causes crash when it
- * is dereference early in boot. We really shouldn't need to put this here,
- * but to deal with what I think is probably a bug in the linker script I'm
- * going to leave this in for now. At least it's fairly cheap :) */
-.weak __register_frame_info
-.global __register_frame_info
-.section .text.metal.init.__register_frame_info
-__register_frame_info:
- .cfi_startproc
- ret
- .cfi_endproc
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine.h>
-#include <metal/gpio.h>
-
-extern __inline__ int metal_gpio_disable_input(struct metal_gpio *gpio, int pin);
-extern __inline__ int metal_gpio_enable_input(struct metal_gpio *gpio, int pin);
-extern __inline__ int metal_gpio_enable_output(struct metal_gpio *gpio, int pin);
-extern __inline__ int metal_gpio_disable_output(struct metal_gpio *gpio, int pin);
-extern __inline__ int metal_gpio_get_output_pin(struct metal_gpio *gpio, int pin);
-extern __inline__ int metal_gpio_get_input_pin(struct metal_gpio *gpio, int pin);
-extern __inline__ int metal_gpio_set_pin(struct metal_gpio *, int pin, int value);
-extern __inline__ int metal_gpio_clear_pin(struct metal_gpio *, int pin);
-extern __inline__ int metal_gpio_toggle_pin(struct metal_gpio *, int pin);
-extern __inline__ int metal_gpio_enable_pinmux(struct metal_gpio *, int pin, int io_function);
-extern __inline__ int metal_gpio_disable_pinmux(struct metal_gpio *, int pin);
-extern __inline__ struct metal_interrupt* metal_gpio_interrupt_controller(struct metal_gpio *gpio);
-extern __inline__ int metal_gpio_get_interrupt_id(struct metal_gpio *gpio, int pin);
-extern __inline__ int metal_gpio_config_interrupt(struct metal_gpio *gpio, int pin, int intr_type);
-extern __inline__ int metal_gpio_clear_interrupt(struct metal_gpio *gpio, int pin, int intr_type);
-
-struct metal_gpio *metal_gpio_get_device(unsigned int device_num)
-{
- if(device_num > __MEE_DT_MAX_GPIOS) {
- return NULL;
- }
-
- return (struct metal_gpio *) __metal_gpio_table[device_num];
-}
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <string.h>
-#include <metal/interrupt.h>
-#include <metal/machine.h>
-
-struct metal_interrupt* metal_interrupt_get_controller (metal_intr_cntrl_type cntrl,
- int id)
-{
- switch (cntrl) {
- case METAL_CPU_CONTROLLER:
- break;
- case METAL_CLINT_CONTROLLER:
-#ifdef __METAL_DT_RISCV_CLINT0_HANDLE
- return __METAL_DT_RISCV_CLINT0_HANDLE;
-#endif
- break;
- case METAL_CLIC_CONTROLLER:
-#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
- return __METAL_DT_SIFIVE_CLIC0_HANDLE;
-#endif
- break;
- case METAL_PLIC_CONTROLLER:
-#ifdef __METAL_DT_RISCV_PLIC0_HANDLE
- return __METAL_DT_RISCV_PLIC0_HANDLE;
-#endif
- break;
- }
- return NULL;
-}
-
-extern __inline__ void metal_interrupt_init(struct metal_interrupt *controller);
-
-extern __inline__ int metal_interrupt_set_vector_mode(struct metal_interrupt *controller,
- metal_vector_mode mode);
-extern __inline__ metal_vector_mode metal_interrupt_get_vector_mode(struct metal_interrupt *controller);
-
-extern __inline__ int metal_interrupt_set_privilege(struct metal_interrupt *controller,
- metal_intr_priv_mode mode);
-extern __inline__ metal_intr_priv_mode metal_interrupt_get_privilege(struct metal_interrupt *controller);
-
-extern __inline__ int metal_interrupt_set_threshold(struct metal_interrupt *controller,
- unsigned int level);
-extern __inline__ unsigned int metal_interrupt_get_threshold(struct metal_interrupt *controller);
-
-extern __inline__ unsigned int metal_interrupt_get_priority(struct metal_interrupt *controller, int id);
-
-extern __inline__ int metal_interrupt_set_priority(struct metal_interrupt *controller, int id, unsigned int priority);
-
-extern __inline__ int metal_interrupt_clear(struct metal_interrupt *controller, int id);
-
-extern __inline__ int metal_interrupt_set(struct metal_interrupt *controller, int id);
-
-extern __inline__ int metal_interrupt_register_handler(struct metal_interrupt *controller,
- int id,
- metal_interrupt_handler_t handler,
- void *priv);
-
-extern __inline__ int metal_interrupt_register_vector_handler(struct metal_interrupt *controller,
- int id,
- metal_interrupt_vector_handler_t handler,
- void *priv_data);
-
-extern __inline__ int metal_interrupt_enable(struct metal_interrupt *controller, int id);
-
-extern __inline__ int metal_interrupt_disable(struct metal_interrupt *controller, int id);
-
-extern __inline__ unsigned int metal_interrupt_get_threshold(struct metal_interrupt *controller);
-
-extern __inline__ int metal_interrupt_set_threshold(struct metal_interrupt *controller, unsigned int threshold);
-
-extern __inline__ unsigned int metal_interrupt_get_priority(struct metal_interrupt *controller, int id);
-
-extern __inline__ int metal_interrupt_set_priority(struct metal_interrupt *controller, int id, unsigned int priority);
-
-extern __inline__ int metal_interrupt_vector_enable(struct metal_interrupt *controller, int id);
-
-extern __inline__ int metal_interrupt_vector_disable(struct metal_interrupt *controller, int id);
-
-extern __inline__ int _metal_interrupt_command_request(struct metal_interrupt *controller,
- int cmd, void *data);
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <string.h>
-#include <metal/led.h>
-#include <metal/machine.h>
-
-struct metal_led* metal_led_get_rgb (char *label, char *color)
-{
- int i;
- struct metal_led *led;
- char led_label[100];
-
- if ((__METAL_DT_MAX_LEDS == 0) ||
- (label == NULL) || (color == NULL)) {
- return NULL;
- }
-
- strcpy(led_label, label);
- strcat(led_label, color);
- for (i = 0; i < __METAL_DT_MAX_LEDS; i++) {
- led = (struct metal_led*)__metal_led_table[i];
- if (led->vtable->led_exist(led, led_label)) {
- return led;
- }
- }
- return NULL;
-}
-
-struct metal_led* metal_led_get (char *label)
-{
- return metal_led_get_rgb(label, "");
-}
-
-extern __inline__ void metal_led_enable(struct metal_led *led);
-extern __inline__ void metal_led_on(struct metal_led *led);
-extern __inline__ void metal_led_off(struct metal_led *led);
-extern __inline__ void metal_led_toggle(struct metal_led *led);
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/lock.h>
-
-extern __inline__ int metal_lock_init(struct metal_lock *lock);
-extern __inline__ int metal_lock_take(struct metal_lock *lock);
-extern __inline__ int metal_lock_give(struct metal_lock *lock);
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine.h>
-#include <metal/memory.h>
-
-struct metal_memory *metal_get_memory_from_address(const uintptr_t address) {
- for(int i = 0; i < __METAL_DT_MAX_MEMORIES; i++) {
- struct metal_memory *mem = __metal_memory_table[i];
-
- uintptr_t lower_bound = metal_memory_get_base_address(mem);
- uintptr_t upper_bound = lower_bound + metal_memory_get_size(mem);
-
- if((address >= lower_bound) && (address < upper_bound)) {
- return mem;
- }
- }
-
- return NULL;
-}
-
-extern __inline__ uintptr_t metal_memory_get_base_address(const struct metal_memory *memory);
-extern __inline__ size_t metal_memory_get_size(const struct metal_memory *memory);
-extern __inline__ int metal_memory_supports_atomics(const struct metal_memory *memory);
-extern __inline__ int metal_memory_is_cachable(const struct metal_memory *memory);
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine.h>
-#include <metal/pmp.h>
-#include <metal/cpu.h>
-
-#define CONFIG_TO_INT(_config) (*((char *) &(_config)))
-#define INT_TO_CONFIG(_int) (*((struct metal_pmp_config *)(char *) &(_int)))
-
-struct metal_pmp *metal_pmp_get_device(void)
-{
-#ifdef __METAL_DT_PMP_HANDLE
- return __METAL_DT_PMP_HANDLE;
-#else
- return NULL;
-#endif
-}
-
-/* This function calculates the minimum granularity from the address
- * that pmpaddr takes on after writing all ones to pmpaddr when pmpcfg = 0.
- *
- * Detect the address granularity based on the position of the
- * least-significant 1 set in the address.
- *
- * For example, if the value read from pmpaddr is 0x3ffffc00, the
- * least-significant set bit is in bit 10 (counting from 0), resulting
- * in a detected granularity of 2^(10 + 2) = 4096.
- */
-static uintptr_t _get_detected_granularity(uintptr_t address) {
- if(address == 0) {
- return (uintptr_t) -1;
- }
-
- /* Get the index of the least significant set bit */
- int index = 0;
- while(((address >> index) & 0x1) == 0) {
- index += 1;
- }
-
- /* The granularity is equal to 2^(index + 2) bytes */
- return (1 << (index + 2));
-}
-
-/* This function calculates the granularity requested by the user's provided
- * value for pmpaddr.
- *
- * Calculate the requested granularity based on the position of the
- * least-significant unset bit.
- *
- * For example, if the requested address is 0x20009ff, the least-significant
- * unset bit is at index 9 (counting from 0), resulting in a requested
- * granularity of 2^(9 + 3) = 4096.
- */
-static uintptr_t _get_pmpaddr_granularity(uintptr_t address) {
- /* Get the index of the least significant unset bit */
- int index = 0;
- while(((address >> index) & 0x1) == 1) {
- index += 1;
- }
-
- /* The granularity is equal to 2^(index + 3) bytes */
- return (1 << (index + 3));
-}
-
-/* Get the number of pmp regions for the given hart */
-int metal_pmp_num_regions(int hartid)
-{
- struct metal_cpu *cpu = metal_cpu_get(hartid);
-
- return __metal_driver_cpu_num_pmp_regions(cpu);
-}
-
-/* Get the number of pmp regions for the current hart */
-static unsigned int _pmp_regions() {
- return metal_pmp_num_regions(metal_cpu_get_current_hartid());
-}
-
-void metal_pmp_init(struct metal_pmp *pmp) {
- if(!pmp) {
- return;
- }
-
- struct metal_pmp_config init_config = {
- .L = METAL_PMP_UNLOCKED,
- .A = METAL_PMP_OFF,
- .X = 0,
- .W = 0,
- .R = 0,
- };
-
- for(unsigned int i = 0; i < _pmp_regions(); i++) {
- metal_pmp_set_region(pmp, i, init_config, 0);
- }
-
- /* Detect the region granularity by writing all 1s to pmpaddr0 while
- * pmpcfg0 = 0. */
- if(metal_pmp_set_address(pmp, 0, -1) != 0) {
- /* Failed to detect granularity */
- return;
- }
-
- /* Calculate the granularity based on the value that pmpaddr0 takes on */
- pmp->_granularity[metal_cpu_get_current_hartid()] = _get_detected_granularity(metal_pmp_get_address(pmp, 0));
-
- /* Clear pmpaddr0 */
- metal_pmp_set_address(pmp, 0, 0);
-}
-
-int metal_pmp_set_region(struct metal_pmp *pmp,
- unsigned int region,
- struct metal_pmp_config config,
- size_t address)
-{
- struct metal_pmp_config old_config;
- size_t old_address;
- size_t cfgmask;
- size_t pmpcfg;
- int rc = 0;
-
- if(!pmp) {
- /* Device handle cannot be NULL */
- return 1;
- }
-
- if(region > _pmp_regions()) {
- /* Region outside of supported range */
- return 2;
- }
-
- if(config.A == METAL_PMP_NA4 && pmp->_granularity[metal_cpu_get_current_hartid()] > 4) {
- /* The requested granularity is too small */
- return 3;
- }
-
- if(config.A == METAL_PMP_NAPOT &&
- pmp->_granularity[metal_cpu_get_current_hartid()] > _get_pmpaddr_granularity(address))
- {
- /* The requested granularity is too small */
- return 3;
- }
-
- rc = metal_pmp_get_region(pmp, region, &old_config, &old_address);
- if(rc) {
- /* Error reading region */
- return rc;
- }
-
- if(old_config.L == METAL_PMP_LOCKED) {
- /* Cannot modify locked region */
- return 4;
- }
-
- /* Update the address first, because if the region is being locked we won't
- * be able to modify it after we set the config */
- if(old_address != address) {
- switch(region) {
- case 0:
- __asm__("csrw pmpaddr0, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 1:
- __asm__("csrw pmpaddr1, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 2:
- __asm__("csrw pmpaddr2, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 3:
- __asm__("csrw pmpaddr3, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 4:
- __asm__("csrw pmpaddr4, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 5:
- __asm__("csrw pmpaddr5, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 6:
- __asm__("csrw pmpaddr6, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 7:
- __asm__("csrw pmpaddr7, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 8:
- __asm__("csrw pmpaddr8, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 9:
- __asm__("csrw pmpaddr9, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 10:
- __asm__("csrw pmpaddr10, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 11:
- __asm__("csrw pmpaddr11, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 12:
- __asm__("csrw pmpaddr12, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 13:
- __asm__("csrw pmpaddr13, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 14:
- __asm__("csrw pmpaddr14, %[addr]"
- :: [addr] "r" (address) :);
- break;
- case 15:
- __asm__("csrw pmpaddr15, %[addr]"
- :: [addr] "r" (address) :);
- break;
- }
- }
-
-#if __riscv_xlen==32
- if(CONFIG_TO_INT(old_config) != CONFIG_TO_INT(config)) {
- /* Mask to clear old pmpcfg */
- cfgmask = (0xFF << (8 * (region % 4)) );
- pmpcfg = (CONFIG_TO_INT(config) << (8 * (region % 4)) );
-
- switch(region / 4) {
- case 0:
- __asm__("csrc pmpcfg0, %[mask]"
- :: [mask] "r" (cfgmask) :);
-
- __asm__("csrs pmpcfg0, %[cfg]"
- :: [cfg] "r" (pmpcfg) :);
- break;
- case 1:
- __asm__("csrc pmpcfg1, %[mask]"
- :: [mask] "r" (cfgmask) :);
-
- __asm__("csrs pmpcfg1, %[cfg]"
- :: [cfg] "r" (pmpcfg) :);
- break;
- case 2:
- __asm__("csrc pmpcfg2, %[mask]"
- :: [mask] "r" (cfgmask) :);
-
- __asm__("csrs pmpcfg2, %[cfg]"
- :: [cfg] "r" (pmpcfg) :);
- break;
- case 3:
- __asm__("csrc pmpcfg3, %[mask]"
- :: [mask] "r" (cfgmask) :);
-
- __asm__("csrs pmpcfg3, %[cfg]"
- :: [cfg] "r" (pmpcfg) :);
- break;
- }
- }
-#elif __riscv_xlen==64
- if(CONFIG_TO_INT(old_config) != CONFIG_TO_INT(config)) {
- /* Mask to clear old pmpcfg */
- cfgmask = (0xFF << (8 * (region % 8)) );
- pmpcfg = (CONFIG_TO_INT(config) << (8 * (region % 8)) );
-
- switch(region / 8) {
- case 0:
- __asm__("csrc pmpcfg0, %[mask]"
- :: [mask] "r" (cfgmask) :);
-
- __asm__("csrs pmpcfg0, %[cfg]"
- :: [cfg] "r" (pmpcfg) :);
- break;
- case 1:
- __asm__("csrc pmpcfg2, %[mask]"
- :: [mask] "r" (cfgmask) :);
-
- __asm__("csrs pmpcfg2, %[cfg]"
- :: [cfg] "r" (pmpcfg) :);
- break;
- }
- }
-#else
-#error XLEN is not set to supported value for PMP driver
-#endif
-
- return 0;
-}
-
-int metal_pmp_get_region(struct metal_pmp *pmp,
- unsigned int region,
- struct metal_pmp_config *config,
- size_t *address)
-{
- size_t pmpcfg = 0;
- char *pmpcfg_convert = (char *)&pmpcfg;
-
- if(!pmp || !config || !address) {
- /* NULL pointers are invalid arguments */
- return 1;
- }
-
- if(region > _pmp_regions()) {
- /* Region outside of supported range */
- return 2;
- }
-
-#if __riscv_xlen==32
- switch(region / 4) {
- case 0:
- __asm__("csrr %[cfg], pmpcfg0"
- : [cfg] "=r" (pmpcfg) ::);
- break;
- case 1:
- __asm__("csrr %[cfg], pmpcfg1"
- : [cfg] "=r" (pmpcfg) ::);
- break;
- case 2:
- __asm__("csrr %[cfg], pmpcfg2"
- : [cfg] "=r" (pmpcfg) ::);
- break;
- case 3:
- __asm__("csrr %[cfg], pmpcfg3"
- : [cfg] "=r" (pmpcfg) ::);
- break;
- }
-
- pmpcfg = (0xFF & (pmpcfg >> (8 * (region % 4)) ) );
-
-#elif __riscv_xlen==64
- switch(region / 8) {
- case 0:
- __asm__("csrr %[cfg], pmpcfg0"
- : [cfg] "=r" (pmpcfg) ::);
- break;
- case 1:
- __asm__("csrr %[cfg], pmpcfg2"
- : [cfg] "=r" (pmpcfg) ::);
- break;
- }
-
- pmpcfg = (0xFF & (pmpcfg >> (8 * (region % 8)) ) );
-
-#else
-#error XLEN is not set to supported value for PMP driver
-#endif
-
- *config = INT_TO_CONFIG(*pmpcfg_convert);
-
- switch(region) {
- case 0:
- __asm__("csrr %[addr], pmpaddr0"
- : [addr] "=r" (*address) ::);
- break;
- case 1:
- __asm__("csrr %[addr], pmpaddr1"
- : [addr] "=r" (*address) ::);
- break;
- case 2:
- __asm__("csrr %[addr], pmpaddr2"
- : [addr] "=r" (*address) ::);
- break;
- case 3:
- __asm__("csrr %[addr], pmpaddr3"
- : [addr] "=r" (*address) ::);
- break;
- case 4:
- __asm__("csrr %[addr], pmpaddr4"
- : [addr] "=r" (*address) ::);
- break;
- case 5:
- __asm__("csrr %[addr], pmpaddr5"
- : [addr] "=r" (*address) ::);
- break;
- case 6:
- __asm__("csrr %[addr], pmpaddr6"
- : [addr] "=r" (*address) ::);
- break;
- case 7:
- __asm__("csrr %[addr], pmpaddr7"
- : [addr] "=r" (*address) ::);
- break;
- case 8:
- __asm__("csrr %[addr], pmpaddr8"
- : [addr] "=r" (*address) ::);
- break;
- case 9:
- __asm__("csrr %[addr], pmpaddr9"
- : [addr] "=r" (*address) ::);
- break;
- case 10:
- __asm__("csrr %[addr], pmpaddr10"
- : [addr] "=r" (*address) ::);
- break;
- case 11:
- __asm__("csrr %[addr], pmpaddr11"
- : [addr] "=r" (*address) ::);
- break;
- case 12:
- __asm__("csrr %[addr], pmpaddr12"
- : [addr] "=r" (*address) ::);
- break;
- case 13:
- __asm__("csrr %[addr], pmpaddr13"
- : [addr] "=r" (*address) ::);
- break;
- case 14:
- __asm__("csrr %[addr], pmpaddr14"
- : [addr] "=r" (*address) ::);
- break;
- case 15:
- __asm__("csrr %[addr], pmpaddr15"
- : [addr] "=r" (*address) ::);
- break;
- }
-
- return 0;
-}
-
-int metal_pmp_lock(struct metal_pmp *pmp, unsigned int region)
-{
- struct metal_pmp_config config;
- size_t address;
- int rc = 0;
-
- rc = metal_pmp_get_region(pmp, region, &config, &address);
- if(rc) {
- return rc;
- }
-
- if(config.L == METAL_PMP_LOCKED) {
- return 0;
- }
-
- config.L = METAL_PMP_LOCKED;
-
- rc = metal_pmp_set_region(pmp, region, config, address);
-
- return rc;
-}
-
-
-int metal_pmp_set_address(struct metal_pmp *pmp, unsigned int region, size_t address)
-{
- struct metal_pmp_config config;
- size_t old_address;
- int rc = 0;
-
- rc = metal_pmp_get_region(pmp, region, &config, &old_address);
- if(rc) {
- return rc;
- }
-
- rc = metal_pmp_set_region(pmp, region, config, address);
-
- return rc;
-}
-
-size_t metal_pmp_get_address(struct metal_pmp *pmp, unsigned int region)
-{
- struct metal_pmp_config config;
- size_t address = 0;
-
- metal_pmp_get_region(pmp, region, &config, &address);
-
- return address;
-}
-
-
-int metal_pmp_set_address_mode(struct metal_pmp *pmp, unsigned int region, enum metal_pmp_address_mode mode)
-{
- struct metal_pmp_config config;
- size_t address;
- int rc = 0;
-
- rc = metal_pmp_get_region(pmp, region, &config, &address);
- if(rc) {
- return rc;
- }
-
- config.A = mode;
-
- rc = metal_pmp_set_region(pmp, region, config, address);
-
- return rc;
-}
-
-enum metal_pmp_address_mode metal_pmp_get_address_mode(struct metal_pmp *pmp, unsigned int region)
-{
- struct metal_pmp_config config;
- size_t address = 0;
-
- metal_pmp_get_region(pmp, region, &config, &address);
-
- return config.A;
-}
-
-
-int metal_pmp_set_executable(struct metal_pmp *pmp, unsigned int region, int X)
-{
- struct metal_pmp_config config;
- size_t address;
- int rc = 0;
-
- rc = metal_pmp_get_region(pmp, region, &config, &address);
- if(rc) {
- return rc;
- }
-
- config.X = X;
-
- rc = metal_pmp_set_region(pmp, region, config, address);
-
- return rc;
-}
-
-int metal_pmp_get_executable(struct metal_pmp *pmp, unsigned int region)
-{
- struct metal_pmp_config config;
- size_t address = 0;
-
- metal_pmp_get_region(pmp, region, &config, &address);
-
- return config.X;
-}
-
-
-int metal_pmp_set_writeable(struct metal_pmp *pmp, unsigned int region, int W)
-{
- struct metal_pmp_config config;
- size_t address;
- int rc = 0;
-
- rc = metal_pmp_get_region(pmp, region, &config, &address);
- if(rc) {
- return rc;
- }
-
- config.W = W;
-
- rc = metal_pmp_set_region(pmp, region, config, address);
-
- return rc;
-}
-
-int metal_pmp_get_writeable(struct metal_pmp *pmp, unsigned int region)
-{
- struct metal_pmp_config config;
- size_t address = 0;
-
- metal_pmp_get_region(pmp, region, &config, &address);
-
- return config.W;
-}
-
-
-int metal_pmp_set_readable(struct metal_pmp *pmp, unsigned int region, int R)
-{
- struct metal_pmp_config config;
- size_t address;
- int rc = 0;
-
- rc = metal_pmp_get_region(pmp, region, &config, &address);
- if(rc) {
- return rc;
- }
-
- config.R = R;
-
- rc = metal_pmp_set_region(pmp, region, config, address);
-
- return rc;
-}
-
-int metal_pmp_get_readable(struct metal_pmp *pmp, unsigned int region)
-{
- struct metal_pmp_config config;
- size_t address = 0;
-
- metal_pmp_get_region(pmp, region, &config, &address);
-
- return config.R;
-}
-
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <stddef.h>
-
-#include <metal/privilege.h>
-
-#define METAL_MSTATUS_MIE_OFFSET 3
-#define METAL_MSTATUS_MPIE_OFFSET 7
-#define METAL_MSTATUS_SIE_OFFSET 1
-#define METAL_MSTATUS_SPIE_OFFSET 5
-#define METAL_MSTATUS_UIE_OFFSET 0
-#define METAL_MSTATUS_UPIE_OFFSET 4
-
-#define METAL_MSTATUS_MPP_OFFSET 11
-#define METAL_MSTATUS_MPP_MASK 3
-
-void metal_privilege_drop_to_mode(enum metal_privilege_mode mode,
- struct metal_register_file regfile,
- metal_privilege_entry_point_t entry_point)
-{
- uintptr_t mstatus;
- __asm__ volatile("csrr %0, mstatus" : "=r" (mstatus));
-
- /* Set xPIE bits based on current xIE bits */
- if(mstatus && (1 << METAL_MSTATUS_MIE_OFFSET)) {
- mstatus |= (1 << METAL_MSTATUS_MPIE_OFFSET);
- } else {
- mstatus &= ~(1 << METAL_MSTATUS_MPIE_OFFSET);
- }
- if(mstatus && (1 << METAL_MSTATUS_SIE_OFFSET)) {
- mstatus |= (1 << METAL_MSTATUS_SPIE_OFFSET);
- } else {
- mstatus &= ~(1 << METAL_MSTATUS_SPIE_OFFSET);
- }
- if(mstatus && (1 << METAL_MSTATUS_UIE_OFFSET)) {
- mstatus |= (1 << METAL_MSTATUS_UPIE_OFFSET);
- } else {
- mstatus &= ~(1 << METAL_MSTATUS_UPIE_OFFSET);
- }
-
- /* Set MPP to the requested privilege mode */
- mstatus &= ~(METAL_MSTATUS_MPP_MASK << METAL_MSTATUS_MPP_OFFSET);
- mstatus |= (mode << METAL_MSTATUS_MPP_OFFSET);
-
- __asm__ volatile("csrw mstatus, %0" :: "r" (mstatus));
-
- /* Set the entry point in MEPC */
- __asm__ volatile("csrw mepc, %0" :: "r" (entry_point));
-
- /* Set the register file */
- __asm__ volatile("mv ra, %0" :: "r" (regfile.ra));
- __asm__ volatile("mv sp, %0" :: "r" (regfile.sp));
-
- __asm__ volatile("mret");
-}
-
+++ /dev/null
-/* Copyright 2019 SiFive, Inc. */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine.h>
-#include <metal/rtc.h>
-
-#include <stddef.h>
-
-extern inline uint64_t metal_rtc_get_rate(const struct metal_rtc *const rtc);
-extern inline uint64_t metal_rtc_set_rate(const struct metal_rtc *const rtc, const uint64_t rate);
-extern inline uint64_t metal_rtc_get_compare(const struct metal_rtc *const rtc);
-extern inline uint64_t metal_rtc_set_compare(const struct metal_rtc *const rtc, const uint64_t compare);
-extern inline uint64_t metal_rtc_get_count(const struct metal_rtc *const rtc);
-extern inline uint64_t metal_rtc_set_count(const struct metal_rtc *const rtc, const uint64_t count);
-extern inline int metal_rtc_run(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option);
-extern inline struct metal_interrupt *metal_rtc_get_interrupt(const struct metal_rtc *const rtc);
-extern inline int metal_rtc_get_interrupt_id(const struct metal_rtc *const rtc);
-
-struct metal_rtc *metal_rtc_get_device(int index) {
-#ifdef __METAL_DT_MAX_RTCS
- if (index < __METAL_DT_MAX_RTCS) {
- return (struct metal_rtc *) __metal_rtc_table[index];
- }
-#endif
- return NULL;
-}
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine.h>
-#include <metal/shutdown.h>
-
-extern __inline__ void __metal_shutdown_exit(const struct __metal_shutdown *sd, int code);
-
-#if defined(__METAL_DT_SHUTDOWN_HANDLE)
-void metal_shutdown(int code)
-{
- __metal_shutdown_exit(__METAL_DT_SHUTDOWN_HANDLE, code);
-}
-#else
-#pragma message("There is no defined shutdown mechanism, metal_shutdown() will spin.")
-void metal_shutdown(int code)
-{
- while (1) {
- __asm__ volatile ("nop");
- }
-}
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine.h>
-#include <metal/spi.h>
-
-extern __inline__ void metal_spi_init(struct metal_spi *spi, int baud_rate);
-extern __inline__ int metal_spi_transfer(struct metal_spi *spi, struct metal_spi_config *config, size_t len, char *tx_buf, char *rx_buf);
-extern __inline__ int metal_spi_get_baud_rate(struct metal_spi *spi);
-extern __inline__ int metal_spi_set_baud_rate(struct metal_spi *spi, int baud_rate);
-
-struct metal_spi *metal_spi_get_device(unsigned int device_num)
-{
-#if __METAL_DT_MAX_SPIS > 0
- if (device_num < __METAL_DT_MAX_SPIS) {
- return (struct metal_spi *) __metal_spi_table[device_num];
- }
-#endif
-
- return NULL;
-}
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/switch.h>
-#include <metal/machine.h>
-
-struct metal_switch* metal_switch_get (char *label)
-{
- int i;
- struct metal_switch *flip;
-
- if ((__METAL_DT_MAX_BUTTONS == 0) || (label == NULL)) {
- return NULL;
- }
-
- for (i = 0; i < __METAL_DT_MAX_BUTTONS; i++) {
- flip = (struct metal_switch*)__metal_switch_table[i];
- if (flip->vtable->switch_exist(flip, label)) {
- return flip;
- }
- }
- return NULL;
-}
-
-extern __inline__ struct metal_interrupt*
- metal_switch_interrupt_controller(struct metal_switch *flip);
-extern __inline__ int metal_switch_get_interrupt_id(struct metal_switch *flip);
+++ /dev/null
-/* 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.
- */
-__attribute__((section(".init")))
-void __metal_synchronize_harts() {
-#if __METAL_DT_MAX_HARTS > 1
-
- int hart;
- __asm__ volatile("csrr %0, mhartid" : "=r" (hart) ::);
-
- 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
-#pragma message(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 */
-}
-
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/time.h>
-#include <metal/timer.h>
-
-int metal_gettimeofday(struct timeval *tp, void *tzp)
-{
- int rv;
- unsigned long long mcc, timebase;
- if ((rv = metal_timer_get_cyclecount(0, &mcc))) {
- return -1;
- }
- if ((rv = metal_timer_get_timebase_frequency(0, &timebase))) {
- return -1;
- }
- tp->tv_sec = mcc / timebase;
- tp->tv_usec = mcc % timebase * 1000000 / timebase;
- return 0;
-}
-
-time_t metal_time (void)
-{
- struct timeval now;
-
- if (metal_gettimeofday(&now, NULL) < 0)
- now.tv_sec = (time_t) -1;
-
- return now.tv_sec;
-}
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <sys/time.h>
-#include <sys/times.h>
-#include <metal/cpu.h>
-#include <metal/timer.h>
-#include <metal/machine.h>
-
-#if defined(__METAL_DT_MAX_HARTS)
-/* This implementation serves as a small shim that interfaces with the first
- * timer on a system. */
-int metal_timer_get_cyclecount(int hartid, unsigned long long *mcc)
-{
- struct metal_cpu *cpu = metal_cpu_get(hartid);
-
- if ( cpu ) {
- *mcc = metal_cpu_get_timer(cpu);
- return 0;
- }
- return -1;
-}
-
-int metal_timer_get_timebase_frequency(int hartid, unsigned long long *timebase)
-{
- struct metal_cpu *cpu = metal_cpu_get(hartid);
-
- if ( cpu ) {
- *timebase = metal_cpu_get_timebase(cpu);
- return 0;
- }
- return -1;
-}
-
-int metal_timer_get_machine_time(int hartid)
-{
- struct metal_cpu *cpu = metal_cpu_get(hartid);
-
- if ( cpu ) {
- return metal_cpu_get_mtime(cpu);
- }
- return 0;
-}
-
-int metal_timer_set_machine_time(int hartid, unsigned long long time)
-{
- struct metal_cpu *cpu = metal_cpu_get(hartid);
-
- if ( cpu ) {
- return metal_cpu_set_mtimecmp(cpu, time);
- }
- return -1;
-}
-
-#else
-
-/* This implementation of gettimeofday doesn't actually do anything, it's just there to
- * provide a shim and return 0 so we can ensure that everything can link to _gettimeofday.
- */
-int nop_cyclecount(int id, unsigned long long *c) __attribute__((section(".text.metal.nop.cyclecount")));
-int nop_cyclecount(int id, unsigned long long *c) { return -1; }
-int nop_timebase(unsigned long long *t) __attribute__((section(".text.metal.nop.timebase")));
-int nop_timebase(unsigned long long *t) { return -1; }
-int nop_tick(int second) __attribute__((section(".text.metal.nop.tick")));
-int nop_tick(int second) { return -1; }
-int metal_timer_get_cyclecount(int hartid, unsigned long long *c) __attribute__((weak, alias("nop_cyclecount")))
-{
-#pragma message("There is no default timer device, metal_timer_get_cyclecount() will always return cyclecount -1.")
-}
-int metal_timer_get_timebase_frequency(unsigned long long *t) __attribute__((weak, alias("nop_timebase")))
-{
-#pragma message("There is no default timer device, metal_timer_get_timebase_frequency() will always return timebase -1.")
-}
-int metal_timer_set_tick(int second) __attribute__((weak, alias("nop_tick")))
-{
-#pragma message("There is no default timer device, metal_timer_set_tick) will always return -1.")
-}
-
-#endif
-
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#define METAL_MSTATUS_MIE_SHIFT 8
-#define METAL_MSTATUS_MPP_M 3
-#define METAL_MSTATUS_MPP_SHIFT 11
-
-#define METAL_MTVEC_MODE_MASK 3
-
-/* void _metal_trap(int ecode)
- *
- * Trigger a machine-mode trap with exception code ecode
- */
-.global _metal_trap
-.type _metal_trap, @function
-
-_metal_trap:
-
- /* Store the instruction which called _metal_trap in mepc */
- addi t0, ra, -1
- csrw mepc, t0
-
- /* Set mcause to the desired exception code */
- csrw mcause, a0
-
- /* Read mstatus */
- csrr t0, mstatus
-
- /* Set MIE=0 */
- li t1, -1
- xori t1, t1, METAL_MSTATUS_MIE_SHIFT
- and t0, t0, t1
-
- /* Set MPP=M */
- li t1, METAL_MSTATUS_MPP_M
- slli t1, t1, METAL_MSTATUS_MPP_SHIFT
- or t0, t0, t1
-
- /* Write mstatus */
- csrw mstatus, t0
-
- /* Read mtvec */
- csrr t0, mtvec
-
- /*
- * Mask the mtvec MODE bits
- * Exceptions always jump to mtvec.BASE regradless of the vectoring mode.
- */
- andi t0, t0, METAL_MTVEC_MODE_MASK
-
- /* Jump to mtvec */
- jr t0
-
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/uart.h>
-#include <metal/tty.h>
-#include <metal/machine.h>
-
-#if defined(__METAL_DT_STDOUT_UART_HANDLE)
-/* This implementation serves as a small shim that interfaces with the first
- * UART on a system. */
-int metal_tty_putc(int c)
-{
- if (c == '\n') {
- metal_tty_putc_raw( '\r' );
- }
- return metal_tty_putc_raw( c );
-}
-
-int metal_tty_putc_raw(int c)
-{
- return metal_uart_putc(__METAL_DT_STDOUT_UART_HANDLE, c);
-}
-
-int metal_tty_getc(int *c)
-{
- do {
- metal_uart_getc( __METAL_DT_STDOUT_UART_HANDLE, c );
- /* -1 means no key pressed, getc waits */
- } while( -1 == *c )
- ;
- return 0;
-}
-
-#ifndef __METAL_DT_STDOUT_UART_BAUD
-#define __METAL_DT_STDOUT_UART_BAUD 115200
-#endif
-
-static void metal_tty_init(void) __attribute__((constructor));
-static void metal_tty_init(void)
-{
- metal_uart_init(__METAL_DT_STDOUT_UART_HANDLE, __METAL_DT_STDOUT_UART_BAUD);
-}
-#else
-/* This implementation of putc doesn't actually do anything, it's just there to
- * provide a shim that eats all the characters so we can ensure that everything
- * can link to metal_tty_putc. */
-int nop_putc(int c) __attribute__((section(".text.metal.nop.putc")));
-int nop_putc(int c) { return -1; }
-int metal_tty_putc(int c) __attribute__((weak, alias("nop_putc")));
-#pragma message("There is no default output device, metal_tty_putc() will throw away all input.")
-#endif
+++ /dev/null
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/uart.h>
-
-extern __inline__ void metal_uart_init(struct metal_uart *uart, int baud_rate);
-extern __inline__ int metal_uart_putc(struct metal_uart *uart, int c);
-extern __inline__ int metal_uart_txready(struct metal_uart *uart);
-extern __inline__ int metal_uart_getc(struct metal_uart *uart, int *c);
-extern __inline__ int metal_uart_get_baud_rate(struct metal_uart *uart);
-extern __inline__ int metal_uart_set_baud_rate(struct metal_uart *uart, int baud_rate);
+++ /dev/null
-/* Copyright 2019 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-/*
- * Jump table for CLINT vectored mode
- */
-.weak metal_interrupt_vector_handler
-.balign 4, 0
-.global metal_interrupt_vector_handler
-
-.weak metal_software_interrupt_vector_handler
-.balign 4, 0
-.global metal_software_interrupt_vector_handler
-
-.weak metal_timer_interrupt_vector_handler
-.balign 4, 0
-.global metal_timer_interrupt_vector_handler
-
-.weak metal_external_interrupt_vector_handler
-.balign 4, 0
-.global metal_external_interrupt_vector_handler
-
-.weak metal_lc0_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc0_interrupt_vector_handler
-
-.weak metal_lc1_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc1_interrupt_vector_handler
-
-.weak metal_lc2_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc2_interrupt_vector_handler
-
-.weak metal_lc3_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc3_interrupt_vector_handler
-
-.weak metal_lc4_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc4_interrupt_vector_handler
-
-.weak metal_lc5_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc5_interrupt_vector_handler
-
-.weak metal_lc6_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc6_interrupt_vector_handler
-
-.weak metal_lc7_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc7_interrupt_vector_handler
-
-.weak metal_lc8_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc8_interrupt_vector_handler
-
-.weak metal_lc9_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc9_interrupt_vector_handler
-
-.weak metal_lc10_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc10_interrupt_vector_handler
-
-.weak metal_lc11_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc11_interrupt_vector_handler
-
-.weak metal_lc12_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc12_interrupt_vector_handler
-
-.weak metal_lc13_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc13_interrupt_vector_handler
-
-.weak metal_lc14_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc14_interrupt_vector_handler
-
-.weak metal_lc15_interrupt_vector_handler
-.balign 4, 0
-.global metal_lc15_interrupt_vector_handler
-
-#if __riscv_xlen == 32
-.balign 128, 0
-#else
-.balign 256, 0
-#endif
-.option norvc
-.global __metal_vector_table
-__metal_vector_table:
-IRQ_0:
- j metal_interrupt_vector_handler
-IRQ_1:
- j metal_interrupt_vector_handler
-IRQ_2:
- j metal_interrupt_vector_handler
-IRQ_3:
- j metal_software_interrupt_vector_handler
-IRQ_4:
- j metal_interrupt_vector_handler
-IRQ_5:
- j metal_interrupt_vector_handler
-IRQ_6:
- j metal_interrupt_vector_handler
-IRQ_7:
- j metal_timer_interrupt_vector_handler
-IRQ_8:
- j metal_interrupt_vector_handler
-IRQ_9:
- j metal_interrupt_vector_handler
-IRQ_10:
- j metal_interrupt_vector_handler
-IRQ_11:
- j metal_interrupt_vector_handler
-IRQ_12:
- j metal_interrupt_vector_handler
-IRQ_13:
- j metal_interrupt_vector_handler
-IRQ_14:
- j metal_interrupt_vector_handler
-IRQ_15:
- j metal_interrupt_vector_handler
-IRQ_LC0:
- j metal_lc0_interrupt_vector_handler
-IRQ_LC1:
- j metal_lc1_interrupt_vector_handler
-IRQ_LC2:
- j metal_lc2_interrupt_vector_handler
-IRQ_LC3:
- j metal_lc3_interrupt_vector_handler
-IRQ_LC4:
- j metal_lc4_interrupt_vector_handler
-IRQ_LC5:
- j metal_lc5_interrupt_vector_handler
-IRQ_LC6:
- j metal_lc6_interrupt_vector_handler
-IRQ_LC7:
- j metal_lc7_interrupt_vector_handler
-IRQ_LC8:
- j metal_lc8_interrupt_vector_handler
-IRQ_LC9:
- j metal_lc9_interrupt_vector_handler
-IRQ_LC10:
- j metal_lc10_interrupt_vector_handler
-IRQ_LC11:
- j metal_lc11_interrupt_vector_handler
-IRQ_LC12:
- j metal_lc12_interrupt_vector_handler
-IRQ_LC13:
- j metal_lc13_interrupt_vector_handler
-IRQ_LC14:
- j metal_lc14_interrupt_vector_handler
-IRQ_LC15:
- j metal_lc15_interrupt_vector_handler
-
-
+++ /dev/null
-/*\r
- * FreeRTOS Kernel V10.2.1\r
- * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
- * this software and associated documentation files (the "Software"), to deal in\r
- * the Software without restriction, including without limitation the rights to\r
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
- * the Software, and to permit persons to whom the Software is furnished to do so,\r
- * subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in all\r
- * copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- *\r
- * http://www.FreeRTOS.org\r
- * http://aws.amazon.com/freertos\r
- *\r
- * 1 tab == 4 spaces!\r
- */\r
-\r
- .extern ulRegTest1LoopCounter\r
- .extern ulRegTest2LoopCounter\r
-\r
- .global vRegTest1Implementation\r
- .global vRegTest2Implementation\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * The register check tasks are described in the comments at the top of\r
- * main_full.c.\r
- */\r
-\r
-.align( 4 )\r
-vRegTest1Implementation:\r
-\r
- /* Fill the core registers with known values. */\r
- li x5, 0x5\r
- li x6, 0x6\r
- li x7, 0x7\r
- li x8, 0x8\r
- li x9, 0x9\r
- li x10, 0xa\r
- li x11, 0xb\r
- li x12, 0xc\r
- li x13, 0xd\r
- li x14, 0xe\r
- li x15, 0xf\r
- li x16, 0x10\r
- li x17, 0x11\r
- li x18, 0x12\r
- li x19, 0x13\r
- li x20, 0x14\r
- li x21, 0x15\r
- li x22, 0x16\r
- li x23, 0x17\r
- li x24, 0x18\r
- li x25, 0x19\r
- li x26, 0x1a\r
- li x27, 0x1b\r
- li x28, 0x1c\r
- li x29, 0x1d\r
- li x30, 0x1e\r
-\r
-reg1_loop:\r
-\r
- /* Check each register still contains the expected known value.\r
- vRegTest1Implementation uses x31 as the temporary, vRegTest2Implementation\r
- uses x5 as the temporary. */\r
- li x31, 0x5\r
- bne x31, x5, reg1_error_loop\r
- li x31, 0x6\r
- bne x31, x6, reg1_error_loop\r
- li x31, 0x7\r
- bne x31, x7, reg1_error_loop\r
- li x31, 0x8\r
- bne x31, x8, reg1_error_loop\r
- li x31, 0x9\r
- bne x31, x9, reg1_error_loop\r
- li x31, 0xa\r
- bne x31, x10, reg1_error_loop\r
- li x31, 0xb\r
- bne x31, x11, reg1_error_loop\r
- li x31, 0xc\r
- bne x31, x12, reg1_error_loop\r
- li x31, 0xd\r
- bne x31, x13, reg1_error_loop\r
- li x31, 0xe\r
- bne x31, x14, reg1_error_loop\r
- li x31, 0xf\r
- bne x31, x15, reg1_error_loop\r
- li x31, 0x10\r
- bne x31, x16, reg1_error_loop\r
- li x31, 0x11\r
- bne x31, x17, reg1_error_loop\r
- li x31, 0x12\r
- bne x31, x18, reg1_error_loop\r
- li x31, 0x13\r
- bne x31, x19, reg1_error_loop\r
- li x31, 0x14\r
- bne x31, x20, reg1_error_loop\r
- li x31, 0x15\r
- bne x31, x21, reg1_error_loop\r
- li x31, 0x16\r
- bne x31, x22, reg1_error_loop\r
- li x31, 0x17\r
- bne x31, x23, reg1_error_loop\r
- li x31, 0x18\r
- bne x31, x24, reg1_error_loop\r
- li x31, 0x19\r
- bne x31, x25, reg1_error_loop\r
- li x31, 0x1a\r
- bne x31, x26, reg1_error_loop\r
- li x31, 0x1b\r
- bne x31, x27, reg1_error_loop\r
- li x31, 0x1c\r
- bne x31, x28, reg1_error_loop\r
- li x31, 0x1d\r
- bne x31, x29, reg1_error_loop\r
- li x31, 0x1e\r
- bne x31, x30, reg1_error_loop\r
-\r
- /* Everything passed, increment the loop counter. */\r
- lw x31, ulRegTest1LoopCounterConst\r
- lw x30, 0(x31)\r
- addi x30, x30, 1\r
- sw x30, 0(x31)\r
-\r
- /* Restore clobbered register reading for next loop. */\r
- li x30, 0x1e\r
-\r
- /* Yield to increase code coverage. */\r
- ecall\r
-\r
- /* Start again. */\r
- jal reg1_loop\r
-\r
-reg1_error_loop:\r
- /* Jump here if a register contains an uxpected value. This stops the loop\r
- counter being incremented so the check task knows an error was found. */\r
- ebreak\r
- jal reg1_error_loop\r
-\r
-.align( 4 )\r
-ulRegTest1LoopCounterConst: .word ulRegTest1LoopCounter\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-.align( 4 )\r
-vRegTest2Implementation:\r
-\r
- /* Fill the core registers with known values. */\r
- li x6, 0x61\r
- li x7, 0x71\r
- li x8, 0x81\r
- li x9, 0x91\r
- li x10, 0xa1\r
- li x11, 0xb1\r
- li x12, 0xc1\r
- li x13, 0xd1\r
- li x14, 0xe1\r
- li x15, 0xf1\r
- li x16, 0x20\r
- li x17, 0x21\r
- li x18, 0x22\r
- li x19, 0x23\r
- li x20, 0x24\r
- li x21, 0x25\r
- li x22, 0x26\r
- li x23, 0x27\r
- li x24, 0x28\r
- li x25, 0x29\r
- li x26, 0x2a\r
- li x27, 0x2b\r
- li x28, 0x2c\r
- li x29, 0x2d\r
- li x30, 0x2e\r
- li x31, 0x2f\r
-\r
-Reg2_loop:\r
-\r
- /* Check each register still contains the expected known value.\r
- vRegTest2Implementation uses x5 as the temporary, vRegTest1Implementation\r
- uses x31 as the temporary. */\r
- li x5, 0x61\r
- bne x5, x6, reg2_error_loop\r
- li x5, 0x71\r
- bne x5, x7, reg2_error_loop\r
- li x5, 0x81\r
- bne x5, x8, reg2_error_loop\r
- li x5, 0x91\r
- bne x5, x9, reg2_error_loop\r
- li x5, 0xa1\r
- bne x5, x10, reg2_error_loop\r
- li x5, 0xb1\r
- bne x5, x11, reg2_error_loop\r
- li x5, 0xc1\r
- bne x5, x12, reg2_error_loop\r
- li x5, 0xd1\r
- bne x5, x13, reg2_error_loop\r
- li x5, 0xe1\r
- bne x5, x14, reg2_error_loop\r
- li x5, 0xf1\r
- bne x5, x15, reg2_error_loop\r
- li x5, 0x20\r
- bne x5, x16, reg2_error_loop\r
- li x5, 0x21\r
- bne x5, x17, reg2_error_loop\r
- li x5, 0x22\r
- bne x5, x18, reg2_error_loop\r
- li x5, 0x23\r
- bne x5, x19, reg2_error_loop\r
- li x5, 0x24\r
- bne x5, x20, reg2_error_loop\r
- li x5, 0x25\r
- bne x5, x21, reg2_error_loop\r
- li x5, 0x26\r
- bne x5, x22, reg2_error_loop\r
- li x5, 0x27\r
- bne x5, x23, reg2_error_loop\r
- li x5, 0x28\r
- bne x5, x24, reg2_error_loop\r
- li x5, 0x29\r
- bne x5, x25, reg2_error_loop\r
- li x5, 0x2a\r
- bne x5, x26, reg2_error_loop\r
- li x5, 0x2b\r
- bne x5, x27, reg2_error_loop\r
- li x5, 0x2c\r
- bne x5, x28, reg2_error_loop\r
- li x5, 0x2d\r
- bne x5, x29, reg2_error_loop\r
- li x5, 0x2e\r
- bne x5, x30, reg2_error_loop\r
- li x5, 0x2f\r
- bne x5, x31, reg2_error_loop\r
-\r
- /* Everything passed, increment the loop counter. */\r
- lw x5, ulRegTest2LoopCounterConst\r
- lw x6, 0(x5)\r
- addi x6, x6, 1\r
- sw x6, 0(x5)\r
-\r
- /* Restore clobbered register reading for next loop. */\r
- li x6, 0x61\r
-\r
- /* Start again. */\r
- jal Reg2_loop\r
-\r
-reg2_error_loop:\r
- /* Jump here if a register contains an uxpected value. This stops the loop\r
- counter being incremented so the check task knows an error was found. */\r
- ebreak\r
- jal reg2_error_loop\r
-\r
-.align( 4 )\r
-ulRegTest2LoopCounterConst: .word ulRegTest2LoopCounter\r
-\r
-\r
+++ /dev/null
-/*\r
- * FreeRTOS Kernel V10.2.1\r
- * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
- * this software and associated documentation files (the "Software"), to deal in\r
- * the Software without restriction, including without limitation the rights to\r
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
- * the Software, and to permit persons to whom the Software is furnished to do so,\r
- * subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in all\r
- * copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- *\r
- * http://www.FreeRTOS.org\r
- * http://aws.amazon.com/freertos\r
- *\r
- * 1 tab == 4 spaces!\r
- */\r
-\r
-/******************************************************************************\r
- * NOTE 1: This project provides two demo applications. A simple blinky style\r
- * project, and a more comprehensive test and demo application. The\r
- * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting in main.c is used to select\r
- * between the two. See the notes on using mainCREATE_SIMPLE_BLINKY_DEMO_ONLY\r
- * in main.c. This file implements the comprehensive test and demo version.\r
- *\r
- * NOTE 2: This file only contains the source code that is specific to the\r
- * full demo. Generic functions, such FreeRTOS hook functions, and functions\r
- * required to configure the hardware, are defined in main.c.\r
- *\r
- ******************************************************************************\r
- *\r
- * main_full() creates all the demo application tasks and software timers, then\r
- * starts the scheduler. The web documentation provides more details of the\r
- * standard demo application tasks, which provide no particular functionality,\r
- * but do provide a good example of how to use the FreeRTOS API.\r
- *\r
- * In addition to the standard demo tasks, the following tasks and tests are\r
- * defined and/or created within this file:\r
- *\r
- * "Reg test" tasks - These fill both the core registers with known values, then\r
- * check that each register maintains its expected value for the lifetime of the\r
- * task. Each task uses a different set of values. The reg test tasks execute\r
- * with a very low priority, so get preempted very frequently. A register\r
- * containing an unexpected value is indicative of an error in the context\r
- * switching mechanism.\r
- *\r
- * "Check" task - The check executes every three seconds. It checks that all\r
- * the standard demo tasks, and the register check tasks, are not only still\r
- * executing, but are executing without reporting any errors. The check task\r
- * toggles the LED every three seconds if all the standard demo tasks are\r
- * executing as expected, or every 500ms if a potential error is discovered in\r
- * any task.\r
- */\r
-\r
-/* Standard includes. */\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <unistd.h>\r
-\r
-/* Kernel includes. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "timers.h"\r
-#include "semphr.h"\r
-\r
-/* Standard demo application includes. */\r
-#include "dynamic.h"\r
-#include "blocktim.h"\r
-#include "TimerDemo.h"\r
-#include "TaskNotify.h"\r
-\r
-/* Priorities for the demo application tasks. */\r
-#define mainCHECK_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )\r
-\r
-/* The period of the check task, in ms, converted to ticks using the\r
-pdMS_TO_TICKS() macro. mainNO_ERROR_CHECK_TASK_PERIOD is used if no errors have\r
-been found, mainERROR_CHECK_TASK_PERIOD is used if an error has been found. */\r
-#define mainNO_ERROR_CHECK_TASK_PERIOD pdMS_TO_TICKS( 3000UL )\r
-#define mainERROR_CHECK_TASK_PERIOD pdMS_TO_TICKS( 500UL )\r
-\r
-/* Parameters that are passed into the register check tasks solely for the\r
-purpose of ensuring parameters are passed into tasks correctly. */\r
-#define mainREG_TEST_TASK_1_PARAMETER ( ( void * ) 0x12345678 )\r
-#define mainREG_TEST_TASK_2_PARAMETER ( ( void * ) 0x87654321 )\r
-\r
-/* The base period used by the timer test tasks. */\r
-#define mainTIMER_TEST_PERIOD ( 50 )\r
-\r
-/* The size of the stack allocated to the check task (as described in the\r
-comments at the top of this file. */\r
-#define mainCHECK_TASK_STACK_SIZE_WORDS 160\r
-\r
-/* Size of the stacks to allocated for the register check tasks. */\r
-#define mainREG_TEST_STACK_SIZE_WORDS 90\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Called by main() to run the full demo (as opposed to the blinky demo) when\r
- * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set to 0.\r
- */\r
-void main_full( void );\r
-\r
-/*\r
- * The check task, as described at the top of this file.\r
- */\r
-static void prvCheckTask( void *pvParameters );\r
-\r
-/*\r
- * Register check tasks as described at the top of this file. The nature of\r
- * these files necessitates that they are written in an assembly file, but the\r
- * entry points are kept in the C file for the convenience of checking the task\r
- * parameter.\r
- */\r
-static void prvRegTestTaskEntry1( void *pvParameters );\r
-extern void vRegTest1Implementation( void );\r
-static void prvRegTestTaskEntry2( void *pvParameters );\r
-extern void vRegTest2Implementation( void );\r
-\r
-/*\r
- * Tick hook used by the full demo, which includes code that interacts with\r
- * some of the tests.\r
- */\r
-void vFullDemoTickHook( void );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* The following two variables are used to communicate the status of the\r
-register check tasks to the check task. If the variables keep incrementing,\r
-then the register check tasks have not discovered any errors. If a variable\r
-stops incrementing, then an error has been found. */\r
-uint32_t ulRegTest1LoopCounter = 0UL, ulRegTest2LoopCounter = 0UL;\r
-volatile uint32_t *pulRegTest1LoopCounter = &ulRegTest1LoopCounter;\r
-volatile uint32_t *pulRegTest2LoopCounter = &ulRegTest2LoopCounter;\r
-/*-----------------------------------------------------------*/\r
-\r
-void main_full( void )\r
-{\r
- /* Start all the other standard demo/test tasks. They have no particular\r
- functionality, but do demonstrate how to use the FreeRTOS API and test the\r
- kernel port. */\r
- vCreateBlockTimeTasks();\r
- vStartTimerDemoTask( mainTIMER_TEST_PERIOD );\r
- vStartDynamicPriorityTasks();\r
- vStartTaskNotifyTask();\r
-\r
- /* Create the register check tasks, as described at the top of this file.\r
- Use xTaskCreateStatic() to create a task using only statically allocated\r
- memory. */\r
- xTaskCreate( prvRegTestTaskEntry1, /* The function that implements the task. */\r
- "Reg1", /* The name of the task. */\r
- mainREG_TEST_STACK_SIZE_WORDS, /* Size of stack to allocate for the task - in words not bytes!. */\r
- mainREG_TEST_TASK_1_PARAMETER, /* Parameter passed into the task. */\r
- tskIDLE_PRIORITY, /* Priority of the task. */\r
- NULL ); /* Can be used to pass out a handle to the created task. */\r
- xTaskCreate( prvRegTestTaskEntry2, "Reg2", mainREG_TEST_STACK_SIZE_WORDS, mainREG_TEST_TASK_2_PARAMETER, tskIDLE_PRIORITY, NULL );\r
-\r
- /* Create the task that performs the 'check' functionality, as described at\r
- the top of this file. */\r
- xTaskCreate( prvCheckTask, "Check", mainCHECK_TASK_STACK_SIZE_WORDS, NULL, mainCHECK_TASK_PRIORITY, NULL );\r
-\r
- /* Start the scheduler. */\r
- vTaskStartScheduler();\r
-\r
- /* If all is well, the scheduler will now be running, and the following\r
- line will never be reached. If the following line does execute, then\r
- there was insufficient FreeRTOS heap memory available for the Idle and/or\r
- timer tasks to be created. See the memory management section on the\r
- FreeRTOS web site for more details on the FreeRTOS heap\r
- http://www.freertos.org/a00111.html. */\r
- for( ;; );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvCheckTask( void *pvParameters )\r
-{\r
-TickType_t xDelayPeriod = mainNO_ERROR_CHECK_TASK_PERIOD;\r
-TickType_t xLastExecutionTime;\r
-uint32_t ulLastRegTest1Value = 0, ulLastRegTest2Value = 0;\r
-char * const pcPassMessage = ".";\r
-char * pcStatusMessage = pcPassMessage;\r
-extern void vToggleLED( void );\r
-\r
- /* Just to stop compiler warnings. */\r
- ( void ) pvParameters;\r
-\r
- /* Initialise xLastExecutionTime so the first call to vTaskDelayUntil()\r
- works correctly. */\r
- xLastExecutionTime = xTaskGetTickCount();\r
-\r
- /* Cycle for ever, delaying then checking all the other tasks are still\r
- operating without error. The onboard LED is toggled on each iteration.\r
- If an error is detected then the delay period is decreased from\r
- mainNO_ERROR_CHECK_TASK_PERIOD to mainERROR_CHECK_TASK_PERIOD. This has the\r
- effect of increasing the rate at which the onboard LED toggles, and in so\r
- doing gives visual feedback of the system status. */\r
- for( ;; )\r
- {\r
- /* Delay until it is time to execute again. */\r
- vTaskDelayUntil( &xLastExecutionTime, xDelayPeriod );\r
-\r
- /* Check all the demo tasks (other than the flash tasks) to ensure\r
- that they are all still running, and that none have detected an error. */\r
- if( xAreDynamicPriorityTasksStillRunning() == pdFALSE )\r
- {\r
- pcStatusMessage = "ERROR: Dynamic priority demo/tests.\r\n";\r
- }\r
-\r
- if( xAreBlockTimeTestTasksStillRunning() == pdFALSE )\r
- {\r
- pcStatusMessage = "ERROR: Block time demo/tests.\r\n";\r
- }\r
-\r
- if( xAreTimerDemoTasksStillRunning( ( TickType_t ) xDelayPeriod ) == pdFALSE )\r
- {\r
- pcStatusMessage = "ERROR: Timer demo/tests.\r\n";\r
- }\r
-\r
- if( xAreTaskNotificationTasksStillRunning() == pdFALSE )\r
- {\r
- pcStatusMessage = "ERROR: Task notification demo/tests.\r\n";\r
- }\r
-\r
- /* Check that the register test 1 task is still running. */\r
- if( ulLastRegTest1Value == ulRegTest1LoopCounter )\r
- {\r
- pcStatusMessage = "ERROR: Register test 1.\r\n";\r
- }\r
- ulLastRegTest1Value = ulRegTest1LoopCounter;\r
-\r
- /* Check that the register test 2 task is still running. */\r
- if( ulLastRegTest2Value == ulRegTest2LoopCounter )\r
- {\r
- pcStatusMessage = "ERROR: Register test 2.\r\n";\r
- }\r
- ulLastRegTest2Value = ulRegTest2LoopCounter;\r
-\r
- /* Write the status message to the UART and toggle the LED to show the\r
- system status if the UART is not connected. */\r
- vToggleLED();\r
-\r
- /* If an error has been found then increase the LED toggle rate by\r
- increasing the cycle frequency. */\r
- if( pcStatusMessage != pcPassMessage )\r
- {\r
- xDelayPeriod = mainERROR_CHECK_TASK_PERIOD;\r
- }\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvRegTestTaskEntry1( void *pvParameters )\r
-{\r
- /* Although the regtest task is written in assembler, its entry point is\r
- written in C for convenience of checking the task parameter is being passed\r
- in correctly. */\r
- if( pvParameters == mainREG_TEST_TASK_1_PARAMETER )\r
- {\r
- /* Start the part of the test that is written in assembler. */\r
- vRegTest1Implementation();\r
- }\r
-\r
- /* The following line will only execute if the task parameter is found to\r
- be incorrect. The check task will detect that the regtest loop counter is\r
- not being incremented and flag an error. */\r
- vTaskDelete( NULL );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvRegTestTaskEntry2( void *pvParameters )\r
-{\r
- /* Although the regtest task is written in assembler, its entry point is\r
- written in C for convenience of checking the task parameter is being passed\r
- in correctly. */\r
- if( pvParameters == mainREG_TEST_TASK_2_PARAMETER )\r
- {\r
- /* Start the part of the test that is written in assembler. */\r
- vRegTest2Implementation();\r
- }\r
-\r
- /* The following line will only execute if the task parameter is found to\r
- be incorrect. The check task will detect that the regtest loop counter is\r
- not being incremented and flag an error. */\r
- vTaskDelete( NULL );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vFullDemoTickHook( void )\r
-{\r
- /* Called from vApplicationTickHook() when the project is configured to\r
- build the full test/demo applications. */\r
-\r
- /* Use task notifications from an interrupt. */\r
- xNotifyTaskFromISR();\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
+++ /dev/null
-/*\r
- * FreeRTOS Kernel V10.2.1\r
- * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
- * this software and associated documentation files (the "Software"), to deal in\r
- * the Software without restriction, including without limitation the rights to\r
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
- * the Software, and to permit persons to whom the Software is furnished to do so,\r
- * subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in all\r
- * copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- *\r
- * http://www.FreeRTOS.org\r
- * http://aws.amazon.com/freertos\r
- *\r
- * 1 tab == 4 spaces!\r
- */\r
-\r
-/******************************************************************************\r
- * This project provides two demo applications. A simple blinky style project,\r
- * and a more comprehensive test and demo application. The\r
- * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting (defined in this file) is used to\r
- * select between the two. The simply blinky demo is implemented and described\r
- * in main_blinky.c. The more comprehensive test and demo application is\r
- * implemented and described in main_full.c.\r
- *\r
- * This file implements the code that is not demo specific, including the\r
- * hardware setup and standard FreeRTOS hook functions.\r
- *\r
- * When running on the HiFive Rev B hardware:\r
- * When executing correctly the blue LED will toggle every three seconds. If\r
- * the blue LED toggles every 500ms then one of the self-monitoring test tasks\r
- * discovered a potential issue. If the red led toggles rapidly then a hardware\r
- * exception occurred.\r
- *\r
- * ENSURE TO READ THE DOCUMENTATION PAGE FOR THIS PORT AND DEMO APPLICATION ON\r
- * THE http://www.FreeRTOS.org WEB SITE FOR FULL INFORMATION ON USING THIS DEMO\r
- * APPLICATION, AND ITS ASSOCIATE FreeRTOS ARCHITECTURE PORT!\r
- *\r
- */\r
-\r
-/* FreeRTOS kernel includes. */\r
-#include <FreeRTOS.h>\r
-#include <task.h>\r
-\r
-/* Freedom metal driver includes. */\r
-#include <metal/cpu.h>\r
-#include <metal/led.h>\r
-\r
-/* Set mainCREATE_SIMPLE_BLINKY_DEMO_ONLY to one to run the simple blinky demo,\r
-or 0 to run the more comprehensive test and demo application. */\r
-#define mainCREATE_SIMPLE_BLINKY_DEMO_ONLY 0\r
-\r
-/* Index to first HART (there is only one). */\r
-#define mainHART_0 0\r
-\r
-/* Registers used to initialise the PLIC. */\r
-#define mainPLIC_PENDING_0 ( * ( ( volatile uint32_t * ) 0x0C001000UL ) )\r
-#define mainPLIC_PENDING_1 ( * ( ( volatile uint32_t * ) 0x0C001004UL ) )\r
-#define mainPLIC_ENABLE_0 ( * ( ( volatile uint32_t * ) 0x0C002000UL ) )\r
-#define mainPLIC_ENABLE_1 ( * ( ( volatile uint32_t * ) 0x0C002004UL ) )\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * main_blinky() is used when mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set to 1.\r
- * main_full() is used when mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set to 0.\r
- */\r
-#if mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 1\r
- extern void main_blinky( void );\r
-#else\r
- extern void main_full( void );\r
-#endif /* #if mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 1 */\r
-\r
-/*\r
- * Prototypes for the standard FreeRTOS callback/hook functions implemented\r
- * within this file. See https://www.freertos.org/a00016.html\r
- */\r
-void vApplicationMallocFailedHook( void );\r
-void vApplicationIdleHook( void );\r
-void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName );\r
-void vApplicationTickHook( void );\r
-\r
-/*\r
- * Setup the hardware to run this demo.\r
- */\r
-static void prvSetupHardware( void );\r
-\r
-/*\r
- * Used by the Freedom Metal drivers.\r
- */\r
-static struct metal_led *pxBlueLED = NULL;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-int main( void )\r
-{\r
- prvSetupHardware();\r
-\r
- /* The mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting is described at the top\r
- of this file. */\r
- #if( mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 1 )\r
- {\r
- main_blinky();\r
- }\r
- #else\r
- {\r
- main_full();\r
- }\r
- #endif\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvSetupHardware( void )\r
-{\r
-struct metal_cpu *pxCPU;\r
-struct metal_interrupt *pxInterruptController;\r
-\r
- /* Initialise the blue LED. */\r
- pxBlueLED = metal_led_get_rgb( "LD0", "blue" );\r
- configASSERT( pxBlueLED );\r
- metal_led_enable( pxBlueLED );\r
- metal_led_off( pxBlueLED );\r
-\r
- /* Initialise the interrupt controller. */\r
- pxCPU = metal_cpu_get( mainHART_0 );\r
- configASSERT( pxCPU );\r
- pxInterruptController = metal_cpu_interrupt_controller( pxCPU );\r
- configASSERT( pxInterruptController );\r
- metal_interrupt_init( pxInterruptController );\r
-\r
- /* Set all interrupt enable bits to 0. */\r
- mainPLIC_ENABLE_0 = 0UL;\r
- mainPLIC_ENABLE_1 = 0UL;\r
-\r
- /* Clear all pending interrupts. */\r
- mainPLIC_PENDING_0 = 0UL;\r
- mainPLIC_PENDING_1 = 0UL;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vApplicationMallocFailedHook( void )\r
-{\r
- /* vApplicationMallocFailedHook() will only be called if\r
- configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook\r
- function that will get called if a call to pvPortMalloc() fails.\r
- pvPortMalloc() is called internally by the kernel whenever a task, queue,\r
- timer or semaphore is created. It is also called by various parts of the\r
- demo application. If heap_1.c or heap_2.c are used, then the size of the\r
- heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in\r
- FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used\r
- to query the size of free heap space that remains (although it does not\r
- provide information on how the remaining heap might be fragmented). */\r
- taskDISABLE_INTERRUPTS();\r
- for( ;; );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vApplicationIdleHook( void )\r
-{\r
- /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set\r
- to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle\r
- task. It is essential that code added to this hook function never attempts\r
- to block in any way (for example, call xQueueReceive() with a block time\r
- specified, or call vTaskDelay()). If the application makes use of the\r
- vTaskDelete() API function (as this demo application does) then it is also\r
- important that vApplicationIdleHook() is permitted to return to its calling\r
- function, because it is the responsibility of the idle task to clean up\r
- memory allocated by the kernel to any task that has since been deleted. */\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )\r
-{\r
- ( void ) pcTaskName;\r
- ( void ) pxTask;\r
-\r
- /* Run time stack overflow checking is performed if\r
- configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook\r
- function is called if a stack overflow is detected. */\r
- taskDISABLE_INTERRUPTS();\r
- for( ;; );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vApplicationTickHook( void )\r
-{\r
- /* The tests in the full demo expect some interaction with interrupts. */\r
- #if( mainCREATE_SIMPLE_BLINKY_DEMO_ONLY != 1 )\r
- {\r
- extern void vFullDemoTickHook( void );\r
- vFullDemoTickHook();\r
- }\r
- #endif\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vAssertCalled( void )\r
-{\r
-static struct metal_led *pxRedLED = NULL;\r
-volatile uint32_t ul;\r
-const uint32_t ulNullLoopDelay = 0x1ffffUL;\r
-\r
- taskDISABLE_INTERRUPTS();\r
-\r
- /* Initialise the red LED. */\r
- pxRedLED = metal_led_get_rgb( "LD0", "red" );\r
- configASSERT( pxRedLED );\r
- metal_led_enable( pxRedLED );\r
- metal_led_off( pxRedLED );\r
-\r
- /* Flash the red LED to indicate that assert was hit - interrupts are off\r
- here to prevent any further tick interrupts or context switches, so the\r
- delay is implemented as a crude loop instead of a peripheral timer. */\r
- for( ;; )\r
- {\r
- for( ul = 0; ul < ulNullLoopDelay; ul++ )\r
- {\r
- __asm volatile( "nop" );\r
- }\r
- metal_led_toggle( pxRedLED );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void handle_trap( void )\r
-{\r
-volatile uint32_t ulMEPC = 0UL, ulMCAUSE = 0UL, ulPLICPending0Register = 0UL, ulPLICPending1Register = 0UL;\r
-\r
- /* Store a few register values that might be useful when determining why this\r
- function was called. */\r
- __asm volatile( "csrr %0, mepc" : "=r"( ulMEPC ) );\r
- __asm volatile( "csrr %0, mcause" : "=r"( ulMCAUSE ) );\r
- ulPLICPending0Register = mainPLIC_PENDING_0;\r
- ulPLICPending1Register = mainPLIC_PENDING_1;\r
-\r
- /* Prevent compiler warnings about unused variables. */\r
- ( void ) ulPLICPending0Register;\r
- ( void ) ulPLICPending1Register;\r
-\r
- /* Force an assert as this function has not been implemented as the demo\r
- does not use external interrupts. */\r
- configASSERT( metal_cpu_get( mainHART_0 ) == 0x00 );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vToggleLED( void )\r
-{\r
- metal_led_toggle( pxBlueLED );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void *malloc( size_t xSize )\r
-{\r
- /* The linker script does not define a heap so artificially force an assert()\r
- if something unexpectedly uses the C library heap. See\r
- https://www.freertos.org/a00111.html for more information. */\r
- configASSERT( metal_cpu_get( mainHART_0 ) == 0x00 );\r
-\r
- /* Remove warnings about unused parameter. */\r
- ( void ) xSize;\r
- return NULL;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-\r