Compare commits

..

No commits in common. "main" and "msvc_compat" have entirely different histories.

107 changed files with 24116 additions and 27817 deletions

View File

@ -1,3 +1,4 @@
---
Language: Cpp Language: Cpp
# BasedOnStyle: LLVM # BasedOnStyle: LLVM
# should be in line with IndentWidth # should be in line with IndentWidth
@ -12,8 +13,8 @@ AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: false AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false AlwaysBreakBeforeMultilineStrings: false
@ -38,8 +39,8 @@ BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: true BreakConstructorInitializersBeforeComma: true
BreakAfterJavaFieldAnnotations: false BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true BreakStringLiterals: true
ColumnLimit: 140 ColumnLimit: 120
CommentPragmas: '^( IWYU pragma:| @suppress)' CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 0 ConstructorInitializerIndentWidth: 0
ContinuationIndentWidth: 4 ContinuationIndentWidth: 4
@ -75,13 +76,13 @@ PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000 PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000 PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60 PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left PointerAlignment: Right
ReflowComments: true ReflowComments: true
SortIncludes: true SortIncludes: true
SpaceAfterCStyleCast: false SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: Never SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1 SpacesBeforeTrailingComments: 1
SpacesInAngles: false SpacesInAngles: false

5
.gitignore vendored
View File

@ -1,6 +1,5 @@
.DS_Store .DS_Store
/*.il /*.il
/.settings
/avr-instr.html /avr-instr.html
/blink.S /blink.S
/flash.* /flash.*
@ -15,6 +14,7 @@
/*.ods /*.ods
/build*/ /build*/
/*.logs /*.logs
language.settings.xml
/*.gtkw /*.gtkw
/Debug wo LLVM/ /Debug wo LLVM/
/*.txdb /*.txdb
@ -30,5 +30,4 @@
/.gdbinit /.gdbinit
/*.out /*.out
/dump.json /dump.json
/*.yaml /src-gen/
/*.json

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "gen_input/CoreDSL-Instruction-Set-Description"]
path = gen_input/CoreDSL-Instruction-Set-Description
url = ../CoreDSL-Instruction-Set-Description.git

View File

@ -23,5 +23,6 @@
<nature>org.eclipse.cdt.core.ccnature</nature> <nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature> <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
<nature>org.eclipse.linuxtools.tmf.project.nature</nature>
</natures> </natures>
</projectDescription> </projectDescription>

View File

@ -0,0 +1,73 @@
eclipse.preferences.version=1
org.eclipse.cdt.codan.checkers.errnoreturn=Warning
org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No return\\")",implicit\=>false}
org.eclipse.cdt.codan.checkers.errreturnvalue=Error
org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused return value\\")"}
org.eclipse.cdt.codan.checkers.nocommentinside=-Error
org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Nesting comments\\")"}
org.eclipse.cdt.codan.checkers.nolinecomment=-Error
org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Line comments\\")"}
org.eclipse.cdt.codan.checkers.noreturn=Error
org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No return value\\")",implicit\=>false}
org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error
org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Abstract class cannot be instantiated\\")"}
org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error
org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Ambiguous problem\\")"}
org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning
org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Assignment in condition\\")"}
org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error
org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Assignment to itself\\")"}
org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning
org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No break at end of case\\")",no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false,enable_fallthrough_quickfix_param\=>false}
org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning
org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Catching by reference is recommended\\")",unknown\=>false,exceptions\=>()}
org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error
org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Circular inheritance\\")"}
org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning
org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Class members should be properly initialized\\")",skip\=>true}
org.eclipse.cdt.codan.internal.checkers.DecltypeAutoProblem=Error
org.eclipse.cdt.codan.internal.checkers.DecltypeAutoProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid 'decltype(auto)' specifier\\")"}
org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error
org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Field cannot be resolved\\")"}
org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error
org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Function cannot be resolved\\")"}
org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error
org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid arguments\\")"}
org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error
org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid template argument\\")"}
org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error
org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Label statement not found\\")"}
org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error
org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Member declaration not found\\")"}
org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error
org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Method cannot be resolved\\")"}
org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info
org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Name convention for function\\")",pattern\=>"^[a-z]",macro\=>true,exceptions\=>()}
org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning
org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Class has a virtual method and non-virtual destructor\\")"}
org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error
org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid overload\\")"}
org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error
org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid redeclaration\\")"}
org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error
org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid redefinition\\")"}
org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning
org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Return with parenthesis\\")"}
org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning
org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Format String Vulnerability\\")"}
org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning
org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Statement has no effect\\")",macro\=>true,exceptions\=>()}
org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning
org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Suggested parenthesis around expression\\")",paramNot\=>false}
org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning
org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Suspicious semicolon\\")",else\=>false,afterelse\=>false}
org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error
org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Type cannot be resolved\\")"}
org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning
org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused function declaration\\")",macro\=>true}
org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning
org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused static function\\")",macro\=>true}
org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning
org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused variable declaration in file scope\\")",macro\=>true,exceptions\=>("@(\#)","$Id")}
org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error
org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Symbol is not resolved\\")"}

View File

@ -0,0 +1,13 @@
eclipse.preferences.version=1
environment/project/cdt.managedbuild.config.gnu.exe.debug.1751741082/append=true
environment/project/cdt.managedbuild.config.gnu.exe.debug.1751741082/appendContributed=true
environment/project/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/LLVM_HOME/delimiter=\:
environment/project/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/LLVM_HOME/operation=append
environment/project/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/LLVM_HOME/value=/usr/lib/llvm-6.0
environment/project/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/append=true
environment/project/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/appendContributed=true
environment/project/cdt.managedbuild.config.gnu.exe.release.1745230171/LLVM_HOME/delimiter=\:
environment/project/cdt.managedbuild.config.gnu.exe.release.1745230171/LLVM_HOME/operation=append
environment/project/cdt.managedbuild.config.gnu.exe.release.1745230171/LLVM_HOME/value=/usr/lib/llvm-6.0
environment/project/cdt.managedbuild.config.gnu.exe.release.1745230171/append=true
environment/project/cdt.managedbuild.config.gnu.exe.release.1745230171/appendContributed=true

View File

@ -0,0 +1,37 @@
eclipse.preferences.version=1
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1751741082/CPATH/delimiter=\:
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1751741082/CPATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1751741082/CPLUS_INCLUDE_PATH/delimiter=\:
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1751741082/CPLUS_INCLUDE_PATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1751741082/C_INCLUDE_PATH/delimiter=\:
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1751741082/C_INCLUDE_PATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1751741082/append=true
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1751741082/appendContributed=true
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/CPATH/delimiter=\:
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/CPATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/CPLUS_INCLUDE_PATH/delimiter=\:
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/CPLUS_INCLUDE_PATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/C_INCLUDE_PATH/delimiter=\:
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/C_INCLUDE_PATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/append=true
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/appendContributed=true
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171/CPATH/delimiter=\:
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171/CPATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171/CPLUS_INCLUDE_PATH/delimiter=\:
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171/CPLUS_INCLUDE_PATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171/C_INCLUDE_PATH/delimiter=\:
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171/C_INCLUDE_PATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171/append=true
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.release.1745230171/appendContributed=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.debug.1751741082/LIBRARY_PATH/delimiter=\:
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.debug.1751741082/LIBRARY_PATH/operation=remove
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.debug.1751741082/append=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.debug.1751741082/appendContributed=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/LIBRARY_PATH/delimiter=\:
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/LIBRARY_PATH/operation=remove
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/append=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.release.1745230171.1259602404/appendContributed=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.release.1745230171/LIBRARY_PATH/delimiter=\:
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.release.1745230171/LIBRARY_PATH/operation=remove
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.release.1745230171/append=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.release.1745230171/appendContributed=true

View File

@ -1,263 +1,169 @@
cmake_minimum_required(VERSION 3.18) cmake_minimum_required(VERSION 3.12)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) ###############################################################################
# ##############################################################################
# #
# ############################################################################## ###############################################################################
project(dbt-rise-tgc VERSION 1.0.0) project(dbt-rise-tgc VERSION 1.0.0)
include(GNUInstallDirs) include(GNUInstallDirs)
include(flink)
find_package(elfio QUIET) find_package(elfio)
find_package(jsoncpp)
find_package(Boost COMPONENTS coroutine REQUIRED) if(WITH_LLVM)
if(DEFINED ENV{LLVM_HOME})
find_path (LLVM_DIR LLVM-Config.cmake $ENV{LLVM_HOME}/lib/cmake/llvm)
endif(DEFINED ENV{LLVM_HOME})
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
llvm_map_components_to_libnames(llvm_libs support core mcjit x86codegen x86asmparser)
endif()
#Mac needed variables (adapt for your needs - http://www.cmake.org/Wiki/CMake_RPATH_handling#Mac_OS_X_and_the_RPATH)
#set(CMAKE_MACOSX_RPATH ON)
#set(CMAKE_SKIP_BUILD_RPATH FALSE)
#set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
#set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
#set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
add_subdirectory(softfloat) add_subdirectory(softfloat)
set(LIB_SOURCES # library files
src/iss/plugin/instruction_count.cpp FILE(GLOB TGC_SOURCES
src/iss/arch/tgc5c.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/iss/*.cpp
src/vm/interp/vm_tgc5c.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/vm/interp/vm_*.cpp
)
set(LIB_SOURCES
src/vm/fp_functions.cpp src/vm/fp_functions.cpp
src/iss/semihosting/semihosting.cpp src/plugin/instruction_count.cpp
src/plugin/cycle_estimate.cpp
${TGC_SOURCES}
) )
if(WITH_TCC)
list(APPEND LIB_SOURCES
src/vm/tcc/vm_tgc5c.cpp
)
endif()
if(WITH_LLVM) if(WITH_LLVM)
list(APPEND LIB_SOURCES set(LIB_SOURCES ${LIB_SOURCES}
src/vm/llvm/vm_tgc5c.cpp src/vm/llvm/fp_impl.cpp
src/vm/llvm/fp_impl.cpp #src/vm/llvm/vm_tgf_b.cpp
) #src/vm/llvm/vm_tgf_c.cpp
endif() )
if(WITH_ASMJIT)
list(APPEND LIB_SOURCES
src/vm/asmjit/vm_tgc5c.cpp
)
endif()
# library files
FILE(GLOB GEN_ISS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp)
FILE(GLOB GEN_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp)
FILE(GLOB GEN_YAML_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/contrib/instr/*.yaml)
list(APPEND LIB_SOURCES ${GEN_ISS_SOURCES} ${GEN_VM_SOURCES})
foreach(FILEPATH ${GEN_ISS_SOURCES})
get_filename_component(CORE ${FILEPATH} NAME_WE)
string(TOUPPER ${CORE} CORE)
list(APPEND LIB_DEFINES CORE_${CORE})
endforeach()
message(STATUS "Core defines are ${LIB_DEFINES}")
if(WITH_LLVM)
FILE(GLOB LLVM_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/llvm/vm_*.cpp)
list(APPEND LIB_SOURCES ${LLVM_GEN_SOURCES})
endif()
if(WITH_TCC)
FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/tcc/vm_*.cpp)
list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
endif()
if(WITH_ASMJIT)
FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/asmjit/vm_*.cpp)
list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
endif()
if(TARGET yaml-cpp::yaml-cpp)
list(APPEND LIB_SOURCES
src/iss/plugin/cycle_estimate.cpp
src/iss/plugin/instruction_count.cpp
)
endif() endif()
# Define the library # Define the library
add_library(${PROJECT_NAME} SHARED ${LIB_SOURCES}) add_library(${PROJECT_NAME} ${LIB_SOURCES})
# list code gen dependencies
if(TARGET ${CORE_NAME}_cpp)
add_dependencies(${PROJECT_NAME} ${CORE_NAME}_cpp)
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-shift-count-overflow) target_compile_options(${PROJECT_NAME} PRIVATE -Wno-shift-count-overflow)
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
target_compile_options(${PROJECT_NAME} PRIVATE /wd4293) target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
endif() endif()
target_include_directories(${PROJECT_NAME} PUBLIC incl)
target_include_directories(${PROJECT_NAME} PUBLIC src) target_link_libraries(${PROJECT_NAME} PUBLIC softfloat scc-util jsoncpp)
target_include_directories(${PROJECT_NAME} PUBLIC src-gen) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-core -Wl,--no-whole-archive)
target_force_link_libraries(${PROJECT_NAME} PRIVATE dbt-rise-core) else()
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-core)
# only re-export the include paths
get_target_property(DBT_CORE_INCL dbt-rise-core INTERFACE_INCLUDE_DIRECTORIES)
target_include_directories(${PROJECT_NAME} INTERFACE ${DBT_CORE_INCL})
get_target_property(DBT_CORE_DEFS dbt-rise-core INTERFACE_COMPILE_DEFINITIONS)
if(NOT(DBT_CORE_DEFS STREQUAL DBT_CORE_DEFS-NOTFOUND))
target_compile_definitions(${PROJECT_NAME} INTERFACE ${DBT_CORE_DEFS})
endif() endif()
if(TARGET CONAN_PKG::elfio)
target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio softfloat scc-util Boost::coroutine) target_link_libraries(${PROJECT_NAME} PUBLIC CONAN_PKG::elfio)
elseif(TARGET elfio::elfio)
if(TARGET yaml-cpp::yaml-cpp) target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio)
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_PLUGINS) else()
target_link_libraries(${PROJECT_NAME} PUBLIC yaml-cpp::yaml-cpp) message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
endif()
if(WITH_LLVM)
find_package(LLVM)
target_compile_definitions(${PROJECT_NAME} PUBLIC ${LLVM_DEFINITIONS})
target_include_directories(${PROJECT_NAME} PUBLIC ${LLVM_INCLUDE_DIRS})
if(BUILD_SHARED_LIBS)
target_link_libraries(${PROJECT_NAME} PUBLIC ${LLVM_LIBRARIES})
endif()
endif() endif()
set_target_properties(${PROJECT_NAME} PROPERTIES set_target_properties(${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
FRAMEWORK FALSE FRAMEWORK FALSE
) )
install(TARGETS ${PROJECT_NAME} COMPONENT ${PROJECT_NAME} install(TARGETS ${PROJECT_NAME} COMPONENT ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Targets # for downstream dependencies EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared lib LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared lib
FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # for mac FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # for mac
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} # headers for mac (note the different component -> different package) PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} # headers for mac (note the different component -> different package)
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers
) )
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss COMPONENT ${PROJECT_NAME} install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss COMPONENT ${PROJECT_NAME}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # target directory DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # target directory
FILES_MATCHING # install only matched files FILES_MATCHING # install only matched files
PATTERN "*.h" # select header files PATTERN "*.h" # select header files
) )
install(FILES ${GEN_YAML_SOURCES} DESTINATION share/tgc-vp) ###############################################################################
# ##############################################################################
# #
# ############################################################################## ###############################################################################
set(CMAKE_INSTALL_RPATH $ORIGIN/../${CMAKE_INSTALL_LIBDIR})
project(tgc-sim) project(tgc-sim)
find_package(Boost COMPONENTS program_options thread REQUIRED) find_package(Boost COMPONENTS program_options thread REQUIRED)
add_executable(${PROJECT_NAME} src/main.cpp) add_executable(${PROJECT_NAME} src/main.cpp)
# This sets the include directory for the reference project. This is the -I flag in gcc.
if(TARGET ${CORE_NAME}_cpp) target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
list(APPEND TGC_SOURCES ${${CORE_NAME}_OUTPUT_FILES}) if(WITH_LLVM)
else() target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
FILE(GLOB TGC_SOURCES target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp
)
list(APPEND TGC_SOURCES ${GEN_SOURCES})
endif() endif()
# Links the target exe against the libraries
foreach(F IN LISTS TGC_SOURCES) target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc)
if(${F} MATCHES ".*/arch/([^/]*)\.cpp")
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
endif()
endforeach()
# if(WITH_LLVM)
# target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
# #target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
# endif()
# if(WITH_TCC)
# target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC)
# endif()
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc fmt::fmt)
if(TARGET Boost::program_options) if(TARGET Boost::program_options)
target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options) target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options Boost::thread)
else() else()
target_link_libraries(${PROJECT_NAME} PUBLIC ${BOOST_program_options_LIBRARY}) target_link_libraries(${PROJECT_NAME} PUBLIC ${BOOST_program_options_LIBRARY} ${BOOST_thread_LIBRARY})
endif() endif()
target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_DL_LIBS}) target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_DL_LIBS})
if (Tcmalloc_FOUND)
if(Tcmalloc_FOUND)
target_link_libraries(${PROJECT_NAME} PUBLIC ${Tcmalloc_LIBRARIES}) target_link_libraries(${PROJECT_NAME} PUBLIC ${Tcmalloc_LIBRARIES})
endif(Tcmalloc_FOUND) endif(Tcmalloc_FOUND)
install(TARGETS tgc-sim install(TARGETS tgc-sim
EXPORT ${PROJECT_NAME}Targets # for downstream dependencies EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared lib LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared lib
FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # for mac FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # for mac
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} # headers for mac (note the different component -> different package) PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} # headers for mac (note the different component -> different package)
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers
) )
###############################################################################
if(BUILD_TESTING)
# ... CMake code to create tests ...
add_test(NAME tgc-sim-interp
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend interp)
if(WITH_TCC)
add_test(NAME tgc-sim-tcc
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend tcc)
endif()
if(WITH_LLVM)
add_test(NAME tgc-sim-llvm
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend llvm)
endif()
if(WITH_ASMJIT)
add_test(NAME tgc-sim-asmjit
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend asmjit)
endif()
endif()
# ##############################################################################
# #
# ############################################################################## ###############################################################################
if(TARGET scc-sysc) project(dbt-rise-tgc_sc VERSION 1.0.0)
project(dbt-rise-tgc_sc VERSION 1.0.0)
set(LIB_SOURCES include(SystemCPackage)
src/sysc/core_complex.cpp if(SystemC_FOUND)
src/sysc/register_tgc_c.cpp add_library(${PROJECT_NAME} src/sysc/core_complex.cpp)
)
FILE(GLOB GEN_SC_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/sysc/register_*.cpp)
list(APPEND LIB_SOURCES ${GEN_SC_SOURCES})
add_library(${PROJECT_NAME} ${LIB_SOURCES})
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC) target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME}) target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_b.h)
foreach(F IN LISTS TGC_SOURCES) target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_B)
if(${F} MATCHES ".*/arch/([^/]*)\.cpp") endif()
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F}) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_c.h)
string(TOUPPER ${CORE_NAME_LC} CORE_NAME) target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_C)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME}) endif()
endif() if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_d.h)
endforeach() target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_D)
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc) target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc)
if(WITH_LLVM)
# if(WITH_LLVM) target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
# target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs}) endif()
# endif()
set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h) set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/core_complex.h)
set_target_properties(${PROJECT_NAME} PROPERTIES set_target_properties(${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
FRAMEWORK FALSE FRAMEWORK FALSE
PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers
) )
install(TARGETS ${PROJECT_NAME} COMPONENT ${PROJECT_NAME} install(TARGETS ${PROJECT_NAME} COMPONENT ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Targets # for downstream dependencies EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared lib LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared lib
FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # for mac FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # for mac
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sysc # headers for mac (note the different component -> different package) PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sysc # headers for mac (note the different component -> different package)
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers
) )
endif() endif()

View File

@ -1,35 +0,0 @@
# according to https://github.com/horance-liu/flink.cmake/tree/master
# SPDX-License-Identifier: Apache-2.0
include(CMakeParseArguments)
function(target_do_force_link_libraries target visibility lib)
if(MSVC)
target_link_libraries(${target} ${visibility} "/WHOLEARCHIVE:${lib}")
elseif(APPLE)
target_link_libraries(${target} ${visibility} -Wl,-force_load ${lib})
else()
target_link_libraries(${target} ${visibility} -Wl,--whole-archive ${lib} -Wl,--no-whole-archive)
endif()
endfunction()
function(target_force_link_libraries target)
cmake_parse_arguments(FLINK
""
""
"PUBLIC;INTERFACE;PRIVATE"
${ARGN}
)
foreach(lib IN LISTS FLINK_PUBLIC)
target_do_force_link_libraries(${target} PUBLIC ${lib})
endforeach()
foreach(lib IN LISTS FLINK_INTERFACE)
target_do_force_link_libraries(${target} INTERFACE ${lib})
endforeach()
foreach(lib IN LISTS FLINK_PRIVATE)
target_do_force_link_libraries(${target} PRIVATE ${lib})
endforeach()
endfunction()

View File

@ -16,7 +16,7 @@ namespace eval Specification {
set libdir "${install_dir}/lib64" set libdir "${install_dir}/lib64"
set preprocessorOptions [concat $preprocessorOptions "-I${incldir}"] set preprocessorOptions [concat $preprocessorOptions "-I${incldir}"]
# Set the Linker paths. # Set the Linker paths.
set linkerOptions [concat $linkerOptions "-Wl,-rpath,${libdir} -L${libdir} -ldbt-rise-tgc_sc -lscc-sysc"] set linkerOptions [concat $linkerOptions "-Wl,-rpath,${libdir} -L${libdir} -ldbt-rise-tgc_sc"]
} }
default { default {
puts stderr "ERROR: \"$target\" is not supported, [::scsh::version]" puts stderr "ERROR: \"$target\" is not supported, [::scsh::version]"

View File

@ -1 +0,0 @@
/*.yaml

View File

@ -1,624 +0,0 @@
RVI:
LUI:
index: 0
encoding: 0b00000000000000000000000000110111
mask: 0b00000000000000000000000001111111
size: 32
branch: false
delay: 1
AUIPC:
index: 1
encoding: 0b00000000000000000000000000010111
mask: 0b00000000000000000000000001111111
size: 32
branch: false
delay: 1
JAL:
index: 2
encoding: 0b00000000000000000000000001101111
mask: 0b00000000000000000000000001111111
size: 32
branch: true
delay: 1
JALR:
index: 3
encoding: 0b00000000000000000000000001100111
mask: 0b00000000000000000111000001111111
size: 32
branch: true
delay: [1,1]
BEQ:
index: 4
encoding: 0b00000000000000000000000001100011
mask: 0b00000000000000000111000001111111
size: 32
branch: true
delay: [1,1]
BNE:
index: 5
encoding: 0b00000000000000000001000001100011
mask: 0b00000000000000000111000001111111
size: 32
branch: true
delay: [1,1]
BLT:
index: 6
encoding: 0b00000000000000000100000001100011
mask: 0b00000000000000000111000001111111
size: 32
branch: true
delay: [1,1]
BGE:
index: 7
encoding: 0b00000000000000000101000001100011
mask: 0b00000000000000000111000001111111
size: 32
branch: true
delay: [1,1]
BLTU:
index: 8
encoding: 0b00000000000000000110000001100011
mask: 0b00000000000000000111000001111111
size: 32
branch: true
delay: [1,1]
BGEU:
index: 9
encoding: 0b00000000000000000111000001100011
mask: 0b00000000000000000111000001111111
size: 32
branch: true
delay: [1,1]
LB:
index: 10
encoding: 0b00000000000000000000000000000011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
LH:
index: 11
encoding: 0b00000000000000000001000000000011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
LW:
index: 12
encoding: 0b00000000000000000010000000000011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
LBU:
index: 13
encoding: 0b00000000000000000100000000000011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
LHU:
index: 14
encoding: 0b00000000000000000101000000000011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
SB:
index: 15
encoding: 0b00000000000000000000000000100011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
SH:
index: 16
encoding: 0b00000000000000000001000000100011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
SW:
index: 17
encoding: 0b00000000000000000010000000100011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
ADDI:
index: 18
encoding: 0b00000000000000000000000000010011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
SLTI:
index: 19
encoding: 0b00000000000000000010000000010011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
SLTIU:
index: 20
encoding: 0b00000000000000000011000000010011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
XORI:
index: 21
encoding: 0b00000000000000000100000000010011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
ORI:
index: 22
encoding: 0b00000000000000000110000000010011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
ANDI:
index: 23
encoding: 0b00000000000000000111000000010011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
SLLI:
index: 24
encoding: 0b00000000000000000001000000010011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
SRLI:
index: 25
encoding: 0b00000000000000000101000000010011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
SRAI:
index: 26
encoding: 0b01000000000000000101000000010011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
ADD:
index: 27
encoding: 0b00000000000000000000000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
SUB:
index: 28
encoding: 0b01000000000000000000000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
SLL:
index: 29
encoding: 0b00000000000000000001000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
SLT:
index: 30
encoding: 0b00000000000000000010000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
SLTU:
index: 31
encoding: 0b00000000000000000011000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
XOR:
index: 32
encoding: 0b00000000000000000100000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
SRL:
index: 33
encoding: 0b00000000000000000101000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
SRA:
index: 34
encoding: 0b01000000000000000101000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
OR:
index: 35
encoding: 0b00000000000000000110000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
AND:
index: 36
encoding: 0b00000000000000000111000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
FENCE:
index: 37
encoding: 0b00000000000000000000000000001111
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
ECALL:
index: 38
encoding: 0b00000000000000000000000001110011
mask: 0b11111111111111111111111111111111
attributes: [[name:no_cont]]
size: 32
branch: false
delay: 1
EBREAK:
index: 39
encoding: 0b00000000000100000000000001110011
mask: 0b11111111111111111111111111111111
attributes: [[name:no_cont]]
size: 32
branch: false
delay: 1
MRET:
index: 40
encoding: 0b00110000001000000000000001110011
mask: 0b11111111111111111111111111111111
attributes: [[name:no_cont]]
size: 32
branch: false
delay: 1
WFI:
index: 41
encoding: 0b00010000010100000000000001110011
mask: 0b11111111111111111111111111111111
size: 32
branch: false
delay: 1
Zicsr:
CSRRW:
index: 42
encoding: 0b00000000000000000001000001110011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
CSRRS:
index: 43
encoding: 0b00000000000000000010000001110011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
CSRRC:
index: 44
encoding: 0b00000000000000000011000001110011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
CSRRWI:
index: 45
encoding: 0b00000000000000000101000001110011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
CSRRSI:
index: 46
encoding: 0b00000000000000000110000001110011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
CSRRCI:
index: 47
encoding: 0b00000000000000000111000001110011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
Zifencei:
FENCE_I:
index: 48
encoding: 0b00000000000000000001000000001111
mask: 0b00000000000000000111000001111111
attributes: [[name:flush]]
size: 32
branch: false
delay: 1
RVM:
MUL:
index: 49
encoding: 0b00000010000000000000000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
MULH:
index: 50
encoding: 0b00000010000000000001000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
MULHSU:
index: 51
encoding: 0b00000010000000000010000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
MULHU:
index: 52
encoding: 0b00000010000000000011000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
DIV:
index: 53
encoding: 0b00000010000000000100000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
DIVU:
index: 54
encoding: 0b00000010000000000101000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
REM:
index: 55
encoding: 0b00000010000000000110000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
REMU:
index: 56
encoding: 0b00000010000000000111000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
Zca:
C__ADDI4SPN:
index: 57
encoding: 0b0000000000000000
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
C__LW:
index: 58
encoding: 0b0100000000000000
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
C__SW:
index: 59
encoding: 0b1100000000000000
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
C__ADDI:
index: 60
encoding: 0b0000000000000001
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
C__NOP:
index: 61
encoding: 0b0000000000000001
mask: 0b1110111110000011
size: 16
branch: false
delay: 1
C__JAL:
index: 62
encoding: 0b0010000000000001
mask: 0b1110000000000011
attributes: [[name:enable, value:1]]
size: 16
branch: true
delay: 1
C__LI:
index: 63
encoding: 0b0100000000000001
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
C__LUI:
index: 64
encoding: 0b0110000000000001
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
C__ADDI16SP:
index: 65
encoding: 0b0110000100000001
mask: 0b1110111110000011
size: 16
branch: false
delay: 1
__reserved_clui:
index: 66
encoding: 0b0110000000000001
mask: 0b1111000001111111
size: 16
branch: false
delay: 1
C__SRLI:
index: 67
encoding: 0b1000000000000001
mask: 0b1111110000000011
attributes: [[name:enable, value:1]]
size: 16
branch: false
delay: 1
C__SRAI:
index: 68
encoding: 0b1000010000000001
mask: 0b1111110000000011
attributes: [[name:enable, value:1]]
size: 16
branch: false
delay: 1
C__ANDI:
index: 69
encoding: 0b1000100000000001
mask: 0b1110110000000011
size: 16
branch: false
delay: 1
C__SUB:
index: 70
encoding: 0b1000110000000001
mask: 0b1111110001100011
size: 16
branch: false
delay: 1
C__XOR:
index: 71
encoding: 0b1000110000100001
mask: 0b1111110001100011
size: 16
branch: false
delay: 1
C__OR:
index: 72
encoding: 0b1000110001000001
mask: 0b1111110001100011
size: 16
branch: false
delay: 1
C__AND:
index: 73
encoding: 0b1000110001100001
mask: 0b1111110001100011
size: 16
branch: false
delay: 1
C__J:
index: 74
encoding: 0b1010000000000001
mask: 0b1110000000000011
size: 16
branch: true
delay: 1
C__BEQZ:
index: 75
encoding: 0b1100000000000001
mask: 0b1110000000000011
size: 16
branch: true
delay: [1,1]
C__BNEZ:
index: 76
encoding: 0b1110000000000001
mask: 0b1110000000000011
size: 16
branch: true
delay: [1,1]
C__SLLI:
index: 77
encoding: 0b0000000000000010
mask: 0b1111000000000011
attributes: [[name:enable, value:1]]
size: 16
branch: false
delay: 1
C__LWSP:
index: 78
encoding: 0b0100000000000010
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
C__MV:
index: 79
encoding: 0b1000000000000010
mask: 0b1111000000000011
size: 16
branch: false
delay: 1
C__JR:
index: 80
encoding: 0b1000000000000010
mask: 0b1111000001111111
size: 16
branch: true
delay: 1
__reserved_cmv:
index: 81
encoding: 0b1000000000000010
mask: 0b1111111111111111
size: 16
branch: false
delay: 1
C__ADD:
index: 82
encoding: 0b1001000000000010
mask: 0b1111000000000011
size: 16
branch: false
delay: 1
C__JALR:
index: 83
encoding: 0b1001000000000010
mask: 0b1111000001111111
size: 16
branch: true
delay: 1
C__EBREAK:
index: 84
encoding: 0b1001000000000010
mask: 0b1111111111111111
size: 16
branch: false
delay: 1
C__SWSP:
index: 85
encoding: 0b1100000000000010
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
DII:
index: 86
encoding: 0b0000000000000000
mask: 0b1111111111111111
size: 16
branch: false
delay: 1

View File

@ -1,650 +0,0 @@
RV32I:
ADD:
branch: false
delay: 1
encoding: 51
index: 27
mask: 4261441663
size: 32
ADDI:
branch: false
delay: 1
encoding: 19
index: 18
mask: 28799
size: 32
AND:
branch: false
delay: 1
encoding: 28723
index: 36
mask: 4261441663
size: 32
ANDI:
branch: false
delay: 1
encoding: 28691
index: 23
mask: 28799
size: 32
AUIPC:
branch: false
delay: 1
encoding: 23
index: 1
mask: 127
size: 32
BEQ:
branch: true
delay:
- 1
- 2
encoding: 99
index: 4
mask: 28799
size: 32
BGE:
branch: true
delay:
- 1
- 2
encoding: 20579
index: 7
mask: 28799
size: 32
BGEU:
branch: true
delay:
- 1
- 2
encoding: 28771
index: 9
mask: 28799
size: 32
BLT:
branch: true
delay:
- 1
- 2
encoding: 16483
index: 6
mask: 28799
size: 32
BLTU:
branch: true
delay:
- 1
- 2
encoding: 24675
index: 8
mask: 28799
size: 32
BNE:
branch: true
delay:
- 1
- 2
encoding: 4195
index: 5
mask: 28799
size: 32
EBREAK:
attributes:
- - name:no_cont
branch: false
delay: 3
encoding: 1048691
index: 39
mask: 4294967295
size: 32
ECALL:
attributes:
- - name:no_cont
branch: false
delay: 1
encoding: 115
index: 38
mask: 4294967295
size: 32
FENCE:
branch: false
delay: 1
encoding: 15
index: 37
mask: 28799
size: 32
JAL:
branch: true
delay: 2
encoding: 111
index: 2
mask: 127
size: 32
JALR:
branch: true
delay: 2
encoding: 103
index: 3
mask: 28799
size: 32
LB:
branch: false
delay: 2
encoding: 3
index: 10
mask: 28799
size: 32
LBU:
branch: false
delay: 2
encoding: 16387
index: 13
mask: 28799
size: 32
LH:
branch: false
delay: 2
encoding: 4099
index: 11
mask: 28799
size: 32
LHU:
branch: false
delay: 2
encoding: 20483
index: 14
mask: 28799
size: 32
LUI:
branch: false
delay: 1
encoding: 55
index: 0
mask: 127
size: 32
LW:
branch: false
delay: 2
encoding: 8195
index: 12
mask: 28799
size: 32
MRET:
attributes:
- - name:no_cont
branch: false
delay: 2
encoding: 807403635
index: 40
mask: 4294967295
size: 32
OR:
branch: false
delay: 1
encoding: 24627
index: 35
mask: 4261441663
size: 32
ORI:
branch: false
delay: 1
encoding: 24595
index: 22
mask: 28799
size: 32
SB:
branch: false
delay: 1
encoding: 35
index: 15
mask: 28799
size: 32
SH:
branch: false
delay: 1
encoding: 4131
index: 16
mask: 28799
size: 32
SLL:
branch: false
delay: X_24:20
encoding: 4147
index: 29
mask: 4261441663
size: 32
SLLI:
branch: false
delay: u_24:20
encoding: 4115
index: 24
mask: 4261441663
size: 32
SLT:
branch: false
delay: 1
encoding: 8243
index: 30
mask: 4261441663
size: 32
SLTI:
branch: false
delay: 1
encoding: 8211
index: 19
mask: 28799
size: 32
SLTIU:
branch: false
delay: 1
encoding: 12307
index: 20
mask: 28799
size: 32
SLTU:
branch: false
delay: 1
encoding: 12339
index: 31
mask: 4261441663
size: 32
SRA:
branch: false
delay: X_24:20
encoding: 1073762355
index: 34
mask: 4261441663
size: 32
SRAI:
branch: false
delay: u_24:20
encoding: 1073762323
index: 26
mask: 4261441663
size: 32
SRL:
branch: false
delay: X_24:20
encoding: 20531
index: 33
mask: 4261441663
size: 32
SRLI:
branch: false
delay: u_24:20
encoding: 20499
index: 25
mask: 4261441663
size: 32
SUB:
branch: false
delay: 1
encoding: 1073741875
index: 28
mask: 4261441663
size: 32
SW:
branch: false
delay: 1
encoding: 8227
index: 17
mask: 28799
size: 32
WFI:
branch: false
delay: 1
encoding: 273678451
index: 41
mask: 4294967295
size: 32
XOR:
branch: false
delay: 1
encoding: 16435
index: 32
mask: 4261441663
size: 32
XORI:
branch: false
delay: 1
encoding: 16403
index: 21
mask: 28799
size: 32
RV32M:
DIV:
branch: false
delay: 33
encoding: 33570867
index: 53
mask: 4261441663
size: 32
DIVU:
branch: false
delay: 33
encoding: 33574963
index: 54
mask: 4261441663
size: 32
MUL:
branch: false
delay: 32
encoding: 33554483
index: 49
mask: 4261441663
size: 32
MULH:
branch: false
delay: 32
encoding: 33558579
index: 50
mask: 4261441663
size: 32
MULHSU:
branch: false
delay: 32
encoding: 33562675
index: 51
mask: 4261441663
size: 32
MULHU:
branch: false
delay: 32
encoding: 33566771
index: 52
mask: 4261441663
size: 32
REM:
branch: false
delay: 33
encoding: 33579059
index: 55
mask: 4261441663
size: 32
REMU:
branch: false
delay: 33
encoding: 33583155
index: 56
mask: 4261441663
size: 32
Zca:
C__ADD:
branch: false
delay: 1
encoding: 36866
index: 82
mask: 61443
size: 16
C__ADDI:
branch: false
delay: 1
encoding: 1
index: 60
mask: 57347
size: 16
C__ADDI16SP:
branch: false
delay: 1
encoding: 24833
index: 65
mask: 61315
size: 16
C__ADDI4SPN:
branch: false
delay: 1
encoding: 0
index: 57
mask: 57347
size: 16
C__AND:
branch: false
delay: 1
encoding: 35937
index: 73
mask: 64611
size: 16
C__ANDI:
branch: false
delay: 1
encoding: 34817
index: 69
mask: 60419
size: 16
C__BEQZ:
branch: true
delay:
- 1
- 2
encoding: 49153
index: 75
mask: 57347
size: 16
C__BNEZ:
branch: true
delay:
- 1
- 2
encoding: 57345
index: 76
mask: 57347
size: 16
C__EBREAK:
branch: false
delay: 3
encoding: 36866
index: 84
mask: 65535
size: 16
C__J:
branch: true
delay: 1
encoding: 40961
index: 74
mask: 57347
size: 16
C__JAL:
attributes:
- - name:enable
- value:1
branch: true
delay: 1
encoding: 8193
index: 62
mask: 57347
size: 16
C__JALR:
branch: true
delay: 1
encoding: 36866
index: 83
mask: 61567
size: 16
C__JR:
branch: true
delay: 1
encoding: 32770
index: 80
mask: 61567
size: 16
C__LI:
branch: false
delay: 1
encoding: 16385
index: 63
mask: 57347
size: 16
C__LUI:
branch: false
delay: 1
encoding: 24577
index: 64
mask: 57347
size: 16
C__LW:
branch: false
delay: 2
encoding: 16384
index: 58
mask: 57347
size: 16
C__LWSP:
branch: false
delay: 2
encoding: 16386
index: 78
mask: 57347
size: 16
C__MV:
branch: false
delay: 1
encoding: 32770
index: 79
mask: 61443
size: 16
C__NOP:
branch: false
delay: 1
encoding: 1
index: 61
mask: 61315
size: 16
C__OR:
branch: false
delay: 1
encoding: 35905
index: 72
mask: 64611
size: 16
C__SLLI:
attributes:
- - name:enable
- value:1
branch: false
delay: u_12:12*16+u_6:2
encoding: 2
index: 77
mask: 61443
size: 16
C__SRAI:
attributes:
- - name:enable
- value:1
branch: false
delay: u_12:12*16+u_6:2
encoding: 33793
index: 68
mask: 64515
size: 16
C__SRLI:
attributes:
- - name:enable
- value:1
branch: false
delay: u_12:12*16+u_6:2
encoding: 32769
index: 67
mask: 64515
size: 16
C__SUB:
branch: false
delay: 1
encoding: 35841
index: 70
mask: 64611
size: 16
C__SW:
branch: false
delay: 1
encoding: 49152
index: 59
mask: 57347
size: 16
C__SWSP:
branch: false
delay: 1
encoding: 49154
index: 85
mask: 57347
size: 16
C__XOR:
branch: false
delay: 1
encoding: 35873
index: 71
mask: 64611
size: 16
DII:
branch: false
delay: 1
encoding: 0
index: 86
mask: 65535
size: 16
__reserved_clui:
branch: false
delay: 1
encoding: 24577
index: 66
mask: 61567
size: 16
__reserved_cmv:
branch: false
delay: 1
encoding: 32770
index: 81
mask: 65535
size: 16
Zicsr:
CSRRC:
branch: false
delay: 1
encoding: 12403
index: 44
mask: 28799
size: 32
CSRRCI:
branch: false
delay: 1
encoding: 28787
index: 47
mask: 28799
size: 32
CSRRS:
branch: false
delay: 1
encoding: 8307
index: 43
mask: 28799
size: 32
CSRRSI:
branch: false
delay: 1
encoding: 24691
index: 46
mask: 28799
size: 32
CSRRW:
branch: false
delay: 1
encoding: 4211
index: 42
mask: 28799
size: 32
CSRRWI:
branch: false
delay: 1
encoding: 20595
index: 45
mask: 28799
size: 32
Zifencei:
FENCE_I:
attributes:
- - name:flush
branch: false
delay: 1
encoding: 4111
index: 48
mask: 28799
size: 32

View File

@ -1,3 +0,0 @@
/results
/cwr
/*.xml

View File

@ -1,43 +0,0 @@
# Notes
* requires conan version 1.59
* requires decent cmake version 3.23
Setup for tcsh:
```
git clone --recursive -b develop https://git.minres.com/TGFS/TGC-ISS.git
cd TGC-ISS/
setenv TGFS_INSTALL_ROOT `pwd`/install
setenv COWAREHOME <your SNPS PA installation>
setenv SNPSLMD_LICENSE_FILE <your SNPS PA license file>
source $COWAREHOME/SLS/linux/setup.csh pae
setenv SNPS_ENABLE_MEM_ON_DEMAND_IN_GENERIC_MEM 1
setenv PATH $COWAREHOME/common/bin/:${PATH}
setenv CC $COWAREHOME/SLS/linux/common/bin/gcc
setenv CXX $COWAREHOME/SLS/linux/common/bin/g++
cmake -S . -B build/PA -DCMAKE_BUILD_TYPE=Debug -DUSE_CWR_SYSTEMC=ON -DBUILD_SHARED_LIBS=ON \
-DCODEGEN=OFF -DCMAKE_INSTALL_PREFIX=${TGFS_INSTALL_ROOT}
cmake --build build/PA --target install -j16
cd dbt-rise-tgc/contrib/pa
# import the TGC core itself
pct tgc_import_tb.tcl
```
Setup for bash:
```
git clone --recursive -b develop https://git.minres.com/TGFS/TGC-ISS.git
cd TGC-ISS/
export TGFS_INSTALL_ROOT `pwd`/install
module load tools/pa/T-2022.06
export SNPS_ENABLE_MEM_ON_DEMAND_IN_GENERIC_MEM=1
export CC=$COWAREHOME/SLS/linux/common/bin/gcc
export CXX=$COWAREHOME/SLS/linux/common/bin/g++
cmake -S . -B build/PA -DCMAKE_BUILD_TYPE=Debug -DUSE_CWR_SYSTEMC=ON -DBUILD_SHARED_LIBS=ON \
-DCODEGEN=OFF -DCMAKE_INSTALL_PREFIX=${TGFS_INSTALL_ROOT}
cmake --build build/PA --target install -j16
cd dbt-rise-tgc/contrib/pa
# import the TGC core itself
pct tgc_import_tb.tcl
```

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View File

@ -1,71 +0,0 @@
source tgc_import.tcl
set hardware /HARDWARE/HW/HW
set FW_name ${scriptDir}/hello.elf
puts "instantiate testbench elements"
::paultra::add_hw_instance GenericIPlib:Memory_Generic -inst_name i_Memory_Generic
::pct::set_param_value i_Memory_Generic/MEM:protocol {Protocol Common Parameters} address_width 30
::pct::set_param_value i_Memory_Generic {Scml Properties} /timing/LT/clock_period_in_ns 1
::pct::set_param_value i_Memory_Generic {Scml Properties} /timing/read/cmd_accept_cycles 1
::pct::set_param_value i_Memory_Generic {Scml Properties} /timing/write/cmd_accept_cycles 1
::pct::set_bounds i_Memory_Generic 1000 300 100 100
::paultra::add_hw_instance Bus:Bus -inst_name i_Bus
::BLWizard::generateFramework i_Bus SBLTLM2FT * {} \
{ common_configuration:BackBone:/advanced/num_resources_per_target:1 }
::pct::set_bounds i_Bus 700 300 100 400
::pct::create_connection C_ibus i_core_complex/ibus i_Bus/i_core_complex_ibus
::pct::set_location_on_owner i_Bus/i_core_complex_ibus 10
::pct::create_connection C_dbus i_core_complex/dbus i_Bus/i_core_complex_dbus
::pct::set_location_on_owner i_Bus/i_core_complex_dbus 10
::pct::create_connection C_mem i_Bus/i_Memory_Generic_MEM i_Memory_Generic/MEM
puts "instantiating clock manager"
set clock "Clk"
::hw::create_hw_instance "" GenericIPlib:ClockGenerator ${clock}_clock
::pct::set_bounds ${clock}_clock 100 100 100 100
::pct::set_param_value $hardware/${clock}_clock {Constructor Arguments} period 1000
::pct::set_param_value $hardware/${clock}_clock {Constructor Arguments} period_unit sc_core::SC_PS
puts "instantiating reset manager"
set reset "Rst"
::hw::create_hw_instance "" GenericIPlib:ResetGenerator ${reset}_reset
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} start_time 0
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} start_time_unit sc_core::SC_PS
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} duration 10000
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} duration_unit sc_core::SC_PS
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} active_level true
::pct::set_bounds ${reset}_reset 300 100 100 100
puts "connecting reset/clock"
::pct::create_connection C_clk . Clk_clock/CLK i_core_complex/clk_i
::pct::add_ports_to_connection C_clk i_Bus/Clk
::pct::add_ports_to_connection C_clk i_Memory_Generic/CLK
::pct::create_connection C_rst . Rst_reset/RST i_core_complex/rst_i
::pct::add_ports_to_connection C_rst i_Bus/Rst
puts "setting parameters for DBT-RISE-TGC/Bus and memory components"
::pct::set_param_value $hardware/i_${top_design_name} {Extra properties} elf_file ${FW_name}
::pct::set_address $hardware/i_${top_design_name}/ibus:i_Memory_Generic/MEM 0x0
::pct::set_address $hardware/i_${top_design_name}/dbus:i_Memory_Generic/MEM 0x0
::BLWizard::updateFramework i_Bus {} { common_configuration:BackBone:/advanced/num_resources_per_target:1 }
::pct::set_main_configuration Default {{#include <scc/report.h>} {::scc::init_logging(::scc::LogConfig().logLevel(::scc::log::INFO).coloredOutput(false).logAsync(false));} {} {} {}}
::pct::set_main_configuration Debug {{#include <scc/report.h>} {::scc::init_logging(::scc::LogConfig().logLevel(::scc::log::DEBUG).coloredOutput(false).logAsync(false));} {} {} {}}
::pct::create_simulation_build_config Debug
::pct::set_simulation_build_project_setting Debug "Main Configuration" Default
# add build settings and save design for next steps
#::pct::set_simulation_build_project_setting "Debug" "Linker Flags" "-Wl,-z,muldefs $::env(VERILATOR_ROOT)/include/verilated.cpp $::env(VERILATOR_ROOT)/include/verilated_vcd_sc.cpp $::env(VERILATOR_ROOT)/include/verilated_vcd_c.cpp"
#::pct::set_simulation_build_project_setting "Debug" "Include Paths" $::env(VERILATOR_ROOT)/include/
#::simulation::set_simulation_property Simulation [list run_for_duration:200ns results_dir:results/test_0 "TLM Port Trace:true"]
#::simulation::run_simulation Simulation
#::pct::set_simulation_build_project_setting Debug {Export Type} {STATIC NETLIST}
#::pct::set_simulation_build_project_setting Debug {Encapsulated Netlist} false
#::pct::export_system "export"
#::cd "export"
#::scsh::open-project
#::scsh::build
#::scsh::elab sim
::pct::save_system testbench.xml

View File

@ -6,11 +6,14 @@ proc getScriptDirectory {} {
set scriptFolder [file dirname $dispScriptFile] set scriptFolder [file dirname $dispScriptFile]
return $scriptFolder return $scriptFolder
} }
if { $::env(SNPS_VP_PRODUCT) == "PAULTRA" } {
set hardware /HARDWARE/HW/HW set hardware /HARDWARE/HW/HW
} else {
set hardware /HARDWARE
}
set scriptDir [getScriptDirectory] set scriptDir [getScriptDirectory]
set top_design_name core_complex set top_design_name core_complex
set encap_name sysc::tgfs::${top_design_name}
set clocks clk_i set clocks clk_i
set resets rst_i set resets rst_i
set model_prefix "i_" set model_prefix "i_"
@ -25,8 +28,7 @@ set model_postfix ""
::pct::set_update_existing_encaps_flag true ::pct::set_update_existing_encaps_flag true
::pct::set_dynamic_port_arrays_flag true ::pct::set_dynamic_port_arrays_flag true
::pct::set_import_scml_properties_flag true ::pct::set_import_scml_properties_flag true
::pct::set_import_encap_prop_as_extra_prop_flag true ::pct::load_modules --set-category modules tgc_import.cc
::pct::load_modules --set-category modules ${scriptDir}/tgc_import.cc
# Set Port Protocols correctly # Set Port Protocols correctly
set block ${top_design_name} set block ${top_design_name}
@ -36,15 +38,13 @@ foreach clock ${clocks} {
foreach reset ${resets} { foreach reset ${resets} {
::pct::set_block_port_protocol --set-category SYSTEM_LIBRARY:$block/${reset} SYSTEM_LIBRARY:RESET ::pct::set_block_port_protocol --set-category SYSTEM_LIBRARY:$block/${reset} SYSTEM_LIBRARY:RESET
} }
#::pct::set_encap_port_array_size SYSTEM_LIBRARY:$block/local_irq_i 16 ::pct::set_encap_port_array_size SYSTEM_LIBRARY:$block/local_irq_i 16
# Set compile settings and look # Set compile settings and look
set block SYSTEM_LIBRARY:${top_design_name} set block SYSTEM_LIBRARY:${top_design_name}
::pct::set_encap_build_script $block/${encap_name} $scriptDir/build.tcl ::pct::set_encap_build_script $block/${top_design_name} $scriptDir/build.tcl
::pct::set_background_color_rgb $block 255 255 255 255 ::pct::set_background_color_rgb $block 255 255 255 255
::pct::create_instance SYSTEM_LIBRARY:${top_design_name} ${hardware} ${model_prefix}${top_design_name}${model_postfix} ${encap_name} ${encap_name}() ::pct::create_instance SYSTEM_LIBRARY:${top_design_name} ${hardware} ${model_prefix}${top_design_name}${model_postfix} ${top_design_name}
::pct::set_bounds i_${top_design_name} 200 300 100 400
::pct::set_image i_${top_design_name} "$scriptDir/minres.png" center center false true
# export the result as component # export the result as component
::pct::export_system_library ${top_design_name} ${top_design_name}.xml ::pct::export_system_library ${top_design_name} ${top_design_name}.xml

View File

@ -1,2 +1 @@
/src-gen/ /src-gen/
/CoreDSL-Instruction-Set-Description

@ -0,0 +1 @@
Subproject commit 8d9a0fb1493b762014c330c71ac8cef96753d302

View File

@ -1,13 +0,0 @@
import "ISA/RVI.core_desc"
import "ISA/RVM.core_desc"
import "ISA/RVC.core_desc"
Core TGC5C provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
architectural_state {
XLEN=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
unsigned int MISA_VAL = 0b01000000000000000001000100000100;
unsigned int MARCHID_VAL = 0x80000003;
}
}

37
gen_input/TGFS.core_desc Normal file
View File

@ -0,0 +1,37 @@
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
Core TGC_B provides RV32I {
architectural_state {
unsigned XLEN=32;
unsigned PCLEN=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
unsigned MISA_VAL = 0b01000000000000000000000100000000;
unsigned PGSIZE = 0x1000; //1 << 12;
unsigned PGMASK = 0xfff; //PGSIZE-1
}
}
Core TGC_C provides RV32I, RV32M, RV32IC {
architectural_state {
unsigned XLEN=32;
unsigned PCLEN=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
unsigned MISA_VAL = 0b01000000000000000001000100000100;
unsigned PGSIZE = 0x1000; //1 << 12;
unsigned PGMASK = 0xfff; //PGSIZE-1
}
}
Core TGC_D provides RV32I, RV32M, RV32IC {
architectural_state {
unsigned XLEN=32;
unsigned PCLEN=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
unsigned MISA_VAL = 0b01000000000000000001000100000100;
}
}

View File

@ -33,14 +33,13 @@
def getRegisterSizes(){ def getRegisterSizes(){
def regs = registers.collect{it.size} def regs = registers.collect{it.size}
regs[-1]=64 // correct for NEXT_PC regs[-1]=64 // correct for NEXT_PC
regs+=[32,32, 64, 64, 64, 32, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH regs+=[32, 32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
return regs return regs
} }
%> %>
// clang-format off
#include "${coreDef.name.toLowerCase()}.h"
#include "util/ities.h" #include "util/ities.h"
#include <util/logging.h> #include <util/logging.h>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <fstream> #include <fstream>
@ -52,14 +51,14 @@ constexpr std::array<const char*, ${registers.size}> iss::arch::traits<iss::a
constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths; constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets; constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() = default; ${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
reg.icount = 0;
}
${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default; ${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default;
void ${coreDef.name.toLowerCase()}::reset(uint64_t address) { void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
auto base_ptr = reinterpret_cast<traits<${coreDef.name.toLowerCase()}>::reg_t*>(get_regs_base_ptr()); for(size_t i=0; i<traits<${coreDef.name.toLowerCase()}>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<${coreDef.name.toLowerCase()}>::reg_t),0));
for(size_t i=0; i<traits<${coreDef.name.toLowerCase()}>::NUM_REGS; ++i)
*(base_ptr+i)=0;
reg.PC=address; reg.PC=address;
reg.NEXT_PC=reg.PC; reg.NEXT_PC=reg.PC;
reg.PRIV=0x3; reg.PRIV=0x3;
@ -71,7 +70,7 @@ uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
return reinterpret_cast<uint8_t*>(&reg); return reinterpret_cast<uint8_t*>(&reg);
} }
${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &addr) { ${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<${coreDef.name.toLowerCase()}>::addr_mask); return phys_addr_t(pc); // change logical address to physical address
} }
// clang-format on

View File

@ -30,12 +30,14 @@
* *
*******************************************************************************/ *******************************************************************************/
<% <%
import com.minres.coredsl.util.BigIntegerWithRadix
def nativeTypeSize(int size){ def nativeTypeSize(int size){
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64; if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
} }
def getRegisterSizes(){ def getRegisterSizes(){
def regs = registers.collect{nativeTypeSize(it.size)} def regs = registers.collect{nativeTypeSize(it.size)}
regs+=[32,32, 64, 64, 64, 32, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH regs+=[32,32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
return regs return regs
} }
def getRegisterOffsets(){ def getRegisterOffsets(){
@ -55,12 +57,15 @@ def byteSize(int size){
return 128; return 128;
} }
def getCString(def val){ def getCString(def val){
return val.toString()+'ULL' if(val instanceof BigIntegerWithRadix)
return ((BigIntegerWithRadix)val).toCString()
else
return val.toString()
} }
%> %>
#ifndef _${coreDef.name.toUpperCase()}_H_ #ifndef _${coreDef.name.toUpperCase()}_H_
#define _${coreDef.name.toUpperCase()}_H_ #define _${coreDef.name.toUpperCase()}_H_
// clang-format off
#include <array> #include <array>
#include <iss/arch/traits.h> #include <iss/arch/traits.h>
#include <iss/arch_if.h> #include <iss/arch_if.h>
@ -76,17 +81,22 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
constexpr static char const* const core_type = "${coreDef.name}"; constexpr static char const* const core_type = "${coreDef.name}";
static constexpr std::array<const char*, ${registers.size}> reg_names{ static constexpr std::array<const char*, ${registers.size}> reg_names{
{"${registers.collect{it.name.toLowerCase()}.join('", "')}"}}; {"${registers.collect{it.name}.join('", "')}"}};
static constexpr std::array<const char*, ${registers.size}> reg_aliases{ static constexpr std::array<const char*, ${registers.size}> reg_aliases{
{"${registers.collect{it.alias.toLowerCase()}.join('", "')}"}}; {"${registers.collect{it.alias}.join('", "')}"}};
enum constants {${constants.collect{c -> c.name+"="+getCString(c.value)}.join(', ')}}; enum constants {${constants.collect{c -> c.name+"="+getCString(c.value)}.join(', ')}};
constexpr static unsigned FP_REGS_SIZE = ${constants.find {it.name=='FLEN'}?.value?:0}; constexpr static unsigned FP_REGS_SIZE = ${constants.find {it.name=='FLEN'}?.value?:0};
enum reg_e { enum reg_e {
${registers.collect{it.name}.join(', ')}, NUM_REGS, TRAP_STATE=NUM_REGS, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH ${registers.collect{it.name}.join(', ')}, NUM_REGS,
TRAP_STATE=NUM_REGS,
PENDING_TRAP,
ICOUNT,
CYCLE,
INSTRET
}; };
using reg_t = uint${addrDataWidth}_t; using reg_t = uint${addrDataWidth}_t;
@ -109,9 +119,9 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
enum sreg_flag_e { FLAGS }; enum sreg_flag_e { FLAGS };
enum mem_type_e { ${spaces.collect{it.name}.join(', ')}, IMEM = MEM }; enum mem_type_e { ${spaces.collect{it.name}.join(', ')} };
enum class opcode_e {<%instructions.eachWithIndex{instr, index -> %> enum class opcode_e : unsigned short {<%instructions.eachWithIndex{instr, index -> %>
${instr.instruction.name} = ${index},<%}%> ${instr.instruction.name} = ${index},<%}%>
MAX_OPCODE MAX_OPCODE
}; };
@ -130,6 +140,14 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
void reset(uint64_t address=0) override; void reset(uint64_t address=0) override;
uint8_t* get_regs_base_ptr() override; uint8_t* get_regs_base_ptr() override;
/// deprecated
void get_reg(short idx, std::vector<uint8_t>& value) override {}
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
/// deprecated
bool get_flag(int flag) override {return false;}
void set_flag(int, bool value) override {};
/// deprecated
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
inline uint64_t get_icount() { return reg.icount; } inline uint64_t get_icount() { return reg.icount; }
@ -137,13 +155,21 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
inline uint64_t stop_code() { return interrupt_sim; } inline uint64_t stop_code() { return interrupt_sim; }
inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<${coreDef.name.toLowerCase()}>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<${coreDef.name.toLowerCase()}>::addr_mask);
} else
return virt2phys(addr);
}
virtual phys_addr_t virt2phys(const iss::addr_t& addr); virtual phys_addr_t virt2phys(const iss::addr_t& addr);
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
inline uint32_t get_last_branch() { return reg.last_branch; } inline uint32_t get_last_branch() { return reg.last_branch; }
protected:
#pragma pack(push, 1) #pragma pack(push, 1)
struct ${coreDef.name}_regs {<% struct ${coreDef.name}_regs {<%
registers.each { reg -> if(reg.size>0) {%> registers.each { reg -> if(reg.size>0) {%>
@ -153,8 +179,7 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
uint64_t icount = 0; uint64_t icount = 0;
uint64_t cycle = 0; uint64_t cycle = 0;
uint64_t instret = 0; uint64_t instret = 0;
uint32_t instruction = 0; uint32_t last_branch;
uint32_t last_branch = 0;
} reg; } reg;
#pragma pack(pop) #pragma pack(pop)
std::array<address_type, 4> addr_mode; std::array<address_type, 4> addr_mode;
@ -174,4 +199,3 @@ if(fcsr != null) {%>
} }
} }
#endif /* _${coreDef.name.toUpperCase()}_H_ */ #endif /* _${coreDef.name.toUpperCase()}_H_ */
// clang-format on

View File

@ -1,12 +1,9 @@
{ {
"${coreDef.name}" : [<%instructions.eachWithIndex{instr,index -> %>${index==0?"":","} "${coreDef.name}" : [<%instructions.eachWithIndex{instr,index -> %>${index==0?"":","}
{ {
"name" : "${instr.name}", "name" : "${instr.name}",
"size" : ${instr.length}, "size" : ${instr.length},
"encoding": "${instr.encoding}", "delay" : ${generator.hasAttribute(instr.instruction, com.minres.coredsl.coreDsl.InstrAttribute.COND)?[1,1]:1}
"mask": "${instr.mask}",
"branch": ${instr.modifiesPC},
"delay" : ${instr.isConditional?"[1,1]":"1"}
}<%}%> }<%}%>
] ]
} }

View File

@ -1,21 +0,0 @@
<% def getInstructionGroups() {
def instrGroups = [:]
instructions.each {
def groupName = it['instruction'].eContainer().name
if(!instrGroups.containsKey(groupName)) {
instrGroups[groupName]=[]
}
instrGroups[groupName]+=it;
}
instrGroups
}%><%int index = 0; getInstructionGroups().each{name, instrList -> %>
${name}: <% instrList.each { %>
${it.instruction.name}:
index: ${index++}
encoding: ${it.encoding}
mask: ${it.mask}<%if(it.attributes.size) {%>
attributes: ${it.attributes}<%}%>
size: ${it.length}
branch: ${it.modifiesPC}
delay: ${it.isConditional?"[1,1]":"1"}<%}}%>

View File

@ -1,131 +0,0 @@
/*******************************************************************************
* Copyright (C) 2023 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
// clang-format off
#include <sysc/iss_factory.h>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h>
#include <sysc/sc_core_adapter.h>
#include <sysc/core_complex.h>
#include <array>
<%
def array_count = coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e"? 3 : 2;
%>
namespace iss {
namespace interp {
using namespace sysc;
volatile std::array<bool, ${array_count}> ${coreDef.name.toLowerCase()}_init = {
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
}),
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
})<%if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") {%>,
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p_clic_pmp|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_EXT_N | iss::arch::FEAT_CLIC)>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
})<%}%>
};
}
#if defined(WITH_LLVM)
namespace llvm {
using namespace sysc;
volatile std::array<bool, ${array_count}> ${coreDef.name.toLowerCase()}_init = {
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|llvm", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
}),
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|llvm", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
})<%if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") {%>,
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p_clic_pmp|llvm", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_EXT_N | iss::arch::FEAT_CLIC)>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
})<%}%>
};
}
#endif
#if defined(WITH_TCC)
namespace tcc {
using namespace sysc;
volatile std::array<bool, ${array_count}> ${coreDef.name.toLowerCase()}_init = {
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
}),
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
})<%if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") {%>,
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p_clic_pmp|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_EXT_N | iss::arch::FEAT_CLIC)>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
})<%}%>
};
}
#endif
#if defined(WITH_ASMJIT)
namespace asmjit {
using namespace sysc;
volatile std::array<bool, ${array_count}> ${coreDef.name.toLowerCase()}_init = {
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|asmjit", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
}),
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|asmjit", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
})<%if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") {%>,
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p_clic_pmp|asmjit", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_EXT_N | iss::arch::FEAT_CLIC)>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
})<%}%>
};
}
#endif
}
// clang-format on

View File

@ -1,384 +0,0 @@
/*******************************************************************************
* Copyright (C) 2017, 2023 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
// clang-format off
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/iss.h>
#include <iss/asmjit/vm_base.h>
#include <asmjit/asmjit.h>
#include <util/logging.h>
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <fmt/format.h>
#include <array>
#include <iss/debugger/riscv_target_adapter.h>
namespace iss {
namespace asmjit {
namespace ${coreDef.name.toLowerCase()} {
using namespace ::asmjit;
using namespace iss::arch;
using namespace iss::debugger;
template <typename ARCH> class vm_impl : public iss::asmjit::vm_base<ARCH> {
public:
using traits = arch::traits<ARCH>;
using super = typename iss::asmjit::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t;
using mem_type_e = typename super::mem_type_e;
using addr_t = typename super::addr_t;
vm_impl();
vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);
void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }
target_adapter_if *accquire_target_adapter(server_if *srv) override {
debugger_if::dbg_enabled = true;
if (vm_base<ARCH>::tgt_adapter == nullptr)
vm_base<ARCH>::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch());
return vm_base<ARCH>::tgt_adapter;
}
protected:
using super::get_ptr_for;
using super::get_reg;
using super::get_reg_for;
using super::load_reg_from_mem;
using super::write_reg_to_mem;
using super::gen_ext;
using super::gen_read_mem;
using super::gen_write_mem;
using super::gen_wait;
using super::gen_leave;
using super::gen_operation;
using this_class = vm_impl<ARCH>;
using compile_func = continuation_e (this_class::*)(virt_addr_t&, code_word_t, jit_holder&);
continuation_e gen_single_inst_behavior(virt_addr_t&, unsigned int &, jit_holder&) override;
void gen_block_prologue(jit_holder& jh) override;
void gen_block_epilogue(jit_holder& jh) override;
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
void gen_instr_prologue(jit_holder& jh);
void gen_instr_epilogue(jit_holder& jh);
inline void gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t cause);
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
inline S sext(U from) {
auto mask = (1ULL<<W) - 1;
auto sign_mask = 1ULL<<(W-1);
return (from & mask) | ((from & sign_mask) ? ~mask : 0);
}
private:
/****************************************************************************
* start opcode definitions
****************************************************************************/
struct instruction_descriptor {
size_t length;
uint32_t value;
uint32_t mask;
compile_func op;
};
struct decoding_tree_node{
std::vector<instruction_descriptor> instrs;
std::vector<decoding_tree_node*> children;
uint32_t submask = std::numeric_limits<uint32_t>::max();
uint32_t value;
decoding_tree_node(uint32_t value) : value(value){}
};
decoding_tree_node* root {nullptr};
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
}};
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
/* instruction ${idx}: ${instr.name} */
continuation_e __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, jit_holder& jh){
uint64_t PC = pc.val;
<%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){
/* generate disass */
<%instr.disass.eachLine{%>
${it}<%}%>
InvokeNode* call_print_disass;
char* mnemonic_ptr = strdup(mnemonic.c_str());
jh.disass_collection.push_back(mnemonic_ptr);
jh.cc.invoke(&call_print_disass, &print_disass, FuncSignatureT<void, void *, uint64_t, char *>());
call_print_disass->setArg(0, jh.arch_if_ptr);
call_print_disass->setArg(1, pc.val);
call_print_disass->setArg(2, mnemonic_ptr);
}
x86::Compiler& cc = jh.cc;
cc.comment(fmt::format("${instr.name}_{:#x}:",pc.val).c_str());
this->gen_sync(jh, PRE_SYNC, ${idx});
cc.mov(jh.pc, pc.val);
pc = pc+${instr.length/8};
cc.mov(jh.next_pc, pc.val);
gen_instr_prologue(jh);
cc.comment("//behavior:");
/*generate behavior*/
<%instr.behavior.eachLine{%>${it}
<%}%>
gen_instr_epilogue(jh);
this->gen_sync(jh, POST_SYNC, ${idx});
return returnValue;
}
<%}%>
/****************************************************************************
* end opcode definitions
****************************************************************************/
continuation_e illegal_intruction(virt_addr_t &pc, code_word_t instr, jit_holder& jh ) {
x86::Compiler& cc = jh.cc;
cc.comment(fmt::format("illegal_intruction{:#x}:",pc.val).c_str());
this->gen_sync(jh, PRE_SYNC, instr_descr.size());
pc = pc + ((instr & 3) == 3 ? 4 : 2);
gen_instr_prologue(jh);
cc.comment("//behavior:");
gen_instr_epilogue(jh);
this->gen_sync(jh, POST_SYNC, instr_descr.size());
return BRANCH;
}
//decoding functionality
void populate_decoding_tree(decoding_tree_node* root){
//create submask
for(auto instr: root->instrs){
root->submask &= instr.mask;
}
//put each instr according to submask&encoding into children
for(auto instr: root->instrs){
bool foundMatch = false;
for(auto child: root->children){
//use value as identifying trait
if(child->value == (instr.value&root->submask)){
child->instrs.push_back(instr);
foundMatch = true;
}
}
if(!foundMatch){
decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
child->instrs.push_back(instr);
root->children.push_back(child);
}
}
root->instrs.clear();
//call populate_decoding_tree for all children
if(root->children.size() >1)
for(auto child: root->children){
populate_decoding_tree(child);
}
else{
//sort instrs by value of the mask, this works bc we want to have the least restrictive one last
std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
return instr1.mask > instr2.mask;
});
}
}
compile_func decode_instr(decoding_tree_node* node, code_word_t word){
if(!node->children.size()){
if(node->instrs.size() == 1) return node->instrs[0].op;
for(auto instr : node->instrs){
if((instr.mask&word) == instr.value) return instr.op;
}
}
else{
for(auto child : node->children){
if (child->value == (node->submask&word)){
return decode_instr(child, word);
}
}
}
return nullptr;
}
};
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) {
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
for(auto instr: instr_descr){
root->instrs.push_back(instr);
}
populate_decoding_tree(root);
}
template <typename ARCH>
continuation_e vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, jit_holder& jh) {
enum {TRAP_ID=1<<16};
code_word_t instr = 0;
phys_addr_t paddr(pc);
auto *const data = (uint8_t *)&instr;
if(this->core.has_mmu())
paddr = this->core.virt2phys(pc);
auto res = this->core.read(paddr, 4, data);
if (res != iss::Ok)
throw trap_access(TRAP_ID, pc.val);
if (instr == 0x0000006f || (instr&0xffff)==0xa001)
throw simulation_stopped(0); // 'J 0' or 'C.J 0'
++inst_cnt;
auto f = decode_instr(root, instr);
if (f == nullptr)
f = &this_class::illegal_intruction;
return (this->*f)(pc, instr, jh);
}
template <typename ARCH>
void vm_impl<ARCH>::gen_instr_prologue(jit_holder& jh) {
auto& cc = jh.cc;
cc.comment("//gen_instr_prologue");
cc.inc(get_ptr_for(jh, traits::ICOUNT));
x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE);
cc.mov(current_trap_state, get_ptr_for(jh, traits::TRAP_STATE));
cc.mov(get_ptr_for(jh, traits::PENDING_TRAP), current_trap_state);
}
template <typename ARCH>
void vm_impl<ARCH>::gen_instr_epilogue(jit_holder& jh) {
auto& cc = jh.cc;
cc.comment("//gen_instr_epilogue");
x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE);
cc.mov(current_trap_state, get_ptr_for(jh, traits::TRAP_STATE));
cc.cmp(current_trap_state, 0);
cc.jne(jh.trap_entry);
}
template <typename ARCH>
void vm_impl<ARCH>::gen_block_prologue(jit_holder& jh){
jh.pc = load_reg_from_mem(jh, traits::PC);
jh.next_pc = load_reg_from_mem(jh, traits::NEXT_PC);
}
template <typename ARCH>
void vm_impl<ARCH>::gen_block_epilogue(jit_holder& jh){
x86::Compiler& cc = jh.cc;
cc.comment("//gen_block_epilogue");
cc.ret(jh.next_pc);
cc.bind(jh.trap_entry);
this->write_back(jh);
this->gen_sync(jh, POST_SYNC, -1);
x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE);
cc.mov(current_trap_state, get_ptr_for(jh, traits::TRAP_STATE));
x86::Gp current_pc = get_reg_for(jh, traits::PC);
cc.mov(current_pc, get_ptr_for(jh, traits::PC));
x86::Gp instr = cc.newInt32("instr");
cc.mov(instr, 0); // FIXME:this is not correct
cc.comment("//enter trap call;");
InvokeNode* call_enter_trap;
cc.invoke(&call_enter_trap, &enter_trap, FuncSignatureT<uint64_t, void*, uint64_t, uint64_t, uint64_t>());
call_enter_trap->setArg(0, jh.arch_if_ptr);
call_enter_trap->setArg(1, current_trap_state);
call_enter_trap->setArg(2, current_pc);
call_enter_trap->setArg(3, instr);
x86::Gp current_next_pc = get_reg_for(jh, traits::NEXT_PC);
cc.mov(current_next_pc, get_ptr_for(jh, traits::NEXT_PC));
cc.mov(jh.next_pc, current_next_pc);
cc.mov(get_ptr_for(jh, traits::LAST_BRANCH), std::numeric_limits<uint32_t>::max());
cc.ret(jh.next_pc);
}
template <typename ARCH>
inline void vm_impl<ARCH>::gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t cause) {
auto& cc = jh.cc;
cc.comment("//gen_raise");
auto tmp1 = get_reg_for(jh, traits::TRAP_STATE);
cc.mov(tmp1, 0x80ULL << 24 | (cause << 16) | trap_id);
cc.mov(get_ptr_for(jh, traits::TRAP_STATE), tmp1);
cc.mov(jh.next_pc, std::numeric_limits<uint32_t>::max());
}
} // namespace tgc5c
template <>
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
auto ret = new ${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*core, dump);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret);
}
} // namespace asmjit
} // namespace iss
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h>
#include <iss/factory.h>
namespace iss {
namespace {
volatile std::array<bool, 2> dummy = {
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|asmjit", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new asmjit::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t)>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};
}),
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|asmjit", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new asmjit::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t)>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};
})
};
}
}
// clang-format on

View File

@ -29,23 +29,15 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
* *
*******************************************************************************/ *******************************************************************************/
<%
def nativeTypeSize(int size){ #include "../fp_functions.h"
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
}
%>
// clang-format off
#include <iss/arch/${coreDef.name.toLowerCase()}.h> #include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/debugger/gdb_session.h> #include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h> #include <iss/debugger/server.h>
#include <iss/iss.h> #include <iss/iss.h>
#include <iss/interp/vm_base.h> #include <iss/interp/vm_base.h>
#include <vm/fp_functions.h>
#include <util/logging.h> #include <util/logging.h>
#include <boost/coroutine2/all.hpp>
#include <functional>
#include <exception>
#include <vector>
#include <sstream> #include <sstream>
#ifndef FMT_HEADER_ONLY #ifndef FMT_HEADER_ONLY
@ -61,11 +53,6 @@ namespace interp {
namespace ${coreDef.name.toLowerCase()} { namespace ${coreDef.name.toLowerCase()} {
using namespace iss::arch; using namespace iss::arch;
using namespace iss::debugger; using namespace iss::debugger;
using namespace std::placeholders;
struct memory_access_exception : public std::exception{
memory_access_exception(){}
};
template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> { template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> {
public: public:
@ -77,8 +64,7 @@ public:
using addr_t = typename super::addr_t; using addr_t = typename super::addr_t;
using reg_t = typename traits::reg_t; using reg_t = typename traits::reg_t;
using mem_type_e = typename traits::mem_type_e; using mem_type_e = typename traits::mem_type_e;
using opcode_e = typename traits::opcode_e;
vm_impl(); vm_impl();
vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0); vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);
@ -97,16 +83,34 @@ protected:
using compile_ret_t = virt_addr_t; using compile_ret_t = virt_addr_t;
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr); using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr);
inline const char *name(size_t index){return index<traits::reg_aliases.size()?traits::reg_aliases[index]:"illegal";} inline const char *name(size_t index){return traits::reg_aliases.at(index);}
compile_func decode_inst(code_word_t instr) ;
virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override; virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
// some compile time constants // some compile time constants
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) };
std::array<compile_func, LUT_SIZE> lut;
std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10;
std::array<compile_func, LUT_SIZE> lut_11;
struct instruction_pattern {
uint32_t value;
uint32_t mask;
compile_func opc;
};
std::array<std::vector<instruction_pattern>, 4> qlut;
inline void raise(uint16_t trap_id, uint16_t cause){ inline void raise(uint16_t trap_id, uint16_t cause){
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id; auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
this->core.reg.trap_state = trap_val; this->template get_reg<uint32_t>(traits::TRAP_STATE) = trap_val;
this->template get_reg<uint${addrDataWidth}_t>(traits::NEXT_PC) = std::numeric_limits<uint${addrDataWidth}_t>::max(); this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max();
} }
inline void leave(unsigned lvl){ inline void leave(unsigned lvl){
@ -117,124 +121,140 @@ protected:
this->core.wait_until(type); this->core.wait_until(type);
} }
using yield_t = boost::coroutines2::coroutine<void>::push_type; template<typename T>
using coro_t = boost::coroutines2::coroutine<void>::pull_type; T& pc_assign(T& val){super::ex_info.branch_taken=true; return val;}
std::vector<coro_t> spawn_blocks; inline uint8_t readSpace1(typename super::mem_type_e space, uint64_t addr){
auto ret = super::template read_mem<uint8_t>(space, addr);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
return ret;
}
inline uint16_t readSpace2(typename super::mem_type_e space, uint64_t addr){
auto ret = super::template read_mem<uint16_t>(space, addr);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
return ret;
}
inline uint32_t readSpace4(typename super::mem_type_e space, uint64_t addr){
auto ret = super::template read_mem<uint32_t>(space, addr);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
return ret;
}
inline uint64_t readSpace8(typename super::mem_type_e space, uint64_t addr){
auto ret = super::template read_mem<uint64_t>(space, addr);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
return ret;
}
inline void writeSpace1(typename super::mem_type_e space, uint64_t addr, uint8_t data){
super::write_mem(space, addr, data);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
}
inline void writeSpace2(typename super::mem_type_e space, uint64_t addr, uint16_t data){
super::write_mem(space, addr, data);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
}
inline void writeSpace4(typename super::mem_type_e space, uint64_t addr, uint32_t data){
super::write_mem(space, addr, data);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
}
inline void writeSpace8(typename super::mem_type_e space, uint64_t addr, uint64_t data){
super::write_mem(space, addr, data);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
}
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type> template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
inline S sext(U from) { inline S sext(U from) {
auto mask = (1ULL<<W) - 1; auto mask = (1ULL<<W) - 1;
auto sign_mask = 1ULL<<(W-1); auto sign_mask = 1ULL<<(W-1);
return (from & mask) | ((from & sign_mask) ? ~mask : 0); return (from & mask) | ((from & sign_mask) ? ~mask : 0);
} }
inline void process_spawn_blocks() {
if(spawn_blocks.size()==0) return;
for(auto it = std::begin(spawn_blocks); it!=std::end(spawn_blocks);)
if(*it){
(*it)();
++it;
} else
spawn_blocks.erase(it);
}
<%functions.each{ it.eachLine { %>
${it}<%}%>
<%}%>
private: private:
/**************************************************************************** /****************************************************************************
* start opcode definitions * start opcode definitions
****************************************************************************/ ****************************************************************************/
struct instruction_descriptor { struct InstructionDesriptor {
size_t length; size_t length;
uint32_t value; uint32_t value;
uint32_t mask; uint32_t mask;
typename arch::traits<ARCH>::opcode_e op; compile_func op;
};
struct decoding_tree_node{
std::vector<instruction_descriptor> instrs;
std::vector<decoding_tree_node*> children;
uint32_t submask = std::numeric_limits<uint32_t>::max();
uint32_t value;
decoding_tree_node(uint32_t value) : value(value){}
}; };
decoding_tree_node* root {nullptr}; const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
{${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%> /* instruction ${instr.instruction.name} */
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
}}; }};
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ /* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
if(this->core.has_mmu()) { /* instruction ${idx}: ${instr.name} */
auto phys_pc = this->core.virt2phys(pc); compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){
// if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary // pre execution stuff
// if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err; auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
// if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction auto NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
// if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) *PC=*NEXT_PC;
// return iss::Err; auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
// } else { *trap_state = *reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PENDING_TRAP]);
if (this->core.read(phys_pc, 4, data) != iss::Ok) if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, ${idx});
return iss::Err; <%instr.fields.eachLine{%>${it}
// } <%}%>if(this->disass_enabled){
/* generate console output when executing the command */
<%instr.disass.eachLine{%>${it}
<%}%>
}
// used registers<%instr.usedVariables.each{ k,v->
if(v.isArray) {%>
auto* ${k} = reinterpret_cast<uint${v.type.size}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}0]);<% }else{ %>
auto* ${k} = reinterpret_cast<uint${v.type.size}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]);
<%}}%>// calculate next pc value
*NEXT_PC = *PC + ${instr.length/8};
// execute instruction
try {
<%instr.behavior.eachLine{%>${it}
<%}%>} catch(...){}
// post execution stuff
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, ${idx});
// trap check
if(*trap_state!=0){
super::core.enter_trap(*trap_state, pc.val, instr);
} else { } else {
if (this->core.read(phys_addr_t(pc.access, pc.space, pc.val), 4, data) != iss::Ok) (*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::ICOUNT]))++;
return iss::Err; (*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::INSTRET]))++;
}
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::CYCLE]))++;
pc.val=*NEXT_PC;
return pc;
}
<%}%>
/****************************************************************************
* end opcode definitions
****************************************************************************/
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr) {
this->do_sync(PRE_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE));
uint32_t* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
uint32_t* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
*NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
raise(0, 2);
// post execution stuff
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE));
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
// trap check
if(*trap_state!=0){
super::core.enter_trap(*trap_state, pc.val, instr);
}
pc.val=*NEXT_PC;
return pc;
}
} static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK;
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
auto phys_pc = this->core.v2p(pc);
//if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
// if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err;
// if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction
// if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) return iss::Err;
//} else {
if (this->core.read(phys_pc, 4, data) != iss::Ok) return iss::Err;
//}
return iss::Ok; return iss::Ok;
} }
void populate_decoding_tree(decoding_tree_node* root){
//create submask
for(auto instr: root->instrs){
root->submask &= instr.mask;
}
//put each instr according to submask&encoding into children
for(auto instr: root->instrs){
bool foundMatch = false;
for(auto child: root->children){
//use value as identifying trait
if(child->value == (instr.value&root->submask)){
child->instrs.push_back(instr);
foundMatch = true;
}
}
if(!foundMatch){
decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
child->instrs.push_back(instr);
root->children.push_back(child);
}
}
root->instrs.clear();
//call populate_decoding_tree for all children
if(root->children.size() >1)
for(auto child: root->children){
populate_decoding_tree(child);
}
else{
//sort instrs by value of the mask, this works bc we want to have the least restrictive one last
std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
return instr1.mask > instr2.mask;
});
}
}
typename arch::traits<ARCH>::opcode_e decode_instr(decoding_tree_node* node, code_word_t word){
if(!node->children.size()){
if(node->instrs.size() == 1) return node->instrs[0].op;
for(auto instr : node->instrs){
if((instr.mask&word) == instr.value) return instr.op;
}
}
else{
for(auto child : node->children){
if (child->value == (node->submask&word)){
return decode_instr(child, word);
}
}
}
return arch::traits<ARCH>::opcode_e::MAX_OPCODE;
}
}; };
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) { template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
@ -261,11 +281,15 @@ constexpr size_t bit_count(uint32_t u) {
template <typename ARCH> template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) { : vm_base<ARCH>(core, core_id, cluster_id) {
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max()); for (auto instr : instr_descr) {
for(auto instr:instr_descr){ auto quadrant = instr.value & 0x3;
root->instrs.push_back(instr); qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op});
}
for(auto& lut: qlut){
std::sort(std::begin(lut), std::end(lut), [](instruction_pattern const& a, instruction_pattern const& b){
return bit_count(a.mask) > bit_count(b.mask);
});
} }
populate_decoding_tree(root);
} }
inline bool is_count_limit_enabled(finish_cond_e cond){ inline bool is_count_limit_enabled(finish_cond_e cond){
@ -277,76 +301,36 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){
} }
template <typename ARCH> template <typename ARCH>
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){ typename vm_impl<ARCH>::compile_func vm_impl<ARCH>::decode_inst(code_word_t instr){
auto pc=start; for(auto& e: qlut[instr&0x3]){
auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]); if(!((instr&e.mask) ^ e.value )) return e.opc;
auto* NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]); }
auto& trap_state = this->core.reg.trap_state; return &this_class::illegal_intruction;
auto& icount = this->core.reg.icount; }
auto& cycle = this->core.reg.cycle;
auto& instret = this->core.reg.instret;
auto& instr = this->core.reg.instruction;
// we fetch at max 4 byte, alignment is 2
auto *const data = reinterpret_cast<uint8_t*>(&instr);
template <typename ARCH>
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){
// we fetch at max 4 byte, alignment is 2
code_word_t insn = 0;
auto *const data = (uint8_t *)&insn;
auto pc=start;
while(!this->core.should_stop() && while(!this->core.should_stop() &&
!(is_count_limit_enabled(cond) && icount >= icount_limit)){ !(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){
if(fetch_ins(pc, data)!=iss::Ok){ auto res = fetch_ins(pc, data);
if(res!=iss::Ok){
this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max()); this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max());
pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0); pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0);
} else { } else {
if (is_jump_to_self_enabled(cond) && if (is_jump_to_self_enabled(cond) &&
(instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' (insn == 0x0000006f || (insn&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
auto inst_id = decode_instr(root, instr); auto f = decode_inst(insn);
// pre execution stuff pc = (this->*f)(pc, insn);
this->core.reg.last_branch = 0;
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
try{
switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %>
case arch::traits<ARCH>::opcode_e::${instr.name}: {
<%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){
/* generate console output when executing the command */<%instr.disass.eachLine{%>
${it}<%}%>
}
// used registers<%instr.usedVariables.each{ k,v->
if(v.isArray) {%>
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}0]);<% }else{ %>
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]);
<%}}%>// calculate next pc value
*NEXT_PC = *PC + ${instr.length/8};
// execute instruction<%instr.behavior.eachLine{%>
${it}<%}%>
break;
}// @suppress("No break at end of case")<%}%>
default: {
*NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
raise(0, 2);
}
}
}catch(memory_access_exception& e){}
// post execution stuff
process_spawn_blocks();
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(inst_id));
// if(!this->core.reg.trap_state) // update trap state if there is a pending interrupt
// this->core.reg.trap_state = this->core.reg.pending_trap;
// trap check
if(trap_state!=0){
super::core.enter_trap(trap_state, pc.val, instr);
} else {
icount++;
instret++;
}
cycle++;
pc.val=*NEXT_PC;
this->core.reg.PC = this->core.reg.NEXT_PC;
this->core.reg.trap_state = this->core.reg.pending_trap;
} }
} }
return pc; return pc;
} }
} // namespace ${coreDef.name.toLowerCase()} } // namespace mnrv32
template <> template <>
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) { std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
@ -356,34 +340,3 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
} }
} // namespace interp } // namespace interp
} // namespace iss } // namespace iss
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h>
#include <iss/factory.h>
namespace iss {
namespace {
volatile std::array<bool, 2> dummy = {
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};
}),
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};
})
};
}
}
// clang-format on

View File

@ -1,394 +0,0 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
// clang-format off
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/iss.h>
#include <iss/llvm/vm_base.h>
#include <util/logging.h>
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <fmt/format.h>
#include <array>
#include <iss/debugger/riscv_target_adapter.h>
namespace iss {
namespace llvm {
namespace fp_impl {
void add_fp_functions_2_module(::llvm::Module *, unsigned, unsigned);
}
namespace ${coreDef.name.toLowerCase()} {
using namespace ::llvm;
using namespace iss::arch;
using namespace iss::debugger;
template <typename ARCH> class vm_impl : public iss::llvm::vm_base<ARCH> {
public:
using traits = arch::traits<ARCH>;
using super = typename iss::llvm::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t;
using addr_t = typename super::addr_t;
vm_impl();
vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);
void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }
target_adapter_if *accquire_target_adapter(server_if *srv) override {
debugger_if::dbg_enabled = true;
if (vm_base<ARCH>::tgt_adapter == nullptr)
vm_base<ARCH>::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch());
return vm_base<ARCH>::tgt_adapter;
}
protected:
using vm_base<ARCH>::get_reg_ptr;
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
template <typename T> inline ConstantInt *size(T type) {
return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits()));
}
void setup_module(Module* m) override {
super::setup_module(m);
iss::llvm::fp_impl::add_fp_functions_2_module(m, traits::FP_REGS_SIZE, traits::XLEN);
}
inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) {
return super::gen_cond_assign(cond, this->gen_ext(trueVal, size), this->gen_ext(falseVal, size));
}
std::tuple<continuation_e, BasicBlock *> gen_single_inst_behavior(virt_addr_t &, unsigned int &, BasicBlock *) override;
void gen_leave_behavior(BasicBlock *leave_blk) override;
void gen_raise_trap(uint16_t trap_id, uint16_t cause);
void gen_leave_trap(unsigned lvl);
void gen_wait(unsigned type);
void gen_trap_behavior(BasicBlock *) override;
void gen_instr_epilogue(BasicBlock *bb);
inline Value *gen_reg_load(unsigned i, unsigned level = 0) {
return this->builder.CreateLoad(this->get_typeptr(i), get_reg_ptr(i), false);
}
inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) {
Value *next_pc_v = this->builder.CreateSExtOrTrunc(this->gen_const(traits::XLEN, pc.val),
this->get_type(traits::XLEN));
this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true);
}
// some compile time constants
using this_class = vm_impl<ARCH>;
using compile_func = std::tuple<continuation_e, BasicBlock *> (this_class::*)(virt_addr_t &pc,
code_word_t instr,
BasicBlock *bb);
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
inline S sext(U from) {
auto mask = (1ULL<<W) - 1;
auto sign_mask = 1ULL<<(W-1);
return (from & mask) | ((from & sign_mask) ? ~mask : 0);
}
private:
/****************************************************************************
* start opcode definitions
****************************************************************************/
struct instruction_descriptor {
size_t length;
uint32_t value;
uint32_t mask;
compile_func op;
};
struct decoding_tree_node{
std::vector<instruction_descriptor> instrs;
std::vector<decoding_tree_node*> children;
uint32_t submask = std::numeric_limits<uint32_t>::max();
uint32_t value;
decoding_tree_node(uint32_t value) : value(value){}
};
decoding_tree_node* root {nullptr};
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
}};
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
/* instruction ${idx}: ${instr.name} */
std::tuple<continuation_e, BasicBlock*> __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){
uint64_t PC = pc.val;
<%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){
/* generate console output when executing the command */<%instr.disass.eachLine{%>
${it}<%}%>
}
bb->setName(fmt::format("${instr.name}_0x{:X}",pc.val));
this->gen_sync(PRE_SYNC,${idx});
auto cur_pc_val = this->gen_const(32,pc.val);
pc=pc+ ${instr.length/8};
this->gen_set_pc(pc, traits::NEXT_PC);
/*generate behavior*/
<%instr.behavior.eachLine{%>${it}
<%}%>
this->gen_instr_epilogue(bb);
this->gen_sync(POST_SYNC, ${idx});
this->builder.CreateBr(bb);
return returnValue;
}
<%}%>
/****************************************************************************
* end opcode definitions
****************************************************************************/
std::tuple<continuation_e, BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) {
this->gen_sync(iss::PRE_SYNC, instr_descr.size());
this->builder.CreateStore(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), true),
get_reg_ptr(traits::PC), true);
this->builder.CreateStore(
this->builder.CreateAdd(this->builder.CreateLoad(this->get_typeptr(traits::ICOUNT), get_reg_ptr(traits::ICOUNT), true),
this->gen_const(64U, 1)),
get_reg_ptr(traits::ICOUNT), true);
pc = pc + ((instr & 3) == 3 ? 4 : 2);
this->gen_raise_trap(0, 2); // illegal instruction trap
this->gen_sync(iss::POST_SYNC, instr_descr.size());
this->gen_instr_epilogue(this->leave_blk);
return std::make_tuple(BRANCH, nullptr);
}
//decoding functionality
void populate_decoding_tree(decoding_tree_node* root){
//create submask
for(auto instr: root->instrs){
root->submask &= instr.mask;
}
//put each instr according to submask&encoding into children
for(auto instr: root->instrs){
bool foundMatch = false;
for(auto child: root->children){
//use value as identifying trait
if(child->value == (instr.value&root->submask)){
child->instrs.push_back(instr);
foundMatch = true;
}
}
if(!foundMatch){
decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
child->instrs.push_back(instr);
root->children.push_back(child);
}
}
root->instrs.clear();
//call populate_decoding_tree for all children
if(root->children.size() >1)
for(auto child: root->children){
populate_decoding_tree(child);
}
else{
//sort instrs by value of the mask, this works bc we want to have the least restrictive one last
std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
return instr1.mask > instr2.mask;
});
}
}
compile_func decode_instr(decoding_tree_node* node, code_word_t word){
if(!node->children.size()){
if(node->instrs.size() == 1) return node->instrs[0].op;
for(auto instr : node->instrs){
if((instr.mask&word) == instr.value) return instr.op;
}
}
else{
for(auto child : node->children){
if (child->value == (node->submask&word)){
return decode_instr(child, word);
}
}
}
return nullptr;
}
};
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
volatile CODE_WORD x = instr;
instr = 2 * x;
}
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) {
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
for(auto instr:instr_descr){
root->instrs.push_back(instr);
}
populate_decoding_tree(root);
}
template <typename ARCH>
std::tuple<continuation_e, BasicBlock *>
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, BasicBlock *this_block) {
// we fetch at max 4 byte, alignment is 2
enum {TRAP_ID=1<<16};
code_word_t instr = 0;
// const typename traits::addr_t upper_bits = ~traits::PGMASK;
phys_addr_t paddr(pc);
auto *const data = (uint8_t *)&instr;
if(this->core.has_mmu())
paddr = this->core.virt2phys(pc);
//TODO: re-add page handling
// if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
// auto res = this->core.read(paddr, 2, data);
// if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
// if ((instr & 0x3) == 0x3) { // this is a 32bit instruction
// res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
// }
// } else {
auto res = this->core.read(paddr, 4, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
// }
if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
// curr pc on stack
++inst_cnt;
auto f = decode_instr(root, instr);
if (f == nullptr) {
f = &this_class::illegal_intruction;
}
return (this->*f)(pc, instr, this_block);
}
template <typename ARCH>
void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) {
this->builder.SetInsertPoint(leave_blk);
this->builder.CreateRet(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC),get_reg_ptr(traits::NEXT_PC), false));
}
template <typename ARCH>
void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id);
this->builder.CreateStore(TRAP_val, get_reg_ptr(traits::TRAP_STATE), true);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits::LAST_BRANCH), false);
}
template <typename ARCH>
void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) };
this->builder.CreateCall(this->mod->getFunction("leave_trap"), args);
auto *PC_val = this->gen_read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN / 8);
this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits::LAST_BRANCH), false);
}
template <typename ARCH>
void vm_impl<ARCH>::gen_wait(unsigned type) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) };
this->builder.CreateCall(this->mod->getFunction("wait"), args);
}
template <typename ARCH>
void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) {
this->builder.SetInsertPoint(trap_blk);
this->gen_sync(POST_SYNC, -1); //TODO get right InstrId
auto *trap_state_val = this->builder.CreateLoad(this->get_typeptr(traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()),
get_reg_ptr(traits::LAST_BRANCH), false);
std::vector<Value *> args{this->core_ptr, this->adj_to64(trap_state_val),
this->adj_to64(this->builder.CreateLoad(this->get_typeptr(traits::PC), get_reg_ptr(traits::PC), false))};
this->builder.CreateCall(this->mod->getFunction("enter_trap"), args);
auto *trap_addr_val = this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), false);
this->builder.CreateRet(trap_addr_val);
}
template <typename ARCH>
void vm_impl<ARCH>::gen_instr_epilogue(BasicBlock *bb) {
auto* target_bb = BasicBlock::Create(this->mod->getContext(), "", this->func, bb);
auto *v = this->builder.CreateLoad(this->get_typeptr(traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true);
this->gen_cond_branch(this->builder.CreateICmp(
ICmpInst::ICMP_EQ, v,
ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))),
target_bb, this->trap_blk, 1);
this->builder.SetInsertPoint(target_bb);
}
} // namespace ${coreDef.name.toLowerCase()}
template <>
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
auto ret = new ${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*core, dump);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret);
}
} // namespace llvm
} // namespace iss
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h>
#include <iss/factory.h>
namespace iss {
namespace {
volatile std::array<bool, 2> dummy = {
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|llvm", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*)>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};
}),
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|llvm", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*)>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};
})
};
}
}
// clang-format on

View File

@ -0,0 +1,9 @@
{
"${coreDef.name}" : [<%instructions.eachWithIndex{instr,index -> %>${index==0?"":","}
{
"name" : "${instr.name}",
"size" : ${instr.length},
"delay" : ${generator.hasAttribute(instr.instruction, com.minres.coredsl.coreDsl.InstrAttribute.COND)?[1,1]:1}
}<%}%>
]
}

View File

@ -0,0 +1,223 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
<%
import com.minres.coredsl.coreDsl.Register
import com.minres.coredsl.coreDsl.RegisterFile
import com.minres.coredsl.coreDsl.RegisterAlias
def getTypeSize(size){
if(size > 32) 64 else if(size > 16) 32 else if(size > 8) 16 else 8
}
def getOriginalName(reg){
if( reg.original instanceof RegisterFile) {
if( reg.index != null ) {
return reg.original.name+generator.generateHostCode(reg.index)
} else {
return reg.original.name
}
} else if(reg.original instanceof Register){
return reg.original.name
}
}
def getRegisterNames(){
def regNames = []
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{
regNames+=reg.name.toLowerCase()+it
}
} else if(reg instanceof Register){
regNames+=reg.name.toLowerCase()
}
}
return regNames
}
def getRegisterAliasNames(){
def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
if( reg instanceof RegisterFile) {
return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
} else if(reg instanceof Register){
regMap[reg.name]?:reg.name.toLowerCase()
}
}.flatten()
}
%>
#ifndef _${coreDef.name.toUpperCase()}_H_
#define _${coreDef.name.toUpperCase()}_H_
#include <array>
#include <iss/arch/traits.h>
#include <iss/arch_if.h>
#include <iss/vm_if.h>
namespace iss {
namespace arch {
struct ${coreDef.name.toLowerCase()};
template <> struct traits<${coreDef.name.toLowerCase()}> {
constexpr static char const* const core_type = "${coreDef.name}";
static constexpr std::array<const char*, ${getRegisterNames().size}> reg_names{
{"${getRegisterNames().join("\", \"")}"}};
static constexpr std::array<const char*, ${getRegisterAliasNames().size}> reg_aliases{
{"${getRegisterAliasNames().join("\", \"")}"}};
enum constants {${coreDef.constants.collect{c -> c.name+"="+c.value}.join(', ')}};
constexpr static unsigned FP_REGS_SIZE = ${coreDef.constants.find {it.name=='FLEN'}?.value?:0};
enum reg_e {<%
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{%>
${reg.name}${it},<%
}
} else if(reg instanceof Register){ %>
${reg.name},<%
}
}%>
NUM_REGS,
NEXT_${pc.name}=NUM_REGS,
TRAP_STATE,
PENDING_TRAP,
MACHINE_STATE,
LAST_BRANCH,
ICOUNT<%
allRegs.each { reg ->
if(reg instanceof RegisterAlias){ def aliasname=getOriginalName(reg)%>,
${reg.name} = ${aliasname}<%
}
}%>
};
using reg_t = uint${regDataWidth}_t;
using addr_t = uint${addrDataWidth}_t;
using code_word_t = uint${addrDataWidth}_t; //TODO: check removal
using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, ${regSizes.size}> reg_bit_widths{
{${regSizes.join(",")}}};
static constexpr std::array<const uint32_t, ${regOffsets.size}> reg_byte_offsets{
{${regOffsets.join(",")}}};
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
enum sreg_flag_e { FLAGS };
enum mem_type_e { ${allSpaces.collect{s -> s.name}.join(', ')} };
};
struct ${coreDef.name.toLowerCase()}: public arch_if {
using virt_addr_t = typename traits<${coreDef.name.toLowerCase()}>::virt_addr_t;
using phys_addr_t = typename traits<${coreDef.name.toLowerCase()}>::phys_addr_t;
using reg_t = typename traits<${coreDef.name.toLowerCase()}>::reg_t;
using addr_t = typename traits<${coreDef.name.toLowerCase()}>::addr_t;
${coreDef.name.toLowerCase()}();
~${coreDef.name.toLowerCase()}();
void reset(uint64_t address=0) override;
uint8_t* get_regs_base_ptr() override;
/// deprecated
void get_reg(short idx, std::vector<uint8_t>& value) override {}
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
/// deprecated
bool get_flag(int flag) override {return false;}
void set_flag(int, bool value) override {};
/// deprecated
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; }
inline uint64_t stop_code() { return interrupt_sim; }
inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<${coreDef.name.toLowerCase()}>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<${coreDef.name.toLowerCase()}>::addr_mask);
} else
return virt2phys(addr);
}
virtual phys_addr_t virt2phys(const iss::addr_t& addr);
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
inline uint32_t get_last_branch() { return reg.last_branch; }
protected:
struct ${coreDef.name}_regs {<%
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{%>
uint${generator.getSize(reg)}_t ${reg.name}${it} = 0;<%
}
} else if(reg instanceof Register){ %>
uint${generator.getSize(reg)}_t ${reg.name} = 0;<%
}
}%>
uint${generator.getSize(pc)}_t NEXT_${pc.name} = 0;
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
uint64_t icount = 0;
} reg;
std::array<address_type, 4> addr_mode;
uint64_t interrupt_sim=0;
<%
def fcsr = allRegs.find {it.name=='FCSR'}
if(fcsr != null) {%>
uint${generator.getSize(fcsr)}_t get_fcsr(){return reg.FCSR;}
void set_fcsr(uint${generator.getSize(fcsr)}_t val){reg.FCSR = val;}
<%} else { %>
uint32_t get_fcsr(){return 0;}
void set_fcsr(uint32_t val){}
<%}%>
};
}
}
#endif /* _${coreDef.name.toUpperCase()}_H_ */

View File

@ -0,0 +1,107 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
<%
import com.minres.coredsl.coreDsl.Register
import com.minres.coredsl.coreDsl.RegisterFile
import com.minres.coredsl.coreDsl.RegisterAlias
def getOriginalName(reg){
if( reg.original instanceof RegisterFile) {
if( reg.index != null ) {
return reg.original.name+generator.generateHostCode(reg.index)
} else {
return reg.original.name
}
} else if(reg.original instanceof Register){
return reg.original.name
}
}
def getRegisterNames(){
def regNames = []
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{
regNames+=reg.name.toLowerCase()+it
}
} else if(reg instanceof Register){
regNames+=reg.name.toLowerCase()
}
}
return regNames
}
def getRegisterAliasNames(){
def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
if( reg instanceof RegisterFile) {
return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
} else if(reg instanceof Register){
regMap[reg.name]?:reg.name.toLowerCase()
}
}.flatten()
}
%>
#include "util/ities.h"
#include <util/logging.h>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <cstdio>
#include <cstring>
#include <fstream>
using namespace iss::arch;
constexpr std::array<const char*, ${getRegisterNames().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_names;
constexpr std::array<const char*, ${getRegisterAliasNames().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases;
constexpr std::array<const uint32_t, ${regSizes.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
constexpr std::array<const uint32_t, ${regOffsets.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
reg.icount = 0;
}
${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default;
void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
for(size_t i=0; i<traits<${coreDef.name.toLowerCase()}>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<${coreDef.name.toLowerCase()}>::reg_t),0));
reg.PC=address;
reg.NEXT_PC=reg.PC;
reg.trap_state=0;
reg.machine_state=0x3;
reg.icount=0;
}
uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
return reinterpret_cast<uint8_t*>(&reg);
}
${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(pc); // change logical address to physical address
}

View File

@ -0,0 +1,325 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/iss.h>
#include <iss/llvm/vm_base.h>
#include <util/logging.h>
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <fmt/format.h>
#include <array>
#include <iss/debugger/riscv_target_adapter.h>
namespace iss {
namespace llvm {
namespace fp_impl {
void add_fp_functions_2_module(::llvm::Module *, unsigned, unsigned);
}
namespace ${coreDef.name.toLowerCase()} {
using namespace ::llvm;
using namespace iss::arch;
using namespace iss::debugger;
template <typename ARCH> class vm_impl : public iss::llvm::vm_base<ARCH> {
public:
using super = typename iss::llvm::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t;
using addr_t = typename super::addr_t;
vm_impl();
vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);
void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }
target_adapter_if *accquire_target_adapter(server_if *srv) override {
debugger_if::dbg_enabled = true;
if (vm_base<ARCH>::tgt_adapter == nullptr)
vm_base<ARCH>::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch());
return vm_base<ARCH>::tgt_adapter;
}
protected:
using vm_base<ARCH>::get_reg_ptr;
inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}
template <typename T> inline ConstantInt *size(T type) {
return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits()));
}
void setup_module(Module* m) override {
super::setup_module(m);
iss::llvm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
}
inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) {
return super::gen_cond_assign(cond, this->gen_ext(trueVal, size), this->gen_ext(falseVal, size));
}
std::tuple<continuation_e, BasicBlock *> gen_single_inst_behavior(virt_addr_t &, unsigned int &, BasicBlock *) override;
void gen_leave_behavior(BasicBlock *leave_blk) override;
void gen_raise_trap(uint16_t trap_id, uint16_t cause);
void gen_leave_trap(unsigned lvl);
void gen_wait(unsigned type);
void gen_trap_behavior(BasicBlock *) override;
void gen_trap_check(BasicBlock *bb);
inline Value *gen_reg_load(unsigned i, unsigned level = 0) {
return this->builder.CreateLoad(get_reg_ptr(i), false);
}
inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) {
Value *next_pc_v = this->builder.CreateSExtOrTrunc(this->gen_const(traits<ARCH>::XLEN, pc.val),
this->get_type(traits<ARCH>::XLEN));
this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true);
}
// some compile time constants
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) };
using this_class = vm_impl<ARCH>;
using compile_func = std::tuple<continuation_e, BasicBlock *> (this_class::*)(virt_addr_t &pc,
code_word_t instr,
BasicBlock *bb);
std::array<compile_func, LUT_SIZE> lut;
std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10;
std::array<compile_func, LUT_SIZE> lut_11;
std::array<compile_func *, 4> qlut;
std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}};
void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[],
compile_func f) {
if (pos < 0) {
lut[idx] = f;
} else {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f);
} else {
if ((valid & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f);
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f);
} else {
auto new_val = idx << 1;
if ((value & bitmask) != 0) new_val++;
expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f);
}
}
}
}
inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); }
uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) {
if (pos >= 0) {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
lut_val = extract_fields(pos - 1, val, mask, lut_val);
} else {
auto new_val = lut_val << 1;
if ((val & bitmask) != 0) new_val++;
lut_val = extract_fields(pos - 1, val, mask, new_val);
}
}
return lut_val;
}
private:
/****************************************************************************
* start opcode definitions
****************************************************************************/
struct InstructionDesriptor {
size_t length;
uint32_t value;
uint32_t mask;
compile_func op;
};
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
/* instruction ${instr.instruction.name} */
{${instr.length}, ${instr.value}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
}};
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
/* instruction ${idx}: ${instr.name} */
std::tuple<continuation_e, BasicBlock*> __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){<%instr.code.eachLine{%>
${it}<%}%>
}
<%}%>
/****************************************************************************
* end opcode definitions
****************************************************************************/
std::tuple<continuation_e, BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) {
this->gen_sync(iss::PRE_SYNC, instr_descr.size());
this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true),
get_reg_ptr(traits<ARCH>::PC), true);
this->builder.CreateStore(
this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true),
this->gen_const(64U, 1)),
get_reg_ptr(traits<ARCH>::ICOUNT), true);
pc = pc + ((instr & 3) == 3 ? 4 : 2);
this->gen_raise_trap(0, 2); // illegal instruction trap
this->gen_sync(iss::POST_SYNC, instr_descr.size());
this->gen_trap_check(this->leave_blk);
return std::make_tuple(BRANCH, nullptr);
}
};
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
volatile CODE_WORD x = insn;
insn = 2 * x;
}
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) {
qlut[0] = lut_00.data();
qlut[1] = lut_01.data();
qlut[2] = lut_10.data();
qlut[3] = lut_11.data();
for (auto instr : instr_descr) {
auto quantrant = instr.value & 0x3;
expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op);
}
}
template <typename ARCH>
std::tuple<continuation_e, BasicBlock *>
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, BasicBlock *this_block) {
// we fetch at max 4 byte, alignment is 2
enum {TRAP_ID=1<<16};
code_word_t insn = 0;
const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK;
phys_addr_t paddr(pc);
auto *const data = (uint8_t *)&insn;
paddr = this->core.v2p(pc);
if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
auto res = this->core.read(paddr, 2, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
if ((insn & 0x3) == 0x3) { // this is a 32bit instruction
res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
}
} else {
auto res = this->core.read(paddr, 4, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
}
if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
// curr pc on stack
++inst_cnt;
auto lut_val = extract_fields(insn);
auto f = qlut[insn & 0x3][lut_val];
if (f == nullptr) {
f = &this_class::illegal_intruction;
}
return (this->*f)(pc, insn, this_block);
}
template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) {
this->builder.SetInsertPoint(leave_blk);
this->builder.CreateRet(this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::NEXT_PC), false));
}
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id);
this->builder.CreateStore(TRAP_val, get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
}
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) };
this->builder.CreateCall(this->mod->getFunction("leave_trap"), args);
auto *PC_val = this->gen_read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN / 8);
this->builder.CreateStore(PC_val, get_reg_ptr(traits<ARCH>::NEXT_PC), false);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
}
template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) };
this->builder.CreateCall(this->mod->getFunction("wait"), args);
}
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) {
this->builder.SetInsertPoint(trap_blk);
auto *trap_state_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()),
get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
std::vector<Value *> args{this->core_ptr, this->adj_to64(trap_state_val),
this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::PC), false))};
this->builder.CreateCall(this->mod->getFunction("enter_trap"), args);
auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), false);
this->builder.CreateRet(trap_addr_val);
}
template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *bb) {
auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::TRAP_STATE), true);
this->gen_cond_branch(this->builder.CreateICmp(
ICmpInst::ICMP_EQ, v,
ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))),
bb, this->trap_blk, 1);
}
} // namespace ${coreDef.name.toLowerCase()}
template <>
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
auto ret = new ${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*core, dump);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret);
}
} // namespace llvm
} // namespace iss

View File

@ -0,0 +1,9 @@
{
"${coreDef.name}" : [<%instructions.eachWithIndex{instr,index -> %>${index==0?"":","}
{
"name" : "${instr.name}",
"size" : ${instr.length},
"delay" : ${generator.hasAttribute(instr.instruction, com.minres.coredsl.coreDsl.InstrAttribute.COND)?[1,1]:1}
}<%}%>
]
}

View File

@ -0,0 +1,223 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
<%
import com.minres.coredsl.coreDsl.Register
import com.minres.coredsl.coreDsl.RegisterFile
import com.minres.coredsl.coreDsl.RegisterAlias
def getTypeSize(size){
if(size > 32) 64 else if(size > 16) 32 else if(size > 8) 16 else 8
}
def getOriginalName(reg){
if( reg.original instanceof RegisterFile) {
if( reg.index != null ) {
return reg.original.name+generator.generateHostCode(reg.index)
} else {
return reg.original.name
}
} else if(reg.original instanceof Register){
return reg.original.name
}
}
def getRegisterNames(){
def regNames = []
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{
regNames+=reg.name.toLowerCase()+it
}
} else if(reg instanceof Register){
regNames+=reg.name.toLowerCase()
}
}
return regNames
}
def getRegisterAliasNames(){
def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
if( reg instanceof RegisterFile) {
return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
} else if(reg instanceof Register){
regMap[reg.name]?:reg.name.toLowerCase()
}
}.flatten()
}
%>
#ifndef _${coreDef.name.toUpperCase()}_H_
#define _${coreDef.name.toUpperCase()}_H_
#include <array>
#include <iss/arch/traits.h>
#include <iss/arch_if.h>
#include <iss/vm_if.h>
namespace iss {
namespace arch {
struct ${coreDef.name.toLowerCase()};
template <> struct traits<${coreDef.name.toLowerCase()}> {
constexpr static char const* const core_type = "${coreDef.name}";
static constexpr std::array<const char*, ${getRegisterNames().size}> reg_names{
{"${getRegisterNames().join("\", \"")}"}};
static constexpr std::array<const char*, ${getRegisterAliasNames().size}> reg_aliases{
{"${getRegisterAliasNames().join("\", \"")}"}};
enum constants {${coreDef.constants.collect{c -> c.name+"="+c.value}.join(', ')}};
constexpr static unsigned FP_REGS_SIZE = ${coreDef.constants.find {it.name=='FLEN'}?.value?:0};
enum reg_e {<%
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{%>
${reg.name}${it},<%
}
} else if(reg instanceof Register){ %>
${reg.name},<%
}
}%>
NUM_REGS,
NEXT_${pc.name}=NUM_REGS,
TRAP_STATE,
PENDING_TRAP,
MACHINE_STATE,
LAST_BRANCH,
ICOUNT<%
allRegs.each { reg ->
if(reg instanceof RegisterAlias){ def aliasname=getOriginalName(reg)%>,
${reg.name} = ${aliasname}<%
}
}%>
};
using reg_t = uint${regDataWidth}_t;
using addr_t = uint${addrDataWidth}_t;
using code_word_t = uint${addrDataWidth}_t; //TODO: check removal
using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, ${regSizes.size}> reg_bit_widths{
{${regSizes.join(",")}}};
static constexpr std::array<const uint32_t, ${regOffsets.size}> reg_byte_offsets{
{${regOffsets.join(",")}}};
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
enum sreg_flag_e { FLAGS };
enum mem_type_e { ${allSpaces.collect{s -> s.name}.join(', ')} };
};
struct ${coreDef.name.toLowerCase()}: public arch_if {
using virt_addr_t = typename traits<${coreDef.name.toLowerCase()}>::virt_addr_t;
using phys_addr_t = typename traits<${coreDef.name.toLowerCase()}>::phys_addr_t;
using reg_t = typename traits<${coreDef.name.toLowerCase()}>::reg_t;
using addr_t = typename traits<${coreDef.name.toLowerCase()}>::addr_t;
${coreDef.name.toLowerCase()}();
~${coreDef.name.toLowerCase()}();
void reset(uint64_t address=0) override;
uint8_t* get_regs_base_ptr() override;
/// deprecated
void get_reg(short idx, std::vector<uint8_t>& value) override {}
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
/// deprecated
bool get_flag(int flag) override {return false;}
void set_flag(int, bool value) override {};
/// deprecated
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; }
inline uint64_t stop_code() { return interrupt_sim; }
inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<${coreDef.name.toLowerCase()}>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<${coreDef.name.toLowerCase()}>::addr_mask);
} else
return virt2phys(addr);
}
virtual phys_addr_t virt2phys(const iss::addr_t& addr);
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
inline uint32_t get_last_branch() { return reg.last_branch; }
protected:
struct ${coreDef.name}_regs {<%
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{%>
uint${generator.getSize(reg)}_t ${reg.name}${it} = 0;<%
}
} else if(reg instanceof Register){ %>
uint${generator.getSize(reg)}_t ${reg.name} = 0;<%
}
}%>
uint${generator.getSize(pc)}_t NEXT_${pc.name} = 0;
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
uint64_t icount = 0;
} reg;
std::array<address_type, 4> addr_mode;
uint64_t interrupt_sim=0;
<%
def fcsr = allRegs.find {it.name=='FCSR'}
if(fcsr != null) {%>
uint${generator.getSize(fcsr)}_t get_fcsr(){return reg.FCSR;}
void set_fcsr(uint${generator.getSize(fcsr)}_t val){reg.FCSR = val;}
<%} else { %>
uint32_t get_fcsr(){return 0;}
void set_fcsr(uint32_t val){}
<%}%>
};
}
}
#endif /* _${coreDef.name.toUpperCase()}_H_ */

View File

@ -0,0 +1,107 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
<%
import com.minres.coredsl.coreDsl.Register
import com.minres.coredsl.coreDsl.RegisterFile
import com.minres.coredsl.coreDsl.RegisterAlias
def getOriginalName(reg){
if( reg.original instanceof RegisterFile) {
if( reg.index != null ) {
return reg.original.name+generator.generateHostCode(reg.index)
} else {
return reg.original.name
}
} else if(reg.original instanceof Register){
return reg.original.name
}
}
def getRegisterNames(){
def regNames = []
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{
regNames+=reg.name.toLowerCase()+it
}
} else if(reg instanceof Register){
regNames+=reg.name.toLowerCase()
}
}
return regNames
}
def getRegisterAliasNames(){
def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
if( reg instanceof RegisterFile) {
return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
} else if(reg instanceof Register){
regMap[reg.name]?:reg.name.toLowerCase()
}
}.flatten()
}
%>
#include "util/ities.h"
#include <util/logging.h>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <cstdio>
#include <cstring>
#include <fstream>
using namespace iss::arch;
constexpr std::array<const char*, ${getRegisterNames().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_names;
constexpr std::array<const char*, ${getRegisterAliasNames().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases;
constexpr std::array<const uint32_t, ${regSizes.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
constexpr std::array<const uint32_t, ${regOffsets.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
reg.icount = 0;
}
${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default;
void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
for(size_t i=0; i<traits<${coreDef.name.toLowerCase()}>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<${coreDef.name.toLowerCase()}>::reg_t),0));
reg.PC=address;
reg.NEXT_PC=reg.PC;
reg.trap_state=0;
reg.machine_state=0x3;
reg.icount=0;
}
uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
return reinterpret_cast<uint8_t*>(&reg);
}
${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(pc); // change logical address to physical address
}

View File

@ -29,8 +29,9 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
* *
*******************************************************************************/ *******************************************************************************/
// clang-format off
#include <iss/arch/${coreDef.name.toLowerCase()}.h> #include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/debugger/gdb_session.h> #include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h> #include <iss/debugger/server.h>
#include <iss/iss.h> #include <iss/iss.h>
@ -54,12 +55,10 @@ using namespace iss::debugger;
template <typename ARCH> class vm_impl : public iss::tcc::vm_base<ARCH> { template <typename ARCH> class vm_impl : public iss::tcc::vm_base<ARCH> {
public: public:
using traits = arch::traits<ARCH>;
using super = typename iss::tcc::vm_base<ARCH>; using super = typename iss::tcc::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t; using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t; using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t; using code_word_t = typename super::code_word_t;
using mem_type_e = typename traits::mem_type_e;
using addr_t = typename super::addr_t; using addr_t = typename super::addr_t;
using tu_builder = typename super::tu_builder; using tu_builder = typename super::tu_builder;
@ -83,7 +82,7 @@ protected:
using compile_ret_t = std::tuple<continuation_e>; using compile_ret_t = std::tuple<continuation_e>;
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&); using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&);
inline const char *name(size_t index){return traits::reg_aliases.at(index);} inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}
void setup_module(std::string m) override { void setup_module(std::string m) override {
super::setup_module(m); super::setup_module(m);
@ -105,10 +104,10 @@ protected:
inline void gen_set_pc(tu_builder& tu, virt_addr_t pc, unsigned reg_num) { inline void gen_set_pc(tu_builder& tu, virt_addr_t pc, unsigned reg_num) {
switch(reg_num){ switch(reg_num){
case traits::NEXT_PC: case traits<ARCH>::NEXT_PC:
tu("*next_pc = {:#x};", pc.val); tu("*next_pc = {:#x};", pc.val);
break; break;
case traits::PC: case traits<ARCH>::PC:
tu("*pc = {:#x};", pc.val); tu("*pc = {:#x};", pc.val);
break; break;
default: default:
@ -120,61 +119,79 @@ protected:
} }
} }
// some compile time constants
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type> // enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
inline S sext(U from) { enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
auto mask = (1ULL<<W) - 1; enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
auto sign_mask = 1ULL<<(W-1); enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) };
return (from & mask) | ((from & sign_mask) ? ~mask : 0);
} std::array<compile_func, LUT_SIZE> lut;
std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10;
std::array<compile_func, LUT_SIZE> lut_11;
std::array<compile_func *, 4> qlut;
std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}};
void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[],
compile_func f) {
if (pos < 0) {
lut[idx] = f;
} else {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f);
} else {
if ((valid & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f);
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f);
} else {
auto new_val = idx << 1;
if ((value & bitmask) != 0) new_val++;
expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f);
}
}
}
}
inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); }
uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) {
if (pos >= 0) {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
lut_val = extract_fields(pos - 1, val, mask, lut_val);
} else {
auto new_val = lut_val << 1;
if ((val & bitmask) != 0) new_val++;
lut_val = extract_fields(pos - 1, val, mask, new_val);
}
}
return lut_val;
}
private: private:
/**************************************************************************** /****************************************************************************
* start opcode definitions * start opcode definitions
****************************************************************************/ ****************************************************************************/
struct instruction_descriptor { struct InstructionDesriptor {
size_t length; size_t length;
uint32_t value; uint32_t value;
uint32_t mask; uint32_t mask;
compile_func op; compile_func op;
}; };
struct decoding_tree_node{
std::vector<instruction_descriptor> instrs;
std::vector<decoding_tree_node*> children;
uint32_t submask = std::numeric_limits<uint32_t>::max();
uint32_t value;
decoding_tree_node(uint32_t value) : value(value){}
};
decoding_tree_node* root {nullptr}; const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */ /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%> {${instr.length}, 0b${instr.value}, 0b${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
}}; }};
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %> /* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
/* instruction ${idx}: ${instr.name} */ /* instruction ${idx}: ${instr.name} */
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){<%instr.code.eachLine{%>
tu("${instr.name}_{:#010x}:", pc.val); ${it}<%}%>
vm_base<ARCH>::gen_sync(tu, PRE_SYNC,${idx});
uint64_t PC = pc.val;
<%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){
/* generate console output when executing the command */<%instr.disass.eachLine{%>
${it}<%}%>
}
auto cur_pc_val = tu.constant(pc.val, traits::reg_bit_widths[traits::PC]);
pc=pc+ ${instr.length/8};
gen_set_pc(tu, pc, traits::NEXT_PC);
tu.open_scope();
<%instr.behavior.eachLine{%>${it}
<%}%>
tu.close_scope();
gen_trap_check(tu);
vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
return returnValue;
} }
<%}%> <%}%>
/**************************************************************************** /****************************************************************************
@ -188,64 +205,11 @@ private:
vm_impl::gen_trap_check(tu); vm_impl::gen_trap_check(tu);
return BRANCH; return BRANCH;
} }
//decoding functionality
void populate_decoding_tree(decoding_tree_node* root){
//create submask
for(auto instr: root->instrs){
root->submask &= instr.mask;
}
//put each instr according to submask&encoding into children
for(auto instr: root->instrs){
bool foundMatch = false;
for(auto child: root->children){
//use value as identifying trait
if(child->value == (instr.value&root->submask)){
child->instrs.push_back(instr);
foundMatch = true;
}
}
if(!foundMatch){
decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
child->instrs.push_back(instr);
root->children.push_back(child);
}
}
root->instrs.clear();
//call populate_decoding_tree for all children
if(root->children.size() >1)
for(auto child: root->children){
populate_decoding_tree(child);
}
else{
//sort instrs by value of the mask, this works bc we want to have the least restrictive one last
std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
return instr1.mask > instr2.mask;
});
}
}
compile_func decode_instr(decoding_tree_node* node, code_word_t word){
if(!node->children.size()){
if(node->instrs.size() == 1) return node->instrs[0].op;
for(auto instr : node->instrs){
if((instr.mask&word) == instr.value) return instr.op;
}
}
else{
for(auto child : node->children){
if (child->value == (node->submask&word)){
return decode_instr(child, word);
}
}
}
return nullptr;
}
}; };
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) { template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
volatile CODE_WORD x = instr; volatile CODE_WORD x = insn;
instr = 2 * x; insn = 2 * x;
} }
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); } template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
@ -253,11 +217,14 @@ template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
template <typename ARCH> template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) { : vm_base<ARCH>(core, core_id, cluster_id) {
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max()); qlut[0] = lut_00.data();
for(auto instr:instr_descr){ qlut[1] = lut_01.data();
root->instrs.push_back(instr); qlut[2] = lut_10.data();
qlut[3] = lut_11.data();
for (auto instr : instr_descr) {
auto quantrant = instr.value & 0x3;
expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op);
} }
populate_decoding_tree(root);
} }
template <typename ARCH> template <typename ARCH>
@ -265,40 +232,41 @@ std::tuple<continuation_e>
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) { vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) {
// we fetch at max 4 byte, alignment is 2 // we fetch at max 4 byte, alignment is 2
enum {TRAP_ID=1<<16}; enum {TRAP_ID=1<<16};
code_word_t instr = 0; code_word_t insn = 0;
const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK;
phys_addr_t paddr(pc); phys_addr_t paddr(pc);
if(this->core.has_mmu()) auto *const data = (uint8_t *)&insn;
paddr = this->core.virt2phys(pc); paddr = this->core.v2p(pc);
//TODO: re-add page handling if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
// if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary auto res = this->core.read(paddr, 2, data);
// auto res = this->core.read(paddr, 2, data);
// if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
// if ((insn & 0x3) == 0x3) { // this is a 32bit instruction
// res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
// }
// } else {
auto res = this->core.read(paddr, 4, reinterpret_cast<uint8_t*>(&instr));
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
// } if ((insn & 0x3) == 0x3) { // this is a 32bit instruction
if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
}
} else {
auto res = this->core.read(paddr, 4, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
}
if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
// curr pc on stack // curr pc on stack
++inst_cnt; ++inst_cnt;
auto f = decode_instr(root, instr); auto lut_val = extract_fields(insn);
auto f = qlut[insn & 0x3][lut_val];
if (f == nullptr) { if (f == nullptr) {
f = &this_class::illegal_intruction; f = &this_class::illegal_intruction;
} }
return (this->*f)(pc, instr, tu); return (this->*f)(pc, insn, tu);
} }
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) { template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id); tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id);
tu.store(traits::NEXT_PC, tu.constant(std::numeric_limits<uint32_t>::max(), 32)); tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
} }
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) { template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) {
tu("leave_trap(core_ptr, {});", lvl); tu("leave_trap(core_ptr, {});", lvl);
tu.store(traits::NEXT_PC, tu.read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN)); tu.store(tu.read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN),traits<ARCH>::NEXT_PC);
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32)); tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
} }
template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) { template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) {
@ -306,13 +274,12 @@ template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned t
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) { template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
tu("trap_entry:"); tu("trap_entry:");
this->gen_sync(tu, POST_SYNC, -1); tu("enter_trap(core_ptr, *trap_state, *pc);");
tu("enter_trap(core_ptr, *trap_state, *pc, 0);"); tu.store(tu.constant(std::numeric_limits<uint32_t>::max(),32),traits<ARCH>::LAST_BRANCH);
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(),32));
tu("return *next_pc;"); tu("return *next_pc;");
} }
} // namespace ${coreDef.name.toLowerCase()} } // namespace mnrv32
template <> template <>
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) { std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
@ -320,36 +287,5 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port); if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret); return std::unique_ptr<vm_if>(ret);
} }
} // namesapce tcc }
} // namespace iss } // namespace iss
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h>
#include <iss/factory.h>
namespace iss {
namespace {
volatile std::array<bool, 2> dummy = {
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t)>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};
}),
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t)>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};
})
};
}
}
// clang-format on

1
incl/iss/arch/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/tgc_*.h

View File

@ -35,40 +35,26 @@
#ifndef _RISCV_HART_COMMON #ifndef _RISCV_HART_COMMON
#define _RISCV_HART_COMMON #define _RISCV_HART_COMMON
#include "iss/arch_if.h"
#include <cstdint> #include <cstdint>
#include <elfio/elfio.hpp>
#include <fmt/format.h>
#include <iss/arch_if.h>
#include <iss/log_categories.h>
#include <string>
#include <unordered_map>
#include <util/logging.h>
namespace iss { namespace iss {
namespace arch { namespace arch {
enum { tohost_dflt = 0xF0001000, fromhost_dflt = 0xF0001040 }; enum { tohost_dflt = 0xF0001000, fromhost_dflt = 0xF0001040 };
enum features_e { FEAT_NONE, FEAT_PMP = 1, FEAT_EXT_N = 2, FEAT_CLIC = 4, FEAT_DEBUG = 8, FEAT_TCM = 16 };
enum riscv_csr { enum riscv_csr {
/* user-level CSR */ /* user-level CSR */
// User Trap Setup // User Trap Setup
ustatus = 0x000, ustatus = 0x000,
uie = 0x004, uie = 0x004,
utvec = 0x005, utvec = 0x005,
utvt = 0x007, // CLIC
// User Trap Handling // User Trap Handling
uscratch = 0x040, uscratch = 0x040,
uepc = 0x041, uepc = 0x041,
ucause = 0x042, ucause = 0x042,
utval = 0x043, utval = 0x043,
uip = 0x044, uip = 0x044,
uxnti = 0x045, // CLIC
uintstatus = 0xCB1, // MRW Current interrupt levels (CLIC) - addr subject to change
uintthresh = 0x047, // MRW Interrupt-level threshold (CLIC) - addr subject to change
uscratchcsw = 0x048, // MRW Conditional scratch swap on priv mode change (CLIC)
uscratchcswl = 0x049, // MRW Conditional scratch swap on level change (CLIC)
// User Floating-Point CSRs // User Floating-Point CSRs
fflags = 0x001, fflags = 0x001,
frm = 0x002, frm = 0x002,
@ -118,18 +104,19 @@ enum riscv_csr {
mie = 0x304, mie = 0x304,
mtvec = 0x305, mtvec = 0x305,
mcounteren = 0x306, mcounteren = 0x306,
mtvt = 0x307, // CLIC mtvt = 0x307, //CLIC
// Machine Trap Handling // Machine Trap Handling
mscratch = 0x340, mscratch = 0x340,
mepc = 0x341, mepc = 0x341,
mcause = 0x342, mcause = 0x342,
mtval = 0x343, mtval = 0x343,
mip = 0x344, mip = 0x344,
mxnti = 0x345, // CLIC mxnti = 0x345, //CLIC
mintstatus = 0xFB1, // MRW Current interrupt levels (CLIC) - addr subject to change mintstatus = 0x346, // MRW Current interrupt levels (CLIC) - addr subject to change
mintthresh = 0x347, // MRW Interrupt-level threshold (CLIC) - addr subject to change mscratchcsw = 0x348, // MRW Conditional scratch swap on priv mode change (CLIC)
mscratchcsw = 0x348, // MRW Conditional scratch swap on priv mode change (CLIC)
mscratchcswl = 0x349, // MRW Conditional scratch swap on level change (CLIC) mscratchcswl = 0x349, // MRW Conditional scratch swap on level change (CLIC)
mintthresh = 0x350, // MRW Interrupt-level threshold (CLIC) - addr subject to change
mclicbase = 0x351, // MRW Base address for CLIC memory mapped registers (CLIC) - addr subject to change
// Physical Memory Protection // Physical Memory Protection
pmpcfg0 = 0x3A0, pmpcfg0 = 0x3A0,
pmpcfg1 = 0x3A1, pmpcfg1 = 0x3A1,
@ -177,10 +164,10 @@ enum riscv_csr {
// Debug Mode Registers // Debug Mode Registers
dcsr = 0x7B0, dcsr = 0x7B0,
dpc = 0x7B1, dpc = 0x7B1,
dscratch0 = 0x7B2, dscratch = 0x7B2
dscratch1 = 0x7B3
}; };
enum { enum {
PGSHIFT = 12, PGSHIFT = 12,
PTE_PPN_SHIFT = 10, PTE_PPN_SHIFT = 10,
@ -198,7 +185,7 @@ enum {
template <typename T> inline bool PTE_TABLE(T PTE) { return (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V); } template <typename T> inline bool PTE_TABLE(T PTE) { return (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V); }
enum { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3, PRIV_D = 4 }; enum { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3 };
enum { enum {
ISA_A = 1, ISA_A = 1,
@ -224,17 +211,6 @@ struct vm_info {
bool is_active() { return levels; } bool is_active() { return levels; }
}; };
struct feature_config {
uint64_t clic_base{0xc0000000};
unsigned clic_int_ctl_bits{4};
unsigned clic_num_irq{16};
unsigned clic_num_trigger{0};
uint64_t tcm_base{0x10000000};
uint64_t tcm_size{0x8000};
uint64_t io_address{0xf0000000};
uint64_t io_addr_mask{0xf0000000};
};
class trap_load_access_fault : public trap_access { class trap_load_access_fault : public trap_access {
public: public:
trap_load_access_fault(uint64_t badaddr) trap_load_access_fault(uint64_t badaddr)
@ -260,105 +236,7 @@ public:
trap_store_page_fault(uint64_t badaddr) trap_store_page_fault(uint64_t badaddr)
: trap_access(15 << 16, badaddr) {} : trap_access(15 << 16, badaddr) {}
}; };
}
inline void read_reg_uint32(uint64_t offs, uint32_t& reg, uint8_t* const data, unsigned length) {
auto reg_ptr = reinterpret_cast<uint8_t*>(&reg);
switch(offs & 0x3) {
case 0:
for(auto i = 0U; i < length; ++i)
*(data + i) = *(reg_ptr + i);
break;
case 1:
for(auto i = 0U; i < length; ++i)
*(data + i) = *(reg_ptr + 1 + i);
break;
case 2:
for(auto i = 0U; i < length; ++i)
*(data + i) = *(reg_ptr + 2 + i);
break;
case 3:
*data = *(reg_ptr + 3);
break;
}
} }
inline void write_reg_uint32(uint64_t offs, uint32_t& reg, const uint8_t* const data, unsigned length) {
auto reg_ptr = reinterpret_cast<uint8_t*>(&reg);
switch(offs & 0x3) {
case 0:
for(auto i = 0U; i < length; ++i)
*(reg_ptr + i) = *(data + i);
break;
case 1:
for(auto i = 0U; i < length; ++i)
*(reg_ptr + 1 + i) = *(data + i);
break;
case 2:
for(auto i = 0U; i < length; ++i)
*(reg_ptr + 2 + i) = *(data + i);
break;
case 3:
*(reg_ptr + 3) = *data;
break;
}
}
struct riscv_hart_common {
riscv_hart_common(){};
~riscv_hart_common(){};
std::unordered_map<std::string, uint64_t> symbol_table;
std::unordered_map<std::string, uint64_t> get_sym_table(std::string name) {
if(!symbol_table.empty())
return symbol_table;
FILE* fp = fopen(name.c_str(), "r");
if(fp) {
std::array<char, 5> buf;
auto n = fread(buf.data(), 1, 4, fp);
fclose(fp);
if(n != 4)
throw std::runtime_error("input file has insufficient size");
buf[4] = 0;
if(strcmp(buf.data() + 1, "ELF") == 0) {
// Create elfio reader
ELFIO::elfio reader;
// Load ELF data
if(!reader.load(name))
throw std::runtime_error("could not process elf file");
// check elf properties
if(reader.get_type() != ET_EXEC)
throw std::runtime_error("wrong elf type in file");
if(reader.get_machine() != EM_RISCV)
throw std::runtime_error("wrong elf machine in file");
const auto sym_sec = reader.sections[".symtab"];
if(SHT_SYMTAB == sym_sec->get_type() || SHT_DYNSYM == sym_sec->get_type()) {
ELFIO::symbol_section_accessor symbols(reader, sym_sec);
auto sym_no = symbols.get_symbols_num();
std::string name;
ELFIO::Elf64_Addr value = 0;
ELFIO::Elf_Xword size = 0;
unsigned char bind = 0;
unsigned char type = 0;
ELFIO::Elf_Half section = 0;
unsigned char other = 0;
for(auto i = 0U; i < sym_no; ++i) {
symbols.get_symbol(i, name, value, size, bind, type, section, other);
if(name != "") {
this->symbol_table[name] = value;
#ifndef NDEBUG
CPPLOG(DEBUG) << "Found Symbol " << name;
#endif
}
}
}
return symbol_table;
}
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file", name));
} else
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
};
};
} // namespace arch
} // namespace iss
#endif #endif

View File

@ -0,0 +1,976 @@
/*******************************************************************************
* Copyright (C) 2021 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
* eyck@minres.com - initial implementation
******************************************************************************/
#ifndef _RISCV_HART_M_P_H
#define _RISCV_HART_M_P_H
#include "riscv_hart_common.h"
#include "iss/arch/traits.h"
#include "iss/instrumentation_if.h"
#include "iss/log_categories.h"
#include "iss/vm_if.h"
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <array>
#include <elfio/elfio.hpp>
#include <fmt/format.h>
#include <iomanip>
#include <sstream>
#include <type_traits>
#include <unordered_map>
#include <functional>
#include <util/bit_field.h>
#include <util/ities.h>
#include <util/sparse_array.h>
#if defined(__GNUC__)
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) x
#define unlikely(x) x
#endif
namespace iss {
namespace arch {
template <typename BASE> class riscv_hart_m_p : public BASE {
protected:
const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
const std::array<const char *, 16> trap_str = {{""
"Instruction address misaligned", // 0
"Instruction access fault", // 1
"Illegal instruction", // 2
"Breakpoint", // 3
"Load address misaligned", // 4
"Load access fault", // 5
"Store/AMO address misaligned", // 6
"Store/AMO access fault", // 7
"Environment call from U-mode", // 8
"Environment call from S-mode", // 9
"Reserved", // a
"Environment call from M-mode", // b
"Instruction page fault", // c
"Load page fault", // d
"Reserved", // e
"Store/AMO page fault"}};
const std::array<const char *, 12> irq_str = {
{"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt",
"User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt",
"User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}};
public:
using core = BASE;
using this_class = riscv_hart_m_p<BASE>;
using phys_addr_t = typename core::phys_addr_t;
using reg_t = typename core::reg_t;
using addr_t = typename core::addr_t;
using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t &);
using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
// primary template
template <class T, class Enable = void> struct hart_state {};
// specialization 32bit
template <typename T> class hart_state<T, typename std::enable_if<std::is_same<T, uint32_t>::value>::type> {
public:
BEGIN_BF_DECL(mstatus_t, T);
// SD bit is read-only and is set when either the FS or XS bits encode a Dirty state (i.e., SD=((FS==11) OR XS==11)))
BF_FIELD(SD, 31, 1);
// Trap SRET
BF_FIELD(TSR, 22, 1);
// Timeout Wait
BF_FIELD(TW, 21, 1);
// Trap Virtual Memory
BF_FIELD(TVM, 20, 1);
// Make eXecutable Readable
BF_FIELD(MXR, 19, 1);
// permit Supervisor User Memory access
BF_FIELD(SUM, 18, 1);
// Modify PRiVilege
BF_FIELD(MPRV, 17, 1);
// status of additional user-mode extensions and associated state, All off/None dirty or clean, some on/None dirty, some clean/Some dirty
BF_FIELD(XS, 15, 2);
// floating-point unit status Off/Initial/Clean/Dirty
BF_FIELD(FS, 13, 2);
// machine previous privilege
BF_FIELD(MPP, 11, 2);
// supervisor previous privilege
BF_FIELD(SPP, 8, 1);
// previous machine interrupt-enable
BF_FIELD(MPIE, 7, 1);
// previous supervisor interrupt-enable
BF_FIELD(SPIE, 5, 1);
// previous user interrupt-enable
BF_FIELD(UPIE, 4, 1);
// machine interrupt-enable
BF_FIELD(MIE, 3, 1);
// supervisor interrupt-enable
BF_FIELD(SIE, 1, 1);
// user interrupt-enable
BF_FIELD(UIE, 0, 1);
END_BF_DECL();
mstatus_t mstatus;
static const reg_t mstatus_reset_val = 0x1800;
void write_mstatus(T val) {
auto mask = get_mask() &0xff; // MPP is hardcode as 0x3
auto new_val = (mstatus.backing.val & ~mask) | (val & mask);
mstatus = new_val;
}
static constexpr uint32_t get_mask() {
//return 0x807ff988UL; // 0b1000 0000 0111 1111 1111 1000 1000 1000 // only machine mode is supported
// +-SD
// | +-TSR
// | |+-TW
// | ||+-TVM
// | |||+-MXR
// | ||||+-SUM
// | |||||+-MPRV
// | |||||| +-XS
// | |||||| | +-FS
// | |||||| | | +-MPP
// | |||||| | | | +-SPP
// | |||||| | | | |+-MPIE
// | ||||||/|/|/| || +-MIE
return 0b00000000000000000001100010001000;
}
};
using hart_state_type = hart_state<reg_t>;
constexpr reg_t get_irq_mask() {
return 0b100010001000; // only machine mode is supported
}
constexpr reg_t get_pc_mask() {
return traits<BASE>::MISA_VAL&0b0100?~1:~3;
}
riscv_hart_m_p();
virtual ~riscv_hart_m_p() = default;
void reset(uint64_t address) override;
std::pair<uint64_t, bool> load_file(std::string name, int type = -1) override;
iss::status read(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, uint8_t *const data) override;
iss::status write(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, const uint8_t *const data) override;
virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_m_p::enter_trap(flags, fault_data, fault_data); }
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
virtual uint64_t leave_trap(uint64_t flags) override;
const reg_t& get_mhartid() const { return mhartid_reg; }
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]",
pc, instr, (reg_t)state.mstatus, this->reg.icount);
};
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
void setMemReadCb(std::function<iss::status(phys_addr_t, unsigned, uint8_t* const)> const& memReadCb) {
mem_read_cb = memReadCb;
}
void setMemWriteCb(std::function<iss::status(phys_addr_t, unsigned, const uint8_t* const)> const& memWriteCb) {
mem_write_cb = memWriteCb;
}
void set_csr(unsigned addr, reg_t val){
csr[addr & csr.page_addr_mask] = val;
}
protected:
struct riscv_instrumentation_if : public iss::instrumentation_if {
riscv_instrumentation_if(riscv_hart_m_p<BASE> &arch)
: arch(arch) {}
/**
* get the name of this architecture
*
* @return the name of this architecture
*/
const std::string core_type_name() const override { return traits<BASE>::core_type; }
virtual uint64_t get_pc() { return arch.get_pc(); };
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
riscv_hart_m_p<BASE> &arch;
};
friend struct riscv_instrumentation_if;
addr_t get_pc() { return this->reg.PC; }
addr_t get_next_pc() { return this->reg.NEXT_PC; }
virtual iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data);
virtual iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data);
virtual iss::status read_csr(unsigned addr, reg_t &val);
virtual iss::status write_csr(unsigned addr, reg_t val);
hart_state_type state;
int64_t cycle_offset{0};
uint64_t mcycle_csr{0};
int64_t instret_offset{0};
uint64_t minstret_csr{0};
reg_t fault_data;
uint64_t tohost = tohost_dflt;
uint64_t fromhost = fromhost_dflt;
unsigned to_host_wr_cnt = 0;
riscv_instrumentation_if instr_if;
using mem_type = util::sparse_array<uint8_t, 1ULL << 32>;
using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>;
using csr_page_type = typename csr_type::page_type;
mem_type mem;
csr_type csr;
std::stringstream uart_buf;
std::unordered_map<reg_t, uint64_t> ptw;
std::unordered_map<uint64_t, uint8_t> atomic_reservation;
std::unordered_map<unsigned, rd_csr_f> csr_rd_cb;
std::unordered_map<unsigned, wr_csr_f> csr_wr_cb;
private:
iss::status read_reg(unsigned addr, reg_t &val);
iss::status write_reg(unsigned addr, reg_t val);
iss::status read_null(unsigned addr, reg_t &val);
iss::status write_null(unsigned addr, reg_t val){return iss::status::Ok;}
iss::status read_cycle(unsigned addr, reg_t &val);
iss::status write_cycle(unsigned addr, reg_t val);
iss::status read_instret(unsigned addr, reg_t &val);
iss::status write_instret(unsigned addr, reg_t val);
iss::status read_tvec(unsigned addr, reg_t &val);
iss::status read_time(unsigned addr, reg_t &val);
iss::status read_status(unsigned addr, reg_t &val);
iss::status write_status(unsigned addr, reg_t val);
iss::status write_cause(unsigned addr, reg_t val);
iss::status read_ie(unsigned addr, reg_t &val);
iss::status write_ie(unsigned addr, reg_t val);
iss::status read_ip(unsigned addr, reg_t &val);
iss::status write_ip(unsigned addr, reg_t val);
iss::status read_hartid(unsigned addr, reg_t &val);
iss::status write_epc(unsigned addr, reg_t val);
reg_t mhartid_reg{0x0};
std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb;
std::function<iss::status(phys_addr_t, unsigned, const uint8_t *const)> mem_write_cb;
protected:
void check_interrupt();
};
template <typename BASE>
riscv_hart_m_p<BASE>::riscv_hart_m_p()
: state()
, instr_if(*this) {
// reset values
csr[misa] = traits<BASE>::MISA_VAL;
csr[mvendorid] = 0x669;
csr[marchid] = 0x80000003;
csr[mimpid] = 1;
uart_buf.str("");
for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
}
for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
//csr_wr_cb[addr] = &this_class::write_reg;
}
// common regs
const std::array<unsigned, 10> addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, mtval, mscratch}};
for(auto addr: addrs) {
csr_rd_cb[addr] = &this_class::read_reg;
csr_wr_cb[addr] = &this_class::write_reg;
}
// special handling & overrides
csr_rd_cb[time] = &this_class::read_time;
csr_rd_cb[timeh] = &this_class::read_time;
csr_rd_cb[cycle] = &this_class::read_cycle;
csr_rd_cb[cycleh] = &this_class::read_cycle;
csr_rd_cb[instret] = &this_class::read_instret;
csr_rd_cb[instreth] = &this_class::read_instret;
csr_rd_cb[mcycle] = &this_class::read_cycle;
csr_wr_cb[mcycle] = &this_class::write_cycle;
csr_rd_cb[mcycleh] = &this_class::read_cycle;
csr_wr_cb[mcycleh] = &this_class::write_cycle;
csr_rd_cb[minstret] = &this_class::read_instret;
csr_wr_cb[minstret] = &this_class::write_instret;
csr_rd_cb[minstreth] = &this_class::read_instret;
csr_wr_cb[minstreth] = &this_class::write_instret;
csr_rd_cb[mstatus] = &this_class::read_status;
csr_wr_cb[mstatus] = &this_class::write_status;
csr_wr_cb[mcause] = &this_class::write_cause;
csr_rd_cb[mtvec] = &this_class::read_tvec;
csr_wr_cb[mepc] = &this_class::write_epc;
csr_rd_cb[mip] = &this_class::read_ip;
csr_wr_cb[mip] = &this_class::write_ip;
csr_rd_cb[mie] = &this_class::read_ie;
csr_wr_cb[mie] = &this_class::write_ie;
csr_rd_cb[mhartid] = &this_class::read_hartid;
csr_rd_cb[mcounteren] = &this_class::read_null;
csr_wr_cb[mcounteren] = &this_class::write_null;
csr_wr_cb[misa] = &this_class::write_null;
csr_wr_cb[mvendorid] = &this_class::write_null;
csr_wr_cb[marchid] = &this_class::write_null;
csr_wr_cb[mimpid] = &this_class::write_null;
}
template <typename BASE> std::pair<uint64_t, bool> riscv_hart_m_p<BASE>::load_file(std::string name, int type) {
FILE *fp = fopen(name.c_str(), "r");
if (fp) {
std::array<char, 5> buf;
auto n = fread(buf.data(), 1, 4, fp);
if (n != 4) throw std::runtime_error("input file has insufficient size");
buf[4] = 0;
if (strcmp(buf.data() + 1, "ELF") == 0) {
fclose(fp);
// Create elfio reader
ELFIO::elfio reader;
// Load ELF data
if (!reader.load(name)) throw std::runtime_error("could not process elf file");
// check elf properties
if (reader.get_class() != ELFCLASS32)
if (sizeof(reg_t) == 4) throw std::runtime_error("wrong elf class in file");
if (reader.get_type() != ET_EXEC) throw std::runtime_error("wrong elf type in file");
if (reader.get_machine() != EM_RISCV) throw std::runtime_error("wrong elf machine in file");
auto entry = reader.get_entry();
for (const auto pseg : reader.segments) {
const auto fsize = pseg->get_file_size(); // 0x42c/0x0
const auto seg_data = pseg->get_data();
if (fsize > 0) {
auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE,
traits<BASE>::MEM, pseg->get_physical_address(),
fsize, reinterpret_cast<const uint8_t *const>(seg_data));
if (res != iss::Ok)
LOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex
<< pseg->get_physical_address();
}
}
for(const auto sec : reader.sections) {
if(sec->get_name() == ".symtab") {
if ( SHT_SYMTAB == sec->get_type() ||
SHT_DYNSYM == sec->get_type() ) {
ELFIO::symbol_section_accessor symbols( reader, sec );
auto sym_no = symbols.get_symbols_num();
std::string name;
ELFIO::Elf64_Addr value = 0;
ELFIO::Elf_Xword size = 0;
unsigned char bind = 0;
unsigned char type = 0;
ELFIO::Elf_Half section = 0;
unsigned char other = 0;
for ( auto i = 0U; i < sym_no; ++i ) {
symbols.get_symbol( i, name, value, size, bind, type, section, other );
if(name=="tohost") {
tohost = value;
} else if(name=="fromhost") {
fromhost = value;
}
}
}
} else if (sec->get_name() == ".tohost") {
tohost = sec->get_address();
fromhost = tohost + 0x40;
}
}
return std::make_pair(entry, true);
}
throw std::runtime_error("memory load file is not a valid elf file");
}
throw std::runtime_error("memory load file not found");
}
template <typename BASE>
iss::status riscv_hart_m_p<BASE>::read(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, uint8_t *const data) {
#ifndef NDEBUG
if (access && iss::access_type::DEBUG) {
LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
} else if(access && iss::access_type::FETCH){
LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
} else {
LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
}
#endif
try {
switch (space) {
case traits<BASE>::MEM: {
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) {
fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
this->reg.trap_state = (1 << 31); // issue trap 0
return iss::Err;
}
try {
auto alignment = access == iss::access_type::FETCH? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
if(alignment>1 && (addr&(alignment-1))){
this->reg.trap_state = 1<<31 | 4<<16;
fault_data=addr;
return iss::Err;
}
auto res = type==iss::address_type::PHYSICAL?
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
if (unlikely(res != iss::Ok)){
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
fault_data=addr;
}
return res;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
} break;
case traits<BASE>::CSR: {
if (length != sizeof(reg_t)) return iss::Err;
return read_csr(addr, *reinterpret_cast<reg_t *const>(data));
} break;
case traits<BASE>::FENCE: {
if ((addr + length) > mem.size()) return iss::Err;
return iss::Ok;
} break;
case traits<BASE>::RES: {
auto it = atomic_reservation.find(addr);
if (it != atomic_reservation.end() && it->second != 0) {
memset(data, 0xff, length);
atomic_reservation.erase(addr);
} else
memset(data, 0, length);
} break;
default:
return iss::Err; // assert("Not supported");
}
return iss::Ok;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
}
template <typename BASE>
iss::status riscv_hart_m_p<BASE>::write(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, const uint8_t *const data) {
#ifndef NDEBUG
const char *prefix = (access && iss::access_type::DEBUG) ? "debug " : "";
switch (length) {
case 8:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t *)&data[0] << std::dec
<< ") @addr 0x" << std::hex << addr;
break;
case 4:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t *)&data[0] << std::dec
<< ") @addr 0x" << std::hex << addr;
break;
case 2:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t *)&data[0] << std::dec
<< ") @addr 0x" << std::hex << addr;
break;
case 1:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec
<< ") @addr 0x" << std::hex << addr;
break;
default:
LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
}
#endif
try {
switch (space) {
case traits<BASE>::MEM: {
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) {
fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
this->reg.trap_state = (1 << 31); // issue trap 0
return iss::Err;
}
try {
if(!(access && iss::access_type::DEBUG) && length>1 && (addr&(length-1))){
this->reg.trap_state = 1<<31 | 6<<16;
fault_data=addr;
return iss::Err;
}
auto res = type==iss::address_type::PHYSICAL?
write_mem(phys_addr_t{access, space, addr}, length, data):
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
if (unlikely(res != iss::Ok)) {
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
fault_data=addr;
}
return res;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr});
if ((paddr.val + length) > mem.size()) return iss::Err;
switch (paddr.val) {
case 0x10013000: // UART0 base, TXFIFO reg
case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0];
if (((char)data[0]) == '\n' || data[0] == 0) {
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
// '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str();
uart_buf.str("");
}
return iss::Ok;
case 0x10008000: { // HFROSC base, hfrosccfg reg
auto &p = mem(paddr.val / mem.page_size);
auto offs = paddr.val & mem.page_addr_mask;
std::copy(data, data + length, p.data() + offs);
auto &x = *(p.data() + offs + 3);
if (x & 0x40) x |= 0x80; // hfroscrdy = 1 if hfroscen==1
return iss::Ok;
}
case 0x10008008: { // HFROSC base, pllcfg reg
auto &p = mem(paddr.val / mem.page_size);
auto offs = paddr.val & mem.page_addr_mask;
std::copy(data, data + length, p.data() + offs);
auto &x = *(p.data() + offs + 3);
x |= 0x80; // set pll lock upon writing
return iss::Ok;
} break;
default: {}
}
} break;
case traits<BASE>::CSR: {
if (length != sizeof(reg_t)) return iss::Err;
return write_csr(addr, *reinterpret_cast<const reg_t *>(data));
} break;
case traits<BASE>::FENCE: {
if ((addr + length) > mem.size()) return iss::Err;
switch (addr) {
case 2:
case 3: {
ptw.clear();
auto tvm = state.mstatus.TVM;
return iss::Ok;
}
}
} break;
case traits<BASE>::RES: {
atomic_reservation[addr] = data[0];
} break;
default:
return iss::Err;
}
return iss::Ok;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_csr(unsigned addr, reg_t &val) {
if (addr >= csr.size()) return iss::Err;
auto req_priv_lvl = (addr >> 8) & 0x3;
if (this->reg.PRIV < req_priv_lvl) // not having required privileges
throw illegal_instruction_fault(this->fault_data);
auto it = csr_rd_cb.find(addr);
if (it == csr_rd_cb.end() || !it->second) // non existent register
throw illegal_instruction_fault(this->fault_data);
return (this->*(it->second))(addr, val);
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_csr(unsigned addr, reg_t val) {
if (addr >= csr.size()) return iss::Err;
auto req_priv_lvl = (addr >> 8) & 0x3;
if (this->reg.PRIV < req_priv_lvl) // not having required privileges
throw illegal_instruction_fault(this->fault_data);
if((addr&0xc00)==0xc00) // writing to read-only region
throw illegal_instruction_fault(this->fault_data);
auto it = csr_wr_cb.find(addr);
if (it == csr_wr_cb.end() || !it->second) // non existent register
throw illegal_instruction_fault(this->fault_data);
return (this->*(it->second))(addr, val);
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_reg(unsigned addr, reg_t &val) {
val = csr[addr];
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_null(unsigned addr, reg_t &val) {
val = 0;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_reg(unsigned addr, reg_t val) {
csr[addr] = val;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned addr, reg_t &val) {
auto cycle_val = this->reg.icount + cycle_offset;
if (addr == mcycle) {
val = static_cast<reg_t>(cycle_val);
} else if (addr == mcycleh) {
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(cycle_val >> 32);
}
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) {
if (addr == mcycleh)
return iss::Err;
mcycle_csr = static_cast<uint64_t>(val);
} else {
if (addr == mcycle) {
mcycle_csr = (mcycle_csr & 0xffffffff00000000) + val;
} else {
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
}
}
cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned addr, reg_t &val) {
if ((addr&0xff) == (minstret&0xff)) {
val = static_cast<reg_t>(this->reg.instret);
} else if ((addr&0xff) == (minstreth&0xff)) {
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(this->reg.instret >> 32);
}
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) {
if ((addr&0xff) == (minstreth&0xff))
return iss::Err;
this->reg.instret = static_cast<uint64_t>(val);
} else {
if ((addr&0xff) == (minstret&0xff)) {
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
} else {
this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
}
}
this->reg.instret--;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned addr, reg_t &val) {
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) {
val = static_cast<reg_t>(time_val);
} else if (addr == timeh) {
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(time_val >> 32);
}
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_tvec(unsigned addr, reg_t &val) {
val = csr[mtvec] & ~2;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_status(unsigned addr, reg_t &val) {
val = state.mstatus & hart_state_type::get_mask();
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_status(unsigned addr, reg_t val) {
state.write_mstatus(val);
check_interrupt();
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cause(unsigned addr, reg_t val) {
csr[mcause] = val & ((1UL<<(traits<BASE>::XLEN-1))|0xf); //TODO: make exception code size configurable
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ie(unsigned addr, reg_t &val) {
val = csr[mie];
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_hartid(unsigned addr, reg_t &val) {
val = mhartid_reg;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ie(unsigned addr, reg_t val) {
auto mask = get_irq_mask();
csr[mie] = (csr[mie] & ~mask) | (val & mask);
check_interrupt();
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ip(unsigned addr, reg_t &val) {
val = csr[mip];
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ip(unsigned addr, reg_t val) {
auto mask = get_irq_mask();
mask &= ~(1 << 7); // MTIP is read only
csr[mip] = (csr[mip] & ~mask) | (val & mask);
check_interrupt();
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_epc(unsigned addr, reg_t val) {
csr[addr] = val & get_pc_mask();
return iss::Ok;
}
template <typename BASE>
iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
if(mem_read_cb) return mem_read_cb(paddr, length, data);
switch (paddr.val) {
case 0x0200BFF8: { // CLINT base, mtime reg
if (sizeof(reg_t) < length) return iss::Err;
reg_t time_val;
this->read_csr(time, time_val);
std::copy((uint8_t *)&time_val, ((uint8_t *)&time_val) + length, data);
} break;
case 0x10008000: {
const mem_type::page_type &p = mem(paddr.val / mem.page_size);
uint64_t offs = paddr.val & mem.page_addr_mask;
std::copy(p.data() + offs, p.data() + offs + length, data);
if (this->reg.icount > 30000) data[3] |= 0x80;
} break;
default: {
for(auto offs=0U; offs<length; ++offs) {
*(data + offs)=mem[(paddr.val+offs)%mem.size()];
}
}
}
return iss::Ok;
}
template <typename BASE>
iss::status riscv_hart_m_p<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
if(mem_write_cb) return mem_write_cb(paddr, length, data);
switch (paddr.val) {
case 0x10013000: // UART0 base, TXFIFO reg
case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0];
if (((char)data[0]) == '\n' || data[0] == 0) {
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
// '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str();
uart_buf.str("");
}
break;
case 0x10008000: { // HFROSC base, hfrosccfg reg
mem_type::page_type &p = mem(paddr.val / mem.page_size);
size_t offs = paddr.val & mem.page_addr_mask;
std::copy(data, data + length, p.data() + offs);
uint8_t &x = *(p.data() + offs + 3);
if (x & 0x40) x |= 0x80; // hfroscrdy = 1 if hfroscen==1
} break;
case 0x10008008: { // HFROSC base, pllcfg reg
mem_type::page_type &p = mem(paddr.val / mem.page_size);
size_t offs = paddr.val & mem.page_addr_mask;
std::copy(data, data + length, p.data() + offs);
uint8_t &x = *(p.data() + offs + 3);
x |= 0x80; // set pll lock upon writing
} break;
default: {
mem_type::page_type &p = mem(paddr.val / mem.page_size);
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
// tohost handling in case of riscv-test
if (paddr.access && iss::access_type::FUNC) {
auto tohost_upper = (traits<BASE>::XLEN == 32 && paddr.val == (tohost + 4)) ||
(traits<BASE>::XLEN == 64 && paddr.val == tohost);
auto tohost_lower =
(traits<BASE>::XLEN == 32 && paddr.val == tohost) || (traits<BASE>::XLEN == 64 && paddr.val == tohost);
if (tohost_lower || tohost_upper) {
uint64_t hostvar = *reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask));
if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
switch (hostvar >> 48) {
case 0:
if (hostvar != 0x1) {
LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation";
} else {
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation";
}
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
this->interrupt_sim=hostvar;
break;
//throw(iss::simulation_stopped(hostvar));
case 0x0101: {
char c = static_cast<char>(hostvar & 0xff);
if (c == '\n' || c == 0) {
LOG(INFO) << "tohost send '" << uart_buf.str() << "'";
uart_buf.str("");
} else
uart_buf << c;
to_host_wr_cnt = 0;
} break;
default:
break;
}
} else if (tohost_lower)
to_host_wr_cnt++;
} else if ((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) ||
(traits<BASE>::XLEN == 64 && paddr.val == fromhost)) {
uint64_t fhostvar = *reinterpret_cast<uint64_t *>(p.data() + (fromhost & mem.page_addr_mask));
*reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
}
}
}
}
return iss::Ok;
}
template <typename BASE> inline void riscv_hart_m_p<BASE>::reset(uint64_t address) {
BASE::reset(address);
state.mstatus = hart_state_type::mstatus_reset_val;
}
template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() {
//auto ideleg = csr[mideleg];
// Multiple simultaneous interrupts and traps at the same privilege level are
// handled in the following decreasing priority order:
// external interrupts, software interrupts, timer interrupts, then finally
// any synchronous traps.
auto ena_irq = csr[mip] & csr[mie];
bool mie = state.mstatus.MIE;
auto m_enabled = this->reg.PRIV < PRIV_M || (this->reg.PRIV == PRIV_M && mie);
auto enabled_interrupts = m_enabled ? ena_irq : 0;
if (enabled_interrupts != 0) {
int res = 0;
while ((enabled_interrupts & 1) == 0) {
enabled_interrupts >>= 1;
res++;
}
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
}
}
template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) {
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
// calculate and write mcause val
auto trap_id = bit_sub<0, 16>(flags);
auto cause = bit_sub<16, 15>(flags);
if (trap_id == 0 && cause == 11) cause = 0x8 + PRIV_M; // adjust environment call cause
// calculate effective privilege level
if (trap_id == 0) { // exception
// store ret addr in xepc register
csr[mepc] = static_cast<reg_t>(addr) & get_pc_mask(); // store actual address instruction of exception
csr[mtval] = cause==2?((instr & 0x3)==3?instr:instr&0xffff):fault_data;
fault_data = 0;
} else {
csr[mepc] = this->reg.NEXT_PC & get_pc_mask(); // store next address if interrupt
this->reg.pending_trap = 0;
}
csr[mcause] = (trap_id << 31) + cause;
// update mstatus
// xPP field of mstatus is written with the active privilege mode at the time
// of the trap; the x PIE field of mstatus
// is written with the value of the active interrupt-enable bit at the time of
// the trap; and the x IE field of mstatus
// is cleared
// store the actual privilege level in yPP and store interrupt enable flags
state.mstatus.MPP = PRIV_M;
state.mstatus.MPIE = state.mstatus.MIE;
state.mstatus.MIE = false;
// get trap vector
auto ivec = csr[mtvec];
// calculate addr// set NEXT_PC to trap addressess to jump to based on MODE
// bits in mtvec
this->reg.NEXT_PC = ivec & ~0x3UL;
if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
// reset trap state
this->reg.PRIV = PRIV_M;
this->reg.trap_state = 0;
std::array<char, 32> buffer;
#if defined(_MSC_VER)
sprintf(buffer.data(), "0x%016llx", addr);
#else
sprintf(buffer.data(), "0x%016lx", addr);
#endif
if((flags&0xffffffff) != 0xffffffff)
CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '"
<< (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" << cause << ")"
<< " at address " << buffer.data() << " occurred";
return this->reg.NEXT_PC;
}
template <typename BASE> uint64_t riscv_hart_m_p<BASE>::leave_trap(uint64_t flags) {
state.mstatus.MIE = state.mstatus.MPIE;
state.mstatus.MPIE = 1;
// sets the pc to the value stored in the x epc register.
this->reg.NEXT_PC = csr[mepc] & get_pc_mask();
CLOG(INFO, disass) << "Executing xRET";
check_interrupt();
return this->reg.NEXT_PC;
}
} // namespace arch
} // namespace iss
#endif /* _RISCV_HART_M_P_H */

File diff suppressed because it is too large Load Diff

View File

@ -30,9 +30,9 @@
* *
*******************************************************************************/ *******************************************************************************/
#ifndef _TGC5C_H_ #ifndef _TGC_C_H_
#define _TGC5C_H_ #define _TGC_C_H_
// clang-format off
#include <array> #include <array>
#include <iss/arch/traits.h> #include <iss/arch/traits.h>
#include <iss/arch_if.h> #include <iss/arch_if.h>
@ -41,24 +41,29 @@
namespace iss { namespace iss {
namespace arch { namespace arch {
struct tgc5c; struct tgc_c;
template <> struct traits<tgc5c> { template <> struct traits<tgc_c> {
constexpr static char const* const core_type = "TGC5C"; constexpr static char const* const core_type = "TGC_C";
static constexpr std::array<const char*, 36> reg_names{ static constexpr std::array<const char*, 35> reg_names{
{"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", "pc", "next_pc", "priv", "dpc"}}; {"X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "X8", "X9", "X10", "X11", "X12", "X13", "X14", "X15", "X16", "X17", "X18", "X19", "X20", "X21", "X22", "X23", "X24", "X25", "X26", "X27", "X28", "X29", "X30", "X31", "PC", "NEXT_PC", "PRIV"}};
static constexpr std::array<const char*, 36> reg_aliases{ static constexpr std::array<const char*, 35> reg_aliases{
{"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", "pc", "next_pc", "priv", "dpc"}}; {"X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "X8", "X9", "X10", "X11", "X12", "X13", "X14", "X15", "X16", "X17", "X18", "X19", "X20", "X21", "X22", "X23", "X24", "X25", "X26", "X27", "X28", "X29", "X30", "X31", "PC", "NEXT_PC", "PRIV"}};
enum constants {MISA_VAL=1073746180ULL, MARCHID_VAL=2147483651ULL, CLIC_NUM_IRQ=0ULL, XLEN=32ULL, INSTR_ALIGNMENT=2ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevmal=2ULL, fencevmau=3ULL, CSR_SIZE=4096ULL, MUL_LEN=64ULL}; enum constants {XLEN=32, PCLEN=32, MISA_VAL=0b01000000000000000001000100000100, PGSIZE=0x1000, PGMASK=0b111111111111, CSR_SIZE=4096, fence=0, fencei=1, fencevmal=2, fencevmau=3, MUL_LEN=64};
constexpr static unsigned FP_REGS_SIZE = 0; constexpr static unsigned FP_REGS_SIZE = 0;
enum reg_e { enum reg_e {
X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, PC, NEXT_PC, PRIV, DPC, NUM_REGS, TRAP_STATE=NUM_REGS, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, PC, NEXT_PC, PRIV, NUM_REGS,
TRAP_STATE=NUM_REGS,
PENDING_TRAP,
ICOUNT,
CYCLE,
INSTRET
}; };
using reg_t = uint32_t; using reg_t = uint32_t;
@ -71,19 +76,19 @@ template <> struct traits<tgc5c> {
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>; using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, 43> reg_bit_widths{ static constexpr std::array<const uint32_t, 40> reg_bit_widths{
{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,8,32,32,32,64,64,64,32,32}}; {32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,8,32,32,64,64,64}};
static constexpr std::array<const uint32_t, 43> reg_byte_offsets{ static constexpr std::array<const uint32_t, 40> reg_byte_offsets{
{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,137,141,145,149,157,165,173,177}}; {0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,137,141,145,153,161}};
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1); static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
enum sreg_flag_e { FLAGS }; enum sreg_flag_e { FLAGS };
enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = MEM }; enum mem_type_e { MEM, CSR, FENCE, RES };
enum class opcode_e { enum class opcode_e : unsigned short {
LUI = 0, LUI = 0,
AUIPC = 1, AUIPC = 1,
JAL = 2, JAL = 2,
@ -124,70 +129,79 @@ template <> struct traits<tgc5c> {
FENCE = 37, FENCE = 37,
ECALL = 38, ECALL = 38,
EBREAK = 39, EBREAK = 39,
MRET = 40, URET = 40,
WFI = 41, SRET = 41,
CSRRW = 42, MRET = 42,
CSRRS = 43, WFI = 43,
CSRRC = 44, CSRRW = 44,
CSRRWI = 45, CSRRS = 45,
CSRRSI = 46, CSRRC = 46,
CSRRCI = 47, CSRRWI = 47,
FENCE_I = 48, CSRRSI = 48,
MUL = 49, CSRRCI = 49,
MULH = 50, MUL = 50,
MULHSU = 51, MULH = 51,
MULHU = 52, MULHSU = 52,
DIV = 53, MULHU = 53,
DIVU = 54, DIV = 54,
REM = 55, DIVU = 55,
REMU = 56, REM = 56,
C__ADDI4SPN = 57, REMU = 57,
C__LW = 58, CADDI4SPN = 58,
C__SW = 59, CLW = 59,
C__ADDI = 60, CSW = 60,
C__NOP = 61, CADDI = 61,
C__JAL = 62, CNOP = 62,
C__LI = 63, CJAL = 63,
C__LUI = 64, CLI = 64,
C__ADDI16SP = 65, CLUI = 65,
__reserved_clui = 66, CADDI16SP = 66,
C__SRLI = 67, __reserved_clui = 67,
C__SRAI = 68, CSRLI = 68,
C__ANDI = 69, CSRAI = 69,
C__SUB = 70, CANDI = 70,
C__XOR = 71, CSUB = 71,
C__OR = 72, CXOR = 72,
C__AND = 73, COR = 73,
C__J = 74, CAND = 74,
C__BEQZ = 75, CJ = 75,
C__BNEZ = 76, CBEQZ = 76,
C__SLLI = 77, CBNEZ = 77,
C__LWSP = 78, CSLLI = 78,
C__MV = 79, CLWSP = 79,
C__JR = 80, CMV = 80,
__reserved_cmv = 81, CJR = 81,
C__ADD = 82, __reserved_cmv = 82,
C__JALR = 83, CADD = 83,
C__EBREAK = 84, CJALR = 84,
C__SWSP = 85, CEBREAK = 85,
DII = 86, CSWSP = 86,
DII = 87,
MAX_OPCODE MAX_OPCODE
}; };
}; };
struct tgc5c: public arch_if { struct tgc_c: public arch_if {
using virt_addr_t = typename traits<tgc5c>::virt_addr_t; using virt_addr_t = typename traits<tgc_c>::virt_addr_t;
using phys_addr_t = typename traits<tgc5c>::phys_addr_t; using phys_addr_t = typename traits<tgc_c>::phys_addr_t;
using reg_t = typename traits<tgc5c>::reg_t; using reg_t = typename traits<tgc_c>::reg_t;
using addr_t = typename traits<tgc5c>::addr_t; using addr_t = typename traits<tgc_c>::addr_t;
tgc5c(); tgc_c();
~tgc5c(); ~tgc_c();
void reset(uint64_t address=0) override; void reset(uint64_t address=0) override;
uint8_t* get_regs_base_ptr() override; uint8_t* get_regs_base_ptr() override;
/// deprecated
void get_reg(short idx, std::vector<uint8_t>& value) override {}
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
/// deprecated
bool get_flag(int flag) override {return false;}
void set_flag(int, bool value) override {};
/// deprecated
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
inline uint64_t get_icount() { return reg.icount; } inline uint64_t get_icount() { return reg.icount; }
@ -195,15 +209,23 @@ struct tgc5c: public arch_if {
inline uint64_t stop_code() { return interrupt_sim; } inline uint64_t stop_code() { return interrupt_sim; }
inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<tgc_c>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<tgc_c>::addr_mask);
} else
return virt2phys(addr);
}
virtual phys_addr_t virt2phys(const iss::addr_t& addr); virtual phys_addr_t virt2phys(const iss::addr_t& addr);
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
inline uint32_t get_last_branch() { return reg.last_branch; } inline uint32_t get_last_branch() { return reg.last_branch; }
protected:
#pragma pack(push, 1) #pragma pack(push, 1)
struct TGC5C_regs { struct TGC_C_regs {
uint32_t X0 = 0; uint32_t X0 = 0;
uint32_t X1 = 0; uint32_t X1 = 0;
uint32_t X2 = 0; uint32_t X2 = 0;
@ -238,14 +260,12 @@ struct tgc5c: public arch_if {
uint32_t X31 = 0; uint32_t X31 = 0;
uint32_t PC = 0; uint32_t PC = 0;
uint32_t NEXT_PC = 0; uint32_t NEXT_PC = 0;
uint8_t PRIV = 0; uint8_t PRIV = 0;
uint32_t DPC = 0;
uint32_t trap_state = 0, pending_trap = 0; uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0; uint64_t icount = 0;
uint64_t cycle = 0; uint64_t cycle = 0;
uint64_t instret = 0; uint64_t instret = 0;
uint32_t instruction = 0; uint32_t last_branch;
uint32_t last_branch = 0;
} reg; } reg;
#pragma pack(pop) #pragma pack(pop)
std::array<address_type, 4> addr_mode; std::array<address_type, 4> addr_mode;
@ -259,5 +279,4 @@ struct tgc5c: public arch_if {
} }
} }
#endif /* _TGC5C_H_ */ #endif /* _TGC_C_H_ */
// clang-format on

View File

@ -53,20 +53,20 @@ using namespace iss::debugger;
template <typename ARCH> class riscv_target_adapter : public target_adapter_base { template <typename ARCH> class riscv_target_adapter : public target_adapter_base {
public: public:
riscv_target_adapter(server_if* srv, iss::arch_if* core) riscv_target_adapter(server_if *srv, iss::arch_if *core)
: target_adapter_base(srv) : target_adapter_base(srv)
, core(core) {} , core(core) {}
/*============== Thread Control ===============================*/ /*============== Thread Control ===============================*/
/* Set generic thread */ /* Set generic thread */
status set_gen_thread(rp_thread_ref& thread) override; status set_gen_thread(rp_thread_ref &thread) override;
/* Set control thread */ /* Set control thread */
status set_ctrl_thread(rp_thread_ref& thread) override; status set_ctrl_thread(rp_thread_ref &thread) override;
/* Get thread status */ /* Get thread status */
status is_thread_alive(rp_thread_ref& thread, bool& alive) override; status is_thread_alive(rp_thread_ref &thread, bool &alive) override;
/*============= Register Access ================================*/ /*============= Register Access ================================*/
@ -74,77 +74,79 @@ public:
target byte order. If register is not available target byte order. If register is not available
corresponding bytes in avail_buf are 0, otherwise corresponding bytes in avail_buf are 0, otherwise
avail buf is 1 */ avail buf is 1 */
status read_registers(std::vector<uint8_t>& data, std::vector<uint8_t>& avail) override; status read_registers(std::vector<uint8_t> &data, std::vector<uint8_t> &avail) override;
/* Write all registers. buf is 4-byte aligned and it is in target /* Write all registers. buf is 4-byte aligned and it is in target
byte order */ byte order */
status write_registers(const std::vector<uint8_t>& data) override; status write_registers(const std::vector<uint8_t> &data) override;
/* Read one register. buf is 4-byte aligned and it is in /* Read one register. buf is 4-byte aligned and it is in
target byte order. If register is not available target byte order. If register is not available
corresponding bytes in avail_buf are 0, otherwise corresponding bytes in avail_buf are 0, otherwise
avail buf is 1 */ avail buf is 1 */
status read_single_register(unsigned int reg_no, std::vector<uint8_t>& buf, std::vector<uint8_t>& avail_buf) override; status read_single_register(unsigned int reg_no, std::vector<uint8_t> &buf,
std::vector<uint8_t> &avail_buf) override;
/* Write one register. buf is 4-byte aligned and it is in target byte /* Write one register. buf is 4-byte aligned and it is in target byte
order */ order */
status write_single_register(unsigned int reg_no, const std::vector<uint8_t>& buf) override; status write_single_register(unsigned int reg_no, const std::vector<uint8_t> &buf) override;
/*=================== Memory Access =====================*/ /*=================== Memory Access =====================*/
/* Read memory, buf is 4-bytes aligned and it is in target /* Read memory, buf is 4-bytes aligned and it is in target
byte order */ byte order */
status read_mem(uint64_t addr, std::vector<uint8_t>& buf) override; status read_mem(uint64_t addr, std::vector<uint8_t> &buf) override;
/* Write memory, buf is 4-bytes aligned and it is in target /* Write memory, buf is 4-bytes aligned and it is in target
byte order */ byte order */
status write_mem(uint64_t addr, const std::vector<uint8_t>& buf) override; status write_mem(uint64_t addr, const std::vector<uint8_t> &buf) override;
status process_query(unsigned int& mask, const rp_thread_ref& arg, rp_thread_info& info) override; status process_query(unsigned int &mask, const rp_thread_ref &arg, rp_thread_info &info) override;
status thread_list_query(int first, const rp_thread_ref& arg, std::vector<rp_thread_ref>& result, size_t max_num, size_t& num, status thread_list_query(int first, const rp_thread_ref &arg, std::vector<rp_thread_ref> &result, size_t max_num,
bool& done) override; size_t &num, bool &done) override;
status current_thread_query(rp_thread_ref& thread) override; status current_thread_query(rp_thread_ref &thread) override;
status offsets_query(uint64_t& text, uint64_t& data, uint64_t& bss) override; status offsets_query(uint64_t &text, uint64_t &data, uint64_t &bss) override;
status crc_query(uint64_t addr, size_t len, uint32_t& val) override; status crc_query(uint64_t addr, size_t len, uint32_t &val) override;
status raw_query(std::string in_buf, std::string& out_buf) override; status raw_query(std::string in_buf, std::string &out_buf) override;
status threadinfo_query(int first, std::string& out_buf) override; status threadinfo_query(int first, std::string &out_buf) override;
status threadextrainfo_query(const rp_thread_ref& thread, std::string& out_buf) override; status threadextrainfo_query(const rp_thread_ref &thread, std::string &out_buf) override;
status packetsize_query(std::string& out_buf) override; status packetsize_query(std::string &out_buf) override;
status add_break(break_type type, uint64_t addr, unsigned int length) override; status add_break(int type, uint64_t addr, unsigned int length) override;
status remove_break(break_type type, uint64_t addr, unsigned int length) override; status remove_break(int type, uint64_t addr, unsigned int length) override;
status resume_from_addr(bool step, int sig, uint64_t addr, rp_thread_ref thread, std::function<void(unsigned)> stop_callback) override; status resume_from_addr(bool step, int sig, uint64_t addr, rp_thread_ref thread,
std::function<void(unsigned)> stop_callback) override;
status target_xml_query(std::string& out_buf) override; status target_xml_query(std::string &out_buf) override;
protected: protected:
static inline constexpr addr_t map_addr(const addr_t& i) { return i; } static inline constexpr addr_t map_addr(const addr_t &i) { return i; }
iss::arch_if* core; iss::arch_if *core;
rp_thread_ref thread_idx; rp_thread_ref thread_idx;
}; };
template <typename ARCH> status riscv_target_adapter<ARCH>::set_gen_thread(rp_thread_ref& thread) { template <typename ARCH> status riscv_target_adapter<ARCH>::set_gen_thread(rp_thread_ref &thread) {
thread_idx = thread; thread_idx = thread;
return Ok; return Ok;
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::set_ctrl_thread(rp_thread_ref& thread) { template <typename ARCH> status riscv_target_adapter<ARCH>::set_ctrl_thread(rp_thread_ref &thread) {
thread_idx = thread; thread_idx = thread;
return Ok; return Ok;
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::is_thread_alive(rp_thread_ref& thread, bool& alive) { template <typename ARCH> status riscv_target_adapter<ARCH>::is_thread_alive(rp_thread_ref &thread, bool &alive) {
alive = 1; alive = 1;
return Ok; return Ok;
} }
@ -156,9 +158,10 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::is_thread_alive(rp_t
* set if all threads are processed. * set if all threads are processed.
*/ */
template <typename ARCH> template <typename ARCH>
status riscv_target_adapter<ARCH>::thread_list_query(int first, const rp_thread_ref& arg, std::vector<rp_thread_ref>& result, status riscv_target_adapter<ARCH>::thread_list_query(int first, const rp_thread_ref &arg,
size_t max_num, size_t& num, bool& done) { std::vector<rp_thread_ref> &result, size_t max_num, size_t &num,
if(first == 0) { bool &done) {
if (first == 0) {
result.clear(); result.clear();
result.push_back(thread_idx); result.push_back(thread_idx);
num = 1; num = 1;
@ -168,78 +171,66 @@ status riscv_target_adapter<ARCH>::thread_list_query(int first, const rp_thread_
return NotSupported; return NotSupported;
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::current_thread_query(rp_thread_ref& thread) { template <typename ARCH> status riscv_target_adapter<ARCH>::current_thread_query(rp_thread_ref &thread) {
thread = thread_idx; thread = thread_idx;
return Ok; return Ok;
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::read_registers(std::vector<uint8_t>& data, std::vector<uint8_t>& avail) { template <typename ARCH>
CPPLOG(TRACE) << "reading target registers"; status riscv_target_adapter<ARCH>::read_registers(std::vector<uint8_t> &data, std::vector<uint8_t> &avail) {
LOG(TRACE) << "reading target registers";
// return idx<0?:; // return idx<0?:;
data.clear(); data.clear();
avail.clear(); avail.clear();
const uint8_t* reg_base = core->get_regs_base_ptr(); const uint8_t *reg_base = core->get_regs_base_ptr();
auto start_reg = arch::traits<ARCH>::X0; auto start_reg=arch::traits<ARCH>::X0;
for(size_t reg_no = start_reg; reg_no < start_reg + 33 /*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) { for (size_t reg_no = start_reg; reg_no < start_reg+33/*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8; auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
unsigned offset = traits<ARCH>::reg_byte_offsets[reg_no]; unsigned offset = traits<ARCH>::reg_byte_offsets[reg_no];
for(size_t j = 0; j < reg_width; ++j) { for (size_t j = 0; j < reg_width; ++j) {
data.push_back(*(reg_base + offset + j)); data.push_back(*(reg_base + offset + j));
avail.push_back(0xff); avail.push_back(0xff);
} }
} }
// work around fill with F type registers // work around fill with F type registers
// if (arch::traits<ARCH>::NUM_REGS < 65) { // if (arch::traits<ARCH>::NUM_REGS < 65) {
// auto reg_width = sizeof(typename arch::traits<ARCH>::reg_t); // auto reg_width = sizeof(typename arch::traits<ARCH>::reg_t);
// for (size_t reg_no = 0; reg_no < 33; ++reg_no) { // for (size_t reg_no = 0; reg_no < 33; ++reg_no) {
// for (size_t j = 0; j < reg_width; ++j) { // for (size_t j = 0; j < reg_width; ++j) {
// data.push_back(0x0); // data.push_back(0x0);
// avail.push_back(0x00); // avail.push_back(0x00);
// } // }
// // if(arch::traits<ARCH>::XLEN < 64) // // if(arch::traits<ARCH>::XLEN < 64)
// // for(unsigned j=0; j<4; ++j){ // // for(unsigned j=0; j<4; ++j){
// // data.push_back(0x0); // // data.push_back(0x0);
// // avail.push_back(0x00); // // avail.push_back(0x00);
// // } // // }
// } // }
// } // }
return Ok; return Ok;
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::write_registers(const std::vector<uint8_t>& data) { template <typename ARCH> status riscv_target_adapter<ARCH>::write_registers(const std::vector<uint8_t> &data) {
auto start_reg = arch::traits<ARCH>::X0; auto start_reg=arch::traits<ARCH>::X0;
auto* reg_base = core->get_regs_base_ptr(); auto *reg_base = core->get_regs_base_ptr();
auto iter = data.data(); auto iter = data.data();
bool e_ext = arch::traits<ARCH>::PC < 32; for (size_t reg_no = 0; reg_no < start_reg+33/*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
for(size_t reg_no = 0; reg_no < start_reg + 33 /*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) { auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
if(e_ext && reg_no > 15) { auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
if(reg_no == 32) { std::copy(iter, iter + reg_width, reg_base);
auto reg_width = arch::traits<ARCH>::reg_bit_widths[arch::traits<ARCH>::PC] / 8; iter += 4;
auto offset = traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]; reg_base += offset;
std::copy(iter, iter + reg_width, reg_base);
} else {
const uint64_t zero_val = 0;
auto reg_width = arch::traits<ARCH>::reg_bit_widths[15] / 8;
auto iter = (uint8_t*)&zero_val;
std::copy(iter, iter + reg_width, reg_base);
}
} else {
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
std::copy(iter, iter + reg_width, reg_base);
iter += 4;
reg_base += offset;
}
} }
return Ok; return Ok;
} }
template <typename ARCH> template <typename ARCH>
status riscv_target_adapter<ARCH>::read_single_register(unsigned int reg_no, std::vector<uint8_t>& data, std::vector<uint8_t>& avail) { status riscv_target_adapter<ARCH>::read_single_register(unsigned int reg_no, std::vector<uint8_t> &data,
if(reg_no < 65) { std::vector<uint8_t> &avail) {
if (reg_no < 65) {
// auto reg_size = arch::traits<ARCH>::reg_bit_width(static_cast<typename // auto reg_size = arch::traits<ARCH>::reg_bit_width(static_cast<typename
// arch::traits<ARCH>::reg_e>(reg_no))/8; // arch::traits<ARCH>::reg_e>(reg_no))/8;
auto* reg_base = core->get_regs_base_ptr(); auto *reg_base = core->get_regs_base_ptr();
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8; auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
data.resize(reg_width); data.resize(reg_width);
avail.resize(reg_width); avail.resize(reg_width);
@ -256,9 +247,10 @@ status riscv_target_adapter<ARCH>::read_single_register(unsigned int reg_no, std
return data.size() > 0 ? Ok : Err; return data.size() > 0 ? Ok : Err;
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::write_single_register(unsigned int reg_no, const std::vector<uint8_t>& data) { template <typename ARCH>
if(reg_no < 65) { status riscv_target_adapter<ARCH>::write_single_register(unsigned int reg_no, const std::vector<uint8_t> &data) {
auto* reg_base = core->get_regs_base_ptr(); if (reg_no < 65) {
auto *reg_base = core->get_regs_base_ptr();
auto reg_width = arch::traits<ARCH>::reg_bit_widths[static_cast<typename arch::traits<ARCH>::reg_e>(reg_no)] / 8; auto reg_width = arch::traits<ARCH>::reg_bit_widths[static_cast<typename arch::traits<ARCH>::reg_e>(reg_no)] / 8;
auto offset = traits<ARCH>::reg_byte_offsets[reg_no]; auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
std::copy(data.begin(), data.begin() + reg_width, reg_base + offset); std::copy(data.begin(), data.begin() + reg_width, reg_base + offset);
@ -269,36 +261,41 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::write_single_registe
return Ok; return Ok;
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::read_mem(uint64_t addr, std::vector<uint8_t>& data) { template <typename ARCH> status riscv_target_adapter<ARCH>::read_mem(uint64_t addr, std::vector<uint8_t> &data) {
auto a = map_addr({iss::access_type::DEBUG_READ, iss::address_type::VIRTUAL, 0, addr}); auto a = map_addr({iss::access_type::DEBUG_READ, iss::address_type::VIRTUAL, 0, addr});
auto f = [&]() -> status { return core->read(a, data.size(), data.data()); }; auto f = [&]() -> status { return core->read(a, data.size(), data.data()); };
return srv->execute_syncronized(f); return srv->execute_syncronized(f);
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::write_mem(uint64_t addr, const std::vector<uint8_t>& data) { template <typename ARCH> status riscv_target_adapter<ARCH>::write_mem(uint64_t addr, const std::vector<uint8_t> &data) {
auto a = map_addr({iss::access_type::DEBUG_READ, iss::address_type::VIRTUAL, 0, addr}); auto a = map_addr({iss::access_type::DEBUG_READ, iss::address_type::VIRTUAL, 0, addr});
auto f = [&]() -> status { return core->write(a, data.size(), data.data()); }; auto f = [&]() -> status { return core->write(a, data.size(), data.data()); };
return srv->execute_syncronized(f); return srv->execute_syncronized(f);
} }
template <typename ARCH> template <typename ARCH>
status riscv_target_adapter<ARCH>::process_query(unsigned int& mask, const rp_thread_ref& arg, rp_thread_info& info) { status riscv_target_adapter<ARCH>::process_query(unsigned int &mask, const rp_thread_ref &arg, rp_thread_info &info) {
return NotSupported; return NotSupported;
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::offsets_query(uint64_t& text, uint64_t& data, uint64_t& bss) { template <typename ARCH>
status riscv_target_adapter<ARCH>::offsets_query(uint64_t &text, uint64_t &data, uint64_t &bss) {
text = 0; text = 0;
data = 0; data = 0;
bss = 0; bss = 0;
return Ok; return Ok;
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::crc_query(uint64_t addr, size_t len, uint32_t& val) { return NotSupported; } template <typename ARCH> status riscv_target_adapter<ARCH>::crc_query(uint64_t addr, size_t len, uint32_t &val) {
return NotSupported;
}
template <typename ARCH> status riscv_target_adapter<ARCH>::raw_query(std::string in_buf, std::string& out_buf) { return NotSupported; } template <typename ARCH> status riscv_target_adapter<ARCH>::raw_query(std::string in_buf, std::string &out_buf) {
return NotSupported;
}
template <typename ARCH> status riscv_target_adapter<ARCH>::threadinfo_query(int first, std::string& out_buf) { template <typename ARCH> status riscv_target_adapter<ARCH>::threadinfo_query(int first, std::string &out_buf) {
if(first) { if (first) {
out_buf = fmt::format("m{:x}", thread_idx.val); out_buf = fmt::format("m{:x}", thread_idx.val);
} else { } else {
out_buf = "l"; out_buf = "l";
@ -306,7 +303,8 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::threadinfo_query(int
return Ok; return Ok;
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::threadextrainfo_query(const rp_thread_ref& thread, std::string& out_buf) { template <typename ARCH>
status riscv_target_adapter<ARCH>::threadextrainfo_query(const rp_thread_ref &thread, std::string &out_buf) {
std::array<char, 20> buf; std::array<char, 20> buf;
memset(buf.data(), 0, 20); memset(buf.data(), 0, 20);
sprintf(buf.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x", 'R', 'u', 'n', 'n', 'a', 'b', 'l', 'e', 0); sprintf(buf.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x", 'R', 'u', 'n', 'n', 'a', 'b', 'l', 'e', 0);
@ -314,61 +312,48 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::threadextrainfo_quer
return Ok; return Ok;
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::packetsize_query(std::string& out_buf) { template <typename ARCH> status riscv_target_adapter<ARCH>::packetsize_query(std::string &out_buf) {
out_buf = "PacketSize=1000"; out_buf = "PacketSize=1000";
return Ok; return Ok;
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::add_break(break_type type, uint64_t addr, unsigned int length) { template <typename ARCH> status riscv_target_adapter<ARCH>::add_break(int type, uint64_t addr, unsigned int length) {
switch(type) { auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
default: auto eaddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr + length});
return Err; target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val);
case SW_EXEC: LOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex
case HW_EXEC: { << saddr.val << std::dec;
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr}); LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
auto eaddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr + length}); return Ok;
target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val);
CPPLOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex << saddr.val
<< std::dec;
CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
return Ok;
}
}
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::remove_break(break_type type, uint64_t addr, unsigned int length) { template <typename ARCH> status riscv_target_adapter<ARCH>::remove_break(int type, uint64_t addr, unsigned int length) {
switch(type) { auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
default: unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val);
return Err; if (handle) {
case SW_EXEC: LOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val
case HW_EXEC: { << std::dec;
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr}); // TODO: check length of addr range
unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val); target_adapter_base::bp_lut.removeEntry(handle);
if(handle) { LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
CPPLOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val << std::dec; return Ok;
// TODO: check length of addr range
target_adapter_base::bp_lut.removeEntry(handle);
CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
return Ok;
}
CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
return Err;
}
} }
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
return Err;
} }
template <typename ARCH> template <typename ARCH>
status riscv_target_adapter<ARCH>::resume_from_addr(bool step, int sig, uint64_t addr, rp_thread_ref thread, status riscv_target_adapter<ARCH>::resume_from_addr(bool step, int sig, uint64_t addr, rp_thread_ref thread,
std::function<void(unsigned)> stop_callback) { std::function<void(unsigned)> stop_callback) {
auto* reg_base = core->get_regs_base_ptr(); auto *reg_base = core->get_regs_base_ptr();
auto reg_width = arch::traits<ARCH>::reg_bit_widths[arch::traits<ARCH>::PC] / 8; auto reg_width = arch::traits<ARCH>::reg_bit_widths[arch::traits<ARCH>::PC] / 8;
auto offset = traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]; auto offset = traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC];
const uint8_t* iter = reinterpret_cast<const uint8_t*>(&addr); const uint8_t *iter = reinterpret_cast<const uint8_t *>(&addr);
std::copy(iter, iter + reg_width, reg_base); std::copy(iter, iter + reg_width, reg_base);
return resume_from_current(step, sig, thread, stop_callback); return resume_from_current(step, sig, thread, stop_callback);
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::target_xml_query(std::string& out_buf) { template <typename ARCH> status riscv_target_adapter<ARCH>::target_xml_query(std::string &out_buf) {
const std::string res{"<?xml version=\"1.0\"?><!DOCTYPE target SYSTEM \"gdb-target.dtd\">" const std::string res{"<?xml version=\"1.0\"?><!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
"<target><architecture>riscv:rv32</architecture>" "<target><architecture>riscv:rv32</architecture>"
//" <feature name=\"org.gnu.gdb.riscv.rv32i\">\n" //" <feature name=\"org.gnu.gdb.riscv.rv32i\">\n"
@ -455,7 +440,7 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::target_xml_query(std
</target> </target>
*/ */
} // namespace debugger }
} // namespace iss }
#endif /* _ISS_DEBUGGER_RISCV_TARGET_ADAPTER_H_ */ #endif /* _ISS_DEBUGGER_RISCV_TARGET_ADAPTER_H_ */

View File

@ -33,20 +33,15 @@
#ifndef _ISS_FACTORY_H_ #ifndef _ISS_FACTORY_H_
#define _ISS_FACTORY_H_ #define _ISS_FACTORY_H_
#include <algorithm>
#include <functional>
#include <iss/iss.h> #include <iss/iss.h>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
namespace iss { namespace iss {
using cpu_ptr = std::unique_ptr<iss::arch_if>; using cpu_ptr = std::unique_ptr<iss::arch_if>;
using vm_ptr = std::unique_ptr<iss::vm_if>; using vm_ptr= std::unique_ptr<iss::vm_if>;
template <typename PLAT> std::tuple<cpu_ptr, vm_ptr> create_cpu(std::string const& backend, unsigned gdb_port) { template<typename PLAT>
std::tuple<cpu_ptr, vm_ptr> create_cpu(std::string const& backend, unsigned gdb_port){
using core_type = typename PLAT::core; using core_type = typename PLAT::core;
core_type* lcpu = new PLAT(); core_type* lcpu = new PLAT();
if(backend == "interp") if(backend == "interp")
@ -55,52 +50,13 @@ template <typename PLAT> std::tuple<cpu_ptr, vm_ptr> create_cpu(std::string cons
if(backend == "llvm") if(backend == "llvm")
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}}; return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
#endif #endif
#ifdef WITH_TCC #ifdef WITH_LLVM
if(backend == "tcc") if(backend == "tcc")
return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}}; return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
#endif #endif
return {nullptr, nullptr}; return {nullptr, nullptr};
} }
class core_factory { }
using cpu_ptr = std::unique_ptr<iss::arch_if>;
using vm_ptr = std::unique_ptr<iss::vm_if>;
using base_t = std::tuple<cpu_ptr, vm_ptr>;
using create_fn = std::function<base_t(unsigned, void*)>;
using registry_t = std::unordered_map<std::string, create_fn>;
registry_t registry;
core_factory() = default;
core_factory(const core_factory&) = delete;
core_factory& operator=(const core_factory&) = delete;
public:
static core_factory& instance() {
static core_factory bf;
return bf;
}
bool register_creator(const std::string& className, create_fn const& fn) {
registry[className] = fn;
return true;
}
base_t create(std::string const& className, unsigned gdb_port = 0, void* init_data = nullptr) const {
registry_t::const_iterator regEntry = registry.find(className);
if(regEntry != registry.end())
return regEntry->second(gdb_port, init_data);
return {nullptr, nullptr};
}
std::vector<std::string> get_names() {
std::vector<std::string> keys{registry.size()};
std::transform(std::begin(registry), std::end(registry), std::begin(keys),
[](std::pair<std::string, create_fn> const& p) { return p.first; });
return keys;
}
};
} // namespace iss
#endif /* _ISS_FACTORY_H_ */ #endif /* _ISS_FACTORY_H_ */

View File

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2017 - 2023, MINRES Technologies GmbH * Copyright (C) 2017, 2018, MINRES Technologies GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -37,61 +37,60 @@
#include "iss/instrumentation_if.h" #include "iss/instrumentation_if.h"
#include "iss/vm_plugin.h" #include "iss/vm_plugin.h"
#include <functional> #include <json/json.h>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector>
namespace iss { namespace iss {
namespace plugin { namespace plugin {
class cycle_estimate : public vm_plugin { class cycle_estimate: public iss::vm_plugin {
struct instr_desc { BEGIN_BF_DECL(instr_desc, uint32_t)
size_t size{0}; BF_FIELD(taken, 24, 8)
bool is_branch{false}; BF_FIELD(not_taken, 16, 8)
unsigned not_taken{1}; BF_FIELD(size, 0, 16)
unsigned taken{1}; instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken): instr_desc() {
std::function<unsigned(uint64_t)> f; this->size=size;
}; this->taken=taken;
this->not_taken=not_taken;
}
END_BF_DECL();
public: public:
cycle_estimate() = delete; cycle_estimate() = delete;
cycle_estimate(const cycle_estimate&) = delete; cycle_estimate(const cycle_estimate &) = delete;
cycle_estimate(const cycle_estimate&&) = delete; cycle_estimate(const cycle_estimate &&) = delete;
cycle_estimate(std::string const& config_file_name); cycle_estimate(std::string config_file_name);
virtual ~cycle_estimate(); virtual ~cycle_estimate();
cycle_estimate& operator=(const cycle_estimate&) = delete; cycle_estimate &operator=(const cycle_estimate &) = delete;
cycle_estimate& operator=(const cycle_estimate&&) = delete; cycle_estimate &operator=(const cycle_estimate &&) = delete;
bool registration(const char* const version, vm_if& arch) override; bool registration(const char *const version, vm_if &arch) override;
sync_type get_sync() override { return ALL_SYNC; }; sync_type get_sync() override { return POST_SYNC; };
void callback(instr_info_t instr_info) override; void callback(instr_info_t instr_info, exec_info const&) override;
private: private:
iss::instrumentation_if* instr_if{nullptr}; iss::instrumentation_if *arch_instr;
uint32_t* reg_base_ptr{nullptr};
instr_desc illegal_desc{};
std::vector<instr_desc> delays; std::vector<instr_desc> delays;
unsigned current_delay{0};
struct pair_hash { struct pair_hash {
size_t operator()(const std::pair<uint64_t, uint64_t>& p) const { size_t operator()(const std::pair<uint64_t, uint64_t> &p) const {
std::hash<uint64_t> hash; std::hash<uint64_t> hash;
return hash(p.first) + hash(p.second); return hash(p.first) + hash(p.second);
} }
}; };
std::unordered_map<std::pair<uint64_t, uint64_t>, uint64_t, pair_hash> blocks; std::unordered_map<std::pair<uint64_t, uint64_t>, uint64_t, pair_hash> blocks;
std::string config_file_name; Json::Value root;
}; };
} // namespace plugin }
} // namespace iss }
#endif /* _ISS_PLUGIN_CYCLE_ESTIMATE_H_ */ #endif /* _ISS_PLUGIN_CYCLE_ESTIMATE_H_ */

View File

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2017 - 2023, MINRES Technologies GmbH * Copyright (C) 2017, 2018, MINRES Technologies GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -36,8 +36,8 @@
#define _ISS_PLUGIN_INSTRUCTION_COUNTER_H_ #define _ISS_PLUGIN_INSTRUCTION_COUNTER_H_
#include <iss/vm_plugin.h> #include <iss/vm_plugin.h>
#include <json/json.h>
#include <string> #include <string>
#include <vector>
namespace iss { namespace iss {
namespace plugin { namespace plugin {
@ -53,29 +53,30 @@ class instruction_count : public iss::vm_plugin {
public: public:
instruction_count() = delete; instruction_count() = delete;
instruction_count(const instruction_count&) = delete; instruction_count(const instruction_count &) = delete;
instruction_count(const instruction_count&&) = delete; instruction_count(const instruction_count &&) = delete;
instruction_count(std::string config_file_name); instruction_count(std::string config_file_name);
virtual ~instruction_count(); virtual ~instruction_count();
instruction_count& operator=(const instruction_count&) = delete; instruction_count &operator=(const instruction_count &) = delete;
instruction_count& operator=(const instruction_count&&) = delete; instruction_count &operator=(const instruction_count &&) = delete;
bool registration(const char* const version, vm_if& arch) override; bool registration(const char *const version, vm_if &arch) override;
sync_type get_sync() override { return POST_SYNC; }; sync_type get_sync() override { return POST_SYNC; };
void callback(instr_info_t) override; void callback(instr_info_t, exec_info const&) override;
private: private:
Json::Value root;
std::vector<instr_delay> delays; std::vector<instr_delay> delays;
std::vector<uint64_t> rep_counts; std::vector<uint64_t> rep_counts;
}; };
} // namespace plugin }
} // namespace iss }
#endif /* _ISS_PLUGIN_INSTRUCTION_COUNTER_H_ */ #endif /* _ISS_PLUGIN_INSTRUCTION_COUNTER_H_ */

View File

@ -33,36 +33,31 @@
#ifndef _SYSC_CORE_COMPLEX_H_ #ifndef _SYSC_CORE_COMPLEX_H_
#define _SYSC_CORE_COMPLEX_H_ #define _SYSC_CORE_COMPLEX_H_
#include <scc/tick2time.h>
#include <scc/traceable.h>
#include <scc/utilities.h>
#include <tlm/scc/initiator_mixin.h> #include <tlm/scc/initiator_mixin.h>
#include <scc/traceable.h>
#include <scc/tick2time.h>
#include <scc/utilities.h>
#include <tlm/scc/scv/tlm_rec_initiator_socket.h> #include <tlm/scc/scv/tlm_rec_initiator_socket.h>
#ifdef CWR_SYSTEMC #ifdef CWR_SYSTEMC
#include <scmlinc/scml_property.h> #include <scmlinc/scml_property.h>
#define SOCKET_WIDTH 32
#else #else
#include <cci_configuration> #include <cci_configuration>
#define SOCKET_WIDTH scc::LT
#endif #endif
#include <memory>
#include <tlm> #include <tlm>
#include <tlm_utils/tlm_quantumkeeper.h> #include <tlm_utils/tlm_quantumkeeper.h>
#include <util/range_lut.h> #include <util/range_lut.h>
#include <memory>
namespace iss {
class vm_plugin;
}
namespace sysc { namespace sysc {
class tlm_dmi_ext : public tlm::tlm_dmi { class tlm_dmi_ext : public tlm::tlm_dmi {
public: public:
bool operator==(const tlm_dmi_ext& o) const { bool operator==(const tlm_dmi_ext &o) const {
return this->get_granted_access() == o.get_granted_access() && this->get_start_address() == o.get_start_address() && return this->get_granted_access() == o.get_granted_access() &&
this->get_end_address() == o.get_end_address(); this->get_start_address() == o.get_start_address() && this->get_end_address() == o.get_end_address();
} }
bool operator!=(const tlm_dmi_ext& o) const { return !operator==(o); } bool operator!=(const tlm_dmi_ext &o) const { return !operator==(o); }
}; };
namespace tgfs { namespace tgfs {
@ -71,13 +66,11 @@ struct core_trace;
class core_complex : public sc_core::sc_module, public scc::traceable { class core_complex : public sc_core::sc_module, public scc::traceable {
public: public:
tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<SOCKET_WIDTH>> ibus{"ibus"}; tlm::scc::initiator_mixin<tlm::scc::scv::tlm_rec_initiator_socket<32>> initiator{"intor"};
tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<SOCKET_WIDTH>> dbus{"dbus"};
sc_core::sc_in<bool> rst_i{"rst_i"}; sc_core::sc_in<bool> rst_i{"rst_i"};
sc_core::sc_in<bool> ext_irq_i{"ext_irq_i"}; sc_core::sc_in<bool> global_irq_i{"global_irq_i"};
sc_core::sc_in<bool> timer_irq_i{"timer_irq_i"}; sc_core::sc_in<bool> timer_irq_i{"timer_irq_i"};
@ -86,19 +79,17 @@ public:
sc_core::sc_vector<sc_core::sc_in<bool>> local_irq_i{"local_irq_i", 16}; sc_core::sc_vector<sc_core::sc_in<bool>> local_irq_i{"local_irq_i", 16};
#ifndef CWR_SYSTEMC #ifndef CWR_SYSTEMC
sc_core::sc_in<sc_core::sc_time> clk_i{"clk_i"}; sc_core::sc_in<sc_core::sc_time> clk_i{"clk_i"};
sc_core::sc_port<tlm::tlm_peek_if<uint64_t>, 1, sc_core::SC_ZERO_OR_MORE_BOUND> mtime_o{"mtime_o"}; sc_core::sc_port<tlm::tlm_peek_if<uint64_t>, 1, sc_core::SC_ZERO_OR_MORE_BOUND> mtime_o;
cci::cci_param<std::string> elf_file{"elf_file", ""}; cci::cci_param<std::string> elf_file{"elf_file", ""};
cci::cci_param<bool> enable_disass{"enable_disass", false}; cci::cci_param<bool> enable_disass{"enable_disass", false};
cci::cci_param<bool> disable_dmi{"disable_dmi", false};
cci::cci_param<uint64_t> reset_address{"reset_address", 0ULL}; cci::cci_param<uint64_t> reset_address{"reset_address", 0ULL};
cci::cci_param<std::string> core_type{"core_type", "tgc5c"}; cci::cci_param<std::string> core_type{"core_type", "tgc_c"};
cci::cci_param<std::string> backend{"backend", "interp"}; cci::cci_param<std::string> backend{"backend", "interp"};
@ -108,24 +99,20 @@ public:
cci::cci_param<uint32_t> mhartid{"mhartid", 0}; cci::cci_param<uint32_t> mhartid{"mhartid", 0};
cci::cci_param<std::string> plugins{"plugins", ""};
core_complex(sc_core::sc_module_name const& name); core_complex(sc_core::sc_module_name const& name);
#else #else
sc_core::sc_in<bool> clk_i{"clk_i"}; sc_core::sc_in<bool> clk_i{"clk_i"};
sc_core::sc_in<uint64_t> mtime_i{"mtime_i"}; sc_core::sc_in<uint64_t> mtime_i{"mtime_i"};
scml_property<std::string> elf_file{"elf_file", ""}; scml_property<std::string> elf_file{"elf_file", ""};
scml_property<bool> enable_disass{"enable_disass", false}; scml_property<bool> enable_disass{"enable_disass", false};
scml_property<bool> disable_dmi{"disable_dmi", false};
scml_property<unsigned long long> reset_address{"reset_address", 0ULL}; scml_property<unsigned long long> reset_address{"reset_address", 0ULL};
scml_property<std::string> core_type{"core_type", "tgc5c"}; scml_property<std::string> core_type{"core_type", "tgc_c"};
scml_property<std::string> backend{"backend", "interp"}; scml_property<std::string> backend{"backend", "interp"};
@ -135,85 +122,71 @@ public:
scml_property<uint32_t> mhartid{"mhartid", 0}; scml_property<uint32_t> mhartid{"mhartid", 0};
scml_property<std::string> plugins{"plugins", ""};
core_complex(sc_core::sc_module_name const& name) core_complex(sc_core::sc_module_name const& name)
: sc_module(name) : sc_module(name)
, local_irq_i{"local_irq_i", 16} , local_irq_i{"local_irq_i", 16}
, elf_file{"elf_file", ""} , elf_file{"elf_file", ""}
, enable_disass{"enable_disass", false} , enable_disass{"enable_disass", false}
, reset_address{"reset_address", 0ULL} , reset_address{"reset_address", 0ULL}
, core_type{"core_type", "tgc5c"} , core_type{"core_type", "tgc_c"}
, backend{"backend", "interp"} , backend{"backend", "interp"}
, gdb_server_port{"gdb_server_port", 0} , gdb_server_port{"gdb_server_port", 0}
, dump_ir{"dump_ir", false} , dump_ir{"dump_ir", false}
, mhartid{"mhartid", 0} , mhartid{"mhartid", 0}
, plugins{"plugins", ""}
, fetch_lut(tlm_dmi_ext())
, read_lut(tlm_dmi_ext()) , read_lut(tlm_dmi_ext())
, write_lut(tlm_dmi_ext()) { , write_lut(tlm_dmi_ext())
init(); {
init();
} }
#endif #endif
~core_complex(); ~core_complex();
inline unsigned get_last_bus_cycles() {
auto mem_incr = std::max(ibus_inc, dbus_inc);
ibus_inc = dbus_inc = 0;
return mem_incr > 1 ? mem_incr : 1;
}
inline void sync(uint64_t cycle) { inline void sync(uint64_t cycle) {
auto core_inc = curr_clk * (cycle - last_sync_cycle); auto time = curr_clk * (cycle - last_sync_cycle);
quantum_keeper.inc(core_inc); quantum_keeper.inc(time);
if(quantum_keeper.need_sync()) { if (quantum_keeper.need_sync()) {
wait(quantum_keeper.get_local_time()); wait(quantum_keeper.get_local_time());
quantum_keeper.reset(); quantum_keeper.reset();
} }
last_sync_cycle = cycle; last_sync_cycle = cycle;
} }
bool read_mem(uint64_t addr, unsigned length, uint8_t* const data, bool is_fetch); bool read_mem(uint64_t addr, unsigned length, uint8_t *const data, bool is_fetch);
bool write_mem(uint64_t addr, unsigned length, const uint8_t* const data); bool write_mem(uint64_t addr, unsigned length, const uint8_t *const data);
bool read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data); bool read_mem_dbg(uint64_t addr, unsigned length, uint8_t *const data);
bool write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data); bool write_mem_dbg(uint64_t addr, unsigned length, const uint8_t *const data);
void trace(sc_core::sc_trace_file* trf) const override; void trace(sc_core::sc_trace_file *trf) const override;
bool disass_output(uint64_t pc, const std::string instr); bool disass_output(uint64_t pc, const std::string instr);
void set_clock_period(sc_core::sc_time period); void set_clock_period(sc_core::sc_time period);
protected: protected:
void before_end_of_elaboration() override; void before_end_of_elaboration() override;
void start_of_simulation() override; void start_of_simulation() override;
void forward(); void forward();
void run(); void run();
void rst_cb(); void rst_cb();
void sw_irq_cb(); void sw_irq_cb();
void timer_irq_cb(); void timer_irq_cb();
void ext_irq_cb(); void global_irq_cb();
void local_irq_cb();
uint64_t last_sync_cycle = 0; uint64_t last_sync_cycle = 0;
util::range_lut<tlm_dmi_ext> fetch_lut, read_lut, write_lut; util::range_lut<tlm_dmi_ext> read_lut, write_lut;
tlm_utils::tlm_quantumkeeper quantum_keeper; tlm_utils::tlm_quantumkeeper quantum_keeper;
std::vector<uint8_t> write_buf; std::vector<uint8_t> write_buf;
core_wrapper* cpu{nullptr}; core_wrapper* cpu{nullptr};
sc_core::sc_signal<sc_core::sc_time> curr_clk; sc_core::sc_signal<sc_core::sc_time> curr_clk;
uint64_t ibus_inc{0}, dbus_inc{0};
core_trace* trc{nullptr}; core_trace* trc{nullptr};
std::unique_ptr<scc::tick2time> t2t; std::unique_ptr<scc::tick2time> t2t;
private: private:
void init(); void init();
std::vector<iss::vm_plugin*> plugin_list;
}; };
} /* namespace tgfs */ } /* namespace SiFive */
} /* namespace sysc */ } /* namespace sysc */
#endif /* _SYSC_CORE_COMPLEX_H_ */ #endif /* _SYSC_CORE_COMPLEX_H_ */

View File

@ -8,7 +8,7 @@ project("sotfloat" VERSION 3.0.0)
# Set the version number of your project here (format is MAJOR.MINOR.PATCHLEVEL - e.g. 1.0.0) # Set the version number of your project here (format is MAJOR.MINOR.PATCHLEVEL - e.g. 1.0.0)
set(VERSION "3e") set(VERSION "3e")
#include(Common) include(Common)
include(GNUInstallDirs) include(GNUInstallDirs)
set(SPECIALIZATION RISCV) set(SPECIALIZATION RISCV)
@ -327,7 +327,7 @@ set(OTHERS
set(LIB_SOURCES ${PRIMITIVES} ${SPECIALIZE} ${OTHERS}) set(LIB_SOURCES ${PRIMITIVES} ${SPECIALIZE} ${OTHERS})
add_library(softfloat STATIC ${LIB_SOURCES}) add_library(softfloat ${LIB_SOURCES})
set_property(TARGET softfloat PROPERTY C_STANDARD 99) set_property(TARGET softfloat PROPERTY C_STANDARD 99)
target_compile_definitions(softfloat PRIVATE target_compile_definitions(softfloat PRIVATE
SOFTFLOAT_ROUND_ODD SOFTFLOAT_ROUND_ODD
@ -347,7 +347,7 @@ set_target_properties(softfloat PROPERTIES
install(TARGETS softfloat install(TARGETS softfloat
EXPORT ${PROJECT_NAME}Targets # for downstream dependencies EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/static COMPONENT libs # static lib ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # static lib
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # shared lib LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # shared lib
FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # for mac FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # for mac
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel # headers for mac (note the different component -> different package) PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel # headers for mac (note the different component -> different package)

View File

@ -35,11 +35,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/ =============================================================================*/
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define LITTLEENDIAN 1 #define LITTLEENDIAN 1
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef __GNUC_STDC_INLINE__ #ifdef __GNUC_STDC_INLINE__
#define INLINE inline #define INLINE inline
#else #else
@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define SOFTFLOAT_BUILTIN_CLZ 1 #define SOFTFLOAT_BUILTIN_CLZ 1
#include "opts-GCC.h" #include "opts-GCC.h"

View File

@ -35,11 +35,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/ =============================================================================*/
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define LITTLEENDIAN 1 #define LITTLEENDIAN 1
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef __GNUC_STDC_INLINE__ #ifdef __GNUC_STDC_INLINE__
#define INLINE inline #define INLINE inline
#else #else
@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define SOFTFLOAT_BUILTIN_CLZ 1 #define SOFTFLOAT_BUILTIN_CLZ 1
#include "opts-GCC.h" #include "opts-GCC.h"

View File

@ -35,11 +35,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/ =============================================================================*/
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define LITTLEENDIAN 1 #define LITTLEENDIAN 1
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef __GNUC_STDC_INLINE__ #ifdef __GNUC_STDC_INLINE__
#define INLINE inline #define INLINE inline
#else #else
@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define SOFTFLOAT_BUILTIN_CLZ 1 #define SOFTFLOAT_BUILTIN_CLZ 1
#include "opts-GCC.h" #include "opts-GCC.h"

View File

@ -35,11 +35,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/ =============================================================================*/
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define LITTLEENDIAN 1 #define LITTLEENDIAN 1
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef __GNUC_STDC_INLINE__ #ifdef __GNUC_STDC_INLINE__
//#define INLINE inline //#define INLINE inline
#define INLINE static #define INLINE static
@ -48,9 +48,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef __GNUC__ #ifdef __GNUC__
#define SOFTFLOAT_BUILTIN_CLZ 1 #define SOFTFLOAT_BUILTIN_CLZ 1
#define SOFTFLOAT_INTRINSIC_INT128 1 #define SOFTFLOAT_INTRINSIC_INT128 1
#endif #endif
#include "opts-GCC.h" #include "opts-GCC.h"

View File

@ -35,11 +35,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/ =============================================================================*/
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define LITTLEENDIAN 1 #define LITTLEENDIAN 1
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef __GNUC_STDC_INLINE__ #ifdef __GNUC_STDC_INLINE__
#define INLINE inline #define INLINE inline
#else #else
@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define SOFTFLOAT_BUILTIN_CLZ 1 #define SOFTFLOAT_BUILTIN_CLZ 1
#include "opts-GCC.h" #include "opts-GCC.h"

View File

@ -35,11 +35,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/ =============================================================================*/
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define LITTLEENDIAN 1 #define LITTLEENDIAN 1
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef __GNUC_STDC_INLINE__ #ifdef __GNUC_STDC_INLINE__
#define INLINE inline #define INLINE inline
#else #else
@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define SOFTFLOAT_BUILTIN_CLZ 1 #define SOFTFLOAT_BUILTIN_CLZ 1
#include "opts-GCC.h" #include "opts-GCC.h"

View File

@ -35,11 +35,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/ =============================================================================*/
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define LITTLEENDIAN 1 #define LITTLEENDIAN 1
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef __GNUC_STDC_INLINE__ #ifdef __GNUC_STDC_INLINE__
#define INLINE inline #define INLINE inline
#else #else
@ -47,7 +47,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define SOFTFLOAT_BUILTIN_CLZ 1 #define SOFTFLOAT_BUILTIN_CLZ 1
#define SOFTFLOAT_INTRINSIC_INT128 1 #define SOFTFLOAT_INTRINSIC_INT128 1
#include "opts-GCC.h" #include "opts-GCC.h"

View File

@ -37,13 +37,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Edit lines marked with `==>'. See "SoftFloat-source.html". // Edit lines marked with `==>'. See "SoftFloat-source.html".
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
== > #define LITTLEENDIAN 1 ==> #define LITTLEENDIAN 1
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
== > #define INLINE inline ==> #define INLINE inline
/*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/
==> #define THREAD_LOCAL _Thread_local
/*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/
== > #define THREAD_LOCAL _Thread_local

View File

@ -37,13 +37,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Edit lines marked with `==>'. See "SoftFloat-source.html". // Edit lines marked with `==>'. See "SoftFloat-source.html".
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
== > #define LITTLEENDIAN 1 ==> #define LITTLEENDIAN 1
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
== > #define INLINE inline ==> #define INLINE inline
/*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/
==> #define THREAD_LOCAL _Thread_local
/*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/
== > #define THREAD_LOCAL _Thread_local

View File

@ -37,10 +37,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef specialize_h #ifndef specialize_h
#define specialize_h 1 #define specialize_h 1
#include "primitiveTypes.h"
#include "softfloat.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "primitiveTypes.h"
#include "softfloat.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Default value for 'softfloat_detectTininess'. | Default value for 'softfloat_detectTininess'.
@ -53,21 +53,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define ui32_fromPosOverflow 0xFFFFFFFF #define ui32_fromPosOverflow 0xFFFFFFFF
#define ui32_fromNegOverflow 0xFFFFFFFF #define ui32_fromNegOverflow 0xFFFFFFFF
#define ui32_fromNaN 0xFFFFFFFF #define ui32_fromNaN 0xFFFFFFFF
#define i32_fromPosOverflow (-0x7FFFFFFF - 1) #define i32_fromPosOverflow (-0x7FFFFFFF - 1)
#define i32_fromNegOverflow (-0x7FFFFFFF - 1) #define i32_fromNegOverflow (-0x7FFFFFFF - 1)
#define i32_fromNaN (-0x7FFFFFFF - 1) #define i32_fromNaN (-0x7FFFFFFF - 1)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The values to return on conversions to 64-bit integer formats that raise an | The values to return on conversions to 64-bit integer formats that raise an
| invalid exception. | invalid exception.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define ui64_fromPosOverflow UINT64_C(0xFFFFFFFFFFFFFFFF) #define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF )
#define ui64_fromNegOverflow UINT64_C(0xFFFFFFFFFFFFFFFF) #define ui64_fromNegOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF )
#define ui64_fromNaN UINT64_C(0xFFFFFFFFFFFFFFFF) #define ui64_fromNaN UINT64_C( 0xFFFFFFFFFFFFFFFF )
#define i64_fromPosOverflow (-INT64_C(0x7FFFFFFFFFFFFFFF) - 1) #define i64_fromPosOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1)
#define i64_fromNegOverflow (-INT64_C(0x7FFFFFFFFFFFFFFF) - 1) #define i64_fromNegOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1)
#define i64_fromNaN (-INT64_C(0x7FFFFFFFFFFFFFFF) - 1) #define i64_fromNaN (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| "Common NaN" structure, used to transfer NaN representations from one format | "Common NaN" structure, used to transfer NaN representations from one format
@ -92,7 +92,7 @@ struct commonNaN {
| 16-bit floating-point signaling NaN. | 16-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF16UI(uiA) ((((uiA)&0x7E00) == 0x7C00) && ((uiA)&0x01FF)) #define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts
@ -100,13 +100,13 @@ struct commonNaN {
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f16UIToCommonNaN(uint_fast16_t uiA, struct commonNaN* zPtr); void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast16_t softfloat_commonNaNToF16UI(const struct commonNaN* aPtr); uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating-
@ -114,7 +114,8 @@ uint_fast16_t softfloat_commonNaNToF16UI(const struct commonNaN* aPtr);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB); uint_fast16_t
softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 32-bit floating-point NaN. | The bit pattern for a default generated 32-bit floating-point NaN.
@ -126,7 +127,7 @@ uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
| 32-bit floating-point signaling NaN. | 32-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF32UI(uiA) ((((uiA)&0x7FC00000) == 0x7F800000) && ((uiA)&0x003FFFFF)) #define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts
@ -134,13 +135,13 @@ uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f32UIToCommonNaN(uint_fast32_t uiA, struct commonNaN* zPtr); void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast32_t softfloat_commonNaNToF32UI(const struct commonNaN* aPtr); uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating-
@ -148,20 +149,20 @@ uint_fast32_t softfloat_commonNaNToF32UI(const struct commonNaN* aPtr);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast32_t softfloat_propagateNaNF32UI(uint_fast32_t uiA, uint_fast32_t uiB); uint_fast32_t
softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 64-bit floating-point NaN. | The bit pattern for a default generated 64-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNF64UI UINT64_C(0xFFF8000000000000) #define defaultNaNF64UI UINT64_C( 0xFFF8000000000000 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a | Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a
| 64-bit floating-point signaling NaN. | 64-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF64UI(uiA) \ #define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF )))
((((uiA)&UINT64_C(0x7FF8000000000000)) == UINT64_C(0x7FF0000000000000)) && ((uiA)&UINT64_C(0x0007FFFFFFFFFFFF)))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts
@ -169,13 +170,13 @@ uint_fast32_t softfloat_propagateNaNF32UI(uint_fast32_t uiA, uint_fast32_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f64UIToCommonNaN(uint_fast64_t uiA, struct commonNaN* zPtr); void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast64_t softfloat_commonNaNToF64UI(const struct commonNaN* aPtr); uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating-
@ -183,13 +184,14 @@ uint_fast64_t softfloat_commonNaNToF64UI(const struct commonNaN* aPtr);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB); uint_fast64_t
softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 80-bit extended floating-point NaN. | The bit pattern for a default generated 80-bit extended floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNExtF80UI64 0xFFFF #define defaultNaNExtF80UI64 0xFFFF
#define defaultNaNExtF80UI0 UINT64_C(0xC000000000000000) #define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when the 80-bit unsigned integer formed from concatenating | Returns true when the 80-bit unsigned integer formed from concatenating
@ -197,8 +199,7 @@ uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB);
| floating-point signaling NaN. | floating-point signaling NaN.
| Note: This macro evaluates its arguments more than once. | Note: This macro evaluates its arguments more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNExtF80UI(uiA64, uiA0) \ #define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF )))
((((uiA64)&0x7FFF) == 0x7FFF) && !((uiA0)&UINT64_C(0x4000000000000000)) && ((uiA0)&UINT64_C(0x3FFFFFFFFFFFFFFF)))
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
@ -214,14 +215,16 @@ uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_extF80UIToCommonNaN(uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN* zPtr); void
softfloat_extF80UIToCommonNaN(
uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended | Converts the common NaN pointed to by 'aPtr' into an 80-bit extended
| floating-point NaN, and returns the bit pattern of this value as an unsigned | floating-point NaN, and returns the bit pattern of this value as an unsigned
| integer. | integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr); struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting the unsigned integer formed from concatenating 'uiA64' and | Interpreting the unsigned integer formed from concatenating 'uiA64' and
@ -232,13 +235,19 @@ struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr);
| result. If either original floating-point value is a signaling NaN, the | result. If either original floating-point value is a signaling NaN, the
| invalid exception is raised. | invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t uiA0, uint_fast16_t uiB64, uint_fast64_t uiB0); struct uint128
softfloat_propagateNaNExtF80UI(
uint_fast16_t uiA64,
uint_fast64_t uiA0,
uint_fast16_t uiB64,
uint_fast64_t uiB0
);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 128-bit floating-point NaN. | The bit pattern for a default generated 128-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNF128UI64 UINT64_C(0xFFFF800000000000) #define defaultNaNF128UI64 UINT64_C( 0xFFFF800000000000 )
#define defaultNaNF128UI0 UINT64_C(0) #define defaultNaNF128UI0 UINT64_C( 0 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when the 128-bit unsigned integer formed from concatenating | Returns true when the 128-bit unsigned integer formed from concatenating
@ -246,8 +255,7 @@ struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t
| point signaling NaN. | point signaling NaN.
| Note: This macro evaluates its arguments more than once. | Note: This macro evaluates its arguments more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF128UI(uiA64, uiA0) \ #define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF ))))
((((uiA64)&UINT64_C(0x7FFF800000000000)) == UINT64_C(0x7FFF000000000000)) && ((uiA0) || ((uiA64)&UINT64_C(0x00007FFFFFFFFFFF))))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' | Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0'
@ -256,13 +264,15 @@ struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t
| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception | pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception
| is raised. | is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f128UIToCommonNaN(uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN* zPtr); void
softfloat_f128UIToCommonNaN(
uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN*); struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting the unsigned integer formed from concatenating 'uiA64' and | Interpreting the unsigned integer formed from concatenating 'uiA64' and
@ -273,7 +283,13 @@ struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN*);
| If either original floating-point value is a signaling NaN, the invalid | If either original floating-point value is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_propagateNaNF128UI(uint_fast64_t uiA64, uint_fast64_t uiA0, uint_fast64_t uiB64, uint_fast64_t uiB0); struct uint128
softfloat_propagateNaNF128UI(
uint_fast64_t uiA64,
uint_fast64_t uiA0,
uint_fast64_t uiB64,
uint_fast64_t uiB0
);
#else #else
@ -288,14 +304,18 @@ struct uint128 softfloat_propagateNaNF128UI(uint_fast64_t uiA64, uint_fast64_t u
| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling | common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling
| NaN, the invalid exception is raised. | NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_extF80MToCommonNaN(const struct extFloat80M* aSPtr, struct commonNaN* zPtr); void
softfloat_extF80MToCommonNaN(
const struct extFloat80M *aSPtr, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended | Converts the common NaN pointed to by 'aPtr' into an 80-bit extended
| floating-point NaN, and stores this NaN at the location pointed to by | floating-point NaN, and stores this NaN at the location pointed to by
| 'zSPtr'. | 'zSPtr'.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat80M* zSPtr); void
softfloat_commonNaNToExtF80M(
const struct commonNaN *aPtr, struct extFloat80M *zSPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming at least one of the two 80-bit extended floating-point values | Assuming at least one of the two 80-bit extended floating-point values
@ -303,7 +323,12 @@ void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat8
| at the location pointed to by 'zSPtr'. If either original floating-point | at the location pointed to by 'zSPtr'. If either original floating-point
| value is a signaling NaN, the invalid exception is raised. | value is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct extFloat80M* bSPtr, struct extFloat80M* zSPtr); void
softfloat_propagateNaNExtF80M(
const struct extFloat80M *aSPtr,
const struct extFloat80M *bSPtr,
struct extFloat80M *zSPtr
);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 128-bit floating-point NaN. | The bit pattern for a default generated 128-bit floating-point NaN.
@ -311,7 +336,7 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
#define defaultNaNF128UI96 0xFFFF8000 #define defaultNaNF128UI96 0xFFFF8000
#define defaultNaNF128UI64 0 #define defaultNaNF128UI64 0
#define defaultNaNF128UI32 0 #define defaultNaNF128UI32 0
#define defaultNaNF128UI0 0 #define defaultNaNF128UI0 0
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, | Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN,
@ -321,7 +346,8 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
| four 32-bit elements that concatenate in the platform's normal endian order | four 32-bit elements that concatenate in the platform's normal endian order
| to form a 128-bit floating-point value. | to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f128MToCommonNaN(const uint32_t* aWPtr, struct commonNaN* zPtr); void
softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point
@ -329,7 +355,8 @@ void softfloat_f128MToCommonNaN(const uint32_t* aWPtr, struct commonNaN* zPtr);
| 'zWPtr' points to an array of four 32-bit elements that concatenate in the | 'zWPtr' points to an array of four 32-bit elements that concatenate in the
| platform's normal endian order to form a 128-bit floating-point value. | platform's normal endian order to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_commonNaNToF128M(const struct commonNaN* aPtr, uint32_t* zWPtr); void
softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming at least one of the two 128-bit floating-point values pointed to by | Assuming at least one of the two 128-bit floating-point values pointed to by
@ -339,8 +366,11 @@ void softfloat_commonNaNToF128M(const struct commonNaN* aPtr, uint32_t* zWPtr);
| and 'zWPtr' points to an array of four 32-bit elements that concatenate in | and 'zWPtr' points to an array of four 32-bit elements that concatenate in
| the platform's normal endian order to form a 128-bit floating-point value. | the platform's normal endian order to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_propagateNaNF128M(const uint32_t* aWPtr, const uint32_t* bWPtr, uint32_t* zWPtr); void
softfloat_propagateNaNF128M(
const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr );
#endif #endif
#endif #endif

View File

@ -37,10 +37,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef specialize_h #ifndef specialize_h
#define specialize_h 1 #define specialize_h 1
#include "primitiveTypes.h"
#include "softfloat.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "primitiveTypes.h"
#include "softfloat.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Default value for 'softfloat_detectTininess'. | Default value for 'softfloat_detectTininess'.
@ -53,21 +53,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define ui32_fromPosOverflow 0xFFFFFFFF #define ui32_fromPosOverflow 0xFFFFFFFF
#define ui32_fromNegOverflow 0xFFFFFFFF #define ui32_fromNegOverflow 0xFFFFFFFF
#define ui32_fromNaN 0xFFFFFFFF #define ui32_fromNaN 0xFFFFFFFF
#define i32_fromPosOverflow (-0x7FFFFFFF - 1) #define i32_fromPosOverflow (-0x7FFFFFFF - 1)
#define i32_fromNegOverflow (-0x7FFFFFFF - 1) #define i32_fromNegOverflow (-0x7FFFFFFF - 1)
#define i32_fromNaN (-0x7FFFFFFF - 1) #define i32_fromNaN (-0x7FFFFFFF - 1)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The values to return on conversions to 64-bit integer formats that raise an | The values to return on conversions to 64-bit integer formats that raise an
| invalid exception. | invalid exception.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define ui64_fromPosOverflow UINT64_C(0xFFFFFFFFFFFFFFFF) #define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF )
#define ui64_fromNegOverflow UINT64_C(0xFFFFFFFFFFFFFFFF) #define ui64_fromNegOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF )
#define ui64_fromNaN UINT64_C(0xFFFFFFFFFFFFFFFF) #define ui64_fromNaN UINT64_C( 0xFFFFFFFFFFFFFFFF )
#define i64_fromPosOverflow (-INT64_C(0x7FFFFFFFFFFFFFFF) - 1) #define i64_fromPosOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1)
#define i64_fromNegOverflow (-INT64_C(0x7FFFFFFFFFFFFFFF) - 1) #define i64_fromNegOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1)
#define i64_fromNaN (-INT64_C(0x7FFFFFFFFFFFFFFF) - 1) #define i64_fromNaN (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| "Common NaN" structure, used to transfer NaN representations from one format | "Common NaN" structure, used to transfer NaN representations from one format
@ -92,7 +92,7 @@ struct commonNaN {
| 16-bit floating-point signaling NaN. | 16-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF16UI(uiA) ((((uiA)&0x7E00) == 0x7C00) && ((uiA)&0x01FF)) #define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts
@ -100,13 +100,13 @@ struct commonNaN {
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f16UIToCommonNaN(uint_fast16_t uiA, struct commonNaN* zPtr); void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast16_t softfloat_commonNaNToF16UI(const struct commonNaN* aPtr); uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating-
@ -114,7 +114,8 @@ uint_fast16_t softfloat_commonNaNToF16UI(const struct commonNaN* aPtr);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB); uint_fast16_t
softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 32-bit floating-point NaN. | The bit pattern for a default generated 32-bit floating-point NaN.
@ -126,7 +127,7 @@ uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
| 32-bit floating-point signaling NaN. | 32-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF32UI(uiA) ((((uiA)&0x7FC00000) == 0x7F800000) && ((uiA)&0x003FFFFF)) #define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts
@ -134,13 +135,13 @@ uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f32UIToCommonNaN(uint_fast32_t uiA, struct commonNaN* zPtr); void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast32_t softfloat_commonNaNToF32UI(const struct commonNaN* aPtr); uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating-
@ -148,20 +149,20 @@ uint_fast32_t softfloat_commonNaNToF32UI(const struct commonNaN* aPtr);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast32_t softfloat_propagateNaNF32UI(uint_fast32_t uiA, uint_fast32_t uiB); uint_fast32_t
softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 64-bit floating-point NaN. | The bit pattern for a default generated 64-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNF64UI UINT64_C(0xFFF8000000000000) #define defaultNaNF64UI UINT64_C( 0xFFF8000000000000 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a | Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a
| 64-bit floating-point signaling NaN. | 64-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF64UI(uiA) \ #define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF )))
((((uiA)&UINT64_C(0x7FF8000000000000)) == UINT64_C(0x7FF0000000000000)) && ((uiA)&UINT64_C(0x0007FFFFFFFFFFFF)))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts
@ -169,13 +170,13 @@ uint_fast32_t softfloat_propagateNaNF32UI(uint_fast32_t uiA, uint_fast32_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f64UIToCommonNaN(uint_fast64_t uiA, struct commonNaN* zPtr); void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast64_t softfloat_commonNaNToF64UI(const struct commonNaN* aPtr); uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating-
@ -183,13 +184,14 @@ uint_fast64_t softfloat_commonNaNToF64UI(const struct commonNaN* aPtr);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB); uint_fast64_t
softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 80-bit extended floating-point NaN. | The bit pattern for a default generated 80-bit extended floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNExtF80UI64 0xFFFF #define defaultNaNExtF80UI64 0xFFFF
#define defaultNaNExtF80UI0 UINT64_C(0xC000000000000000) #define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when the 80-bit unsigned integer formed from concatenating | Returns true when the 80-bit unsigned integer formed from concatenating
@ -197,8 +199,7 @@ uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB);
| floating-point signaling NaN. | floating-point signaling NaN.
| Note: This macro evaluates its arguments more than once. | Note: This macro evaluates its arguments more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNExtF80UI(uiA64, uiA0) \ #define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF )))
((((uiA64)&0x7FFF) == 0x7FFF) && !((uiA0)&UINT64_C(0x4000000000000000)) && ((uiA0)&UINT64_C(0x3FFFFFFFFFFFFFFF)))
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
@ -214,14 +215,16 @@ uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_extF80UIToCommonNaN(uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN* zPtr); void
softfloat_extF80UIToCommonNaN(
uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended | Converts the common NaN pointed to by 'aPtr' into an 80-bit extended
| floating-point NaN, and returns the bit pattern of this value as an unsigned | floating-point NaN, and returns the bit pattern of this value as an unsigned
| integer. | integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr); struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting the unsigned integer formed from concatenating 'uiA64' and | Interpreting the unsigned integer formed from concatenating 'uiA64' and
@ -232,13 +235,19 @@ struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr);
| result. If either original floating-point value is a signaling NaN, the | result. If either original floating-point value is a signaling NaN, the
| invalid exception is raised. | invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t uiA0, uint_fast16_t uiB64, uint_fast64_t uiB0); struct uint128
softfloat_propagateNaNExtF80UI(
uint_fast16_t uiA64,
uint_fast64_t uiA0,
uint_fast16_t uiB64,
uint_fast64_t uiB0
);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 128-bit floating-point NaN. | The bit pattern for a default generated 128-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNF128UI64 UINT64_C(0xFFFF800000000000) #define defaultNaNF128UI64 UINT64_C( 0xFFFF800000000000 )
#define defaultNaNF128UI0 UINT64_C(0) #define defaultNaNF128UI0 UINT64_C( 0 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when the 128-bit unsigned integer formed from concatenating | Returns true when the 128-bit unsigned integer formed from concatenating
@ -246,8 +255,7 @@ struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t
| point signaling NaN. | point signaling NaN.
| Note: This macro evaluates its arguments more than once. | Note: This macro evaluates its arguments more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF128UI(uiA64, uiA0) \ #define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF ))))
((((uiA64)&UINT64_C(0x7FFF800000000000)) == UINT64_C(0x7FFF000000000000)) && ((uiA0) || ((uiA64)&UINT64_C(0x00007FFFFFFFFFFF))))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' | Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0'
@ -256,13 +264,15 @@ struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t
| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception | pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception
| is raised. | is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f128UIToCommonNaN(uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN* zPtr); void
softfloat_f128UIToCommonNaN(
uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN*); struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting the unsigned integer formed from concatenating 'uiA64' and | Interpreting the unsigned integer formed from concatenating 'uiA64' and
@ -273,7 +283,13 @@ struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN*);
| If either original floating-point value is a signaling NaN, the invalid | If either original floating-point value is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_propagateNaNF128UI(uint_fast64_t uiA64, uint_fast64_t uiA0, uint_fast64_t uiB64, uint_fast64_t uiB0); struct uint128
softfloat_propagateNaNF128UI(
uint_fast64_t uiA64,
uint_fast64_t uiA0,
uint_fast64_t uiB64,
uint_fast64_t uiB0
);
#else #else
@ -288,14 +304,18 @@ struct uint128 softfloat_propagateNaNF128UI(uint_fast64_t uiA64, uint_fast64_t u
| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling | common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling
| NaN, the invalid exception is raised. | NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_extF80MToCommonNaN(const struct extFloat80M* aSPtr, struct commonNaN* zPtr); void
softfloat_extF80MToCommonNaN(
const struct extFloat80M *aSPtr, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended | Converts the common NaN pointed to by 'aPtr' into an 80-bit extended
| floating-point NaN, and stores this NaN at the location pointed to by | floating-point NaN, and stores this NaN at the location pointed to by
| 'zSPtr'. | 'zSPtr'.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat80M* zSPtr); void
softfloat_commonNaNToExtF80M(
const struct commonNaN *aPtr, struct extFloat80M *zSPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming at least one of the two 80-bit extended floating-point values | Assuming at least one of the two 80-bit extended floating-point values
@ -303,7 +323,12 @@ void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat8
| at the location pointed to by 'zSPtr'. If either original floating-point | at the location pointed to by 'zSPtr'. If either original floating-point
| value is a signaling NaN, the invalid exception is raised. | value is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct extFloat80M* bSPtr, struct extFloat80M* zSPtr); void
softfloat_propagateNaNExtF80M(
const struct extFloat80M *aSPtr,
const struct extFloat80M *bSPtr,
struct extFloat80M *zSPtr
);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 128-bit floating-point NaN. | The bit pattern for a default generated 128-bit floating-point NaN.
@ -311,7 +336,7 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
#define defaultNaNF128UI96 0xFFFF8000 #define defaultNaNF128UI96 0xFFFF8000
#define defaultNaNF128UI64 0 #define defaultNaNF128UI64 0
#define defaultNaNF128UI32 0 #define defaultNaNF128UI32 0
#define defaultNaNF128UI0 0 #define defaultNaNF128UI0 0
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, | Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN,
@ -321,7 +346,8 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
| four 32-bit elements that concatenate in the platform's normal endian order | four 32-bit elements that concatenate in the platform's normal endian order
| to form a 128-bit floating-point value. | to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f128MToCommonNaN(const uint32_t* aWPtr, struct commonNaN* zPtr); void
softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point
@ -329,7 +355,8 @@ void softfloat_f128MToCommonNaN(const uint32_t* aWPtr, struct commonNaN* zPtr);
| 'zWPtr' points to an array of four 32-bit elements that concatenate in the | 'zWPtr' points to an array of four 32-bit elements that concatenate in the
| platform's normal endian order to form a 128-bit floating-point value. | platform's normal endian order to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_commonNaNToF128M(const struct commonNaN* aPtr, uint32_t* zWPtr); void
softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming at least one of the two 128-bit floating-point values pointed to by | Assuming at least one of the two 128-bit floating-point values pointed to by
@ -339,8 +366,11 @@ void softfloat_commonNaNToF128M(const struct commonNaN* aPtr, uint32_t* zWPtr);
| and 'zWPtr' points to an array of four 32-bit elements that concatenate in | and 'zWPtr' points to an array of four 32-bit elements that concatenate in
| the platform's normal endian order to form a 128-bit floating-point value. | the platform's normal endian order to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_propagateNaNF128M(const uint32_t* aWPtr, const uint32_t* bWPtr, uint32_t* zWPtr); void
softfloat_propagateNaNF128M(
const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr );
#endif #endif
#endif #endif

View File

@ -37,10 +37,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef specialize_h #ifndef specialize_h
#define specialize_h 1 #define specialize_h 1
#include "primitiveTypes.h"
#include "softfloat.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "primitiveTypes.h"
#include "softfloat.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Default value for 'softfloat_detectTininess'. | Default value for 'softfloat_detectTininess'.
@ -53,29 +53,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define ui32_fromPosOverflow 0xFFFFFFFF #define ui32_fromPosOverflow 0xFFFFFFFF
#define ui32_fromNegOverflow 0 #define ui32_fromNegOverflow 0
#define ui32_fromNaN 0 #define ui32_fromNaN 0
#define i32_fromPosOverflow 0x7FFFFFFF #define i32_fromPosOverflow 0x7FFFFFFF
#define i32_fromNegOverflow (-0x7FFFFFFF - 1) #define i32_fromNegOverflow (-0x7FFFFFFF - 1)
#define i32_fromNaN 0 #define i32_fromNaN 0
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The values to return on conversions to 64-bit integer formats that raise an | The values to return on conversions to 64-bit integer formats that raise an
| invalid exception. | invalid exception.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define ui64_fromPosOverflow UINT64_C(0xFFFFFFFFFFFFFFFF) #define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF )
#define ui64_fromNegOverflow 0 #define ui64_fromNegOverflow 0
#define ui64_fromNaN 0 #define ui64_fromNaN 0
#define i64_fromPosOverflow INT64_C(0x7FFFFFFFFFFFFFFF) #define i64_fromPosOverflow INT64_C( 0x7FFFFFFFFFFFFFFF )
#define i64_fromNegOverflow (-INT64_C(0x7FFFFFFFFFFFFFFF) - 1) #define i64_fromNegOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1)
#define i64_fromNaN 0 #define i64_fromNaN 0
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| "Common NaN" structure, used to transfer NaN representations from one format | "Common NaN" structure, used to transfer NaN representations from one format
| to another. | to another.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct commonNaN { struct commonNaN { char _unused; };
char _unused;
};
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 16-bit floating-point NaN. | The bit pattern for a default generated 16-bit floating-point NaN.
@ -87,7 +85,7 @@ struct commonNaN {
| 16-bit floating-point signaling NaN. | 16-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF16UI(uiA) ((((uiA)&0x7E00) == 0x7C00) && ((uiA)&0x01FF)) #define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts
@ -95,15 +93,13 @@ struct commonNaN {
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_f16UIToCommonNaN(uiA, zPtr) \ #define softfloat_f16UIToCommonNaN( uiA, zPtr ) if ( ! ((uiA) & 0x0200) ) softfloat_raiseFlags( softfloat_flag_invalid )
if(!((uiA)&0x0200)) \
softfloat_raiseFlags(softfloat_flag_invalid)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_commonNaNToF16UI(aPtr) ((uint_fast16_t)defaultNaNF16UI) #define softfloat_commonNaNToF16UI( aPtr ) ((uint_fast16_t) defaultNaNF16UI)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating-
@ -111,7 +107,8 @@ struct commonNaN {
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB); uint_fast16_t
softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 32-bit floating-point NaN. | The bit pattern for a default generated 32-bit floating-point NaN.
@ -123,7 +120,7 @@ uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
| 32-bit floating-point signaling NaN. | 32-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF32UI(uiA) ((((uiA)&0x7FC00000) == 0x7F800000) && ((uiA)&0x003FFFFF)) #define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts
@ -131,15 +128,13 @@ uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_f32UIToCommonNaN(uiA, zPtr) \ #define softfloat_f32UIToCommonNaN( uiA, zPtr ) if ( ! ((uiA) & 0x00400000) ) softfloat_raiseFlags( softfloat_flag_invalid )
if(!((uiA)&0x00400000)) \
softfloat_raiseFlags(softfloat_flag_invalid)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_commonNaNToF32UI(aPtr) ((uint_fast32_t)defaultNaNF32UI) #define softfloat_commonNaNToF32UI( aPtr ) ((uint_fast32_t) defaultNaNF32UI)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating-
@ -147,20 +142,20 @@ uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast32_t softfloat_propagateNaNF32UI(uint_fast32_t uiA, uint_fast32_t uiB); uint_fast32_t
softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 64-bit floating-point NaN. | The bit pattern for a default generated 64-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNF64UI UINT64_C(0x7FF8000000000000) #define defaultNaNF64UI UINT64_C( 0x7FF8000000000000 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a | Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a
| 64-bit floating-point signaling NaN. | 64-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF64UI(uiA) \ #define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF )))
((((uiA)&UINT64_C(0x7FF8000000000000)) == UINT64_C(0x7FF0000000000000)) && ((uiA)&UINT64_C(0x0007FFFFFFFFFFFF)))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts
@ -168,15 +163,13 @@ uint_fast32_t softfloat_propagateNaNF32UI(uint_fast32_t uiA, uint_fast32_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_f64UIToCommonNaN(uiA, zPtr) \ #define softfloat_f64UIToCommonNaN( uiA, zPtr ) if ( ! ((uiA) & UINT64_C( 0x0008000000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid )
if(!((uiA)&UINT64_C(0x0008000000000000))) \
softfloat_raiseFlags(softfloat_flag_invalid)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_commonNaNToF64UI(aPtr) ((uint_fast64_t)defaultNaNF64UI) #define softfloat_commonNaNToF64UI( aPtr ) ((uint_fast64_t) defaultNaNF64UI)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating-
@ -184,13 +177,14 @@ uint_fast32_t softfloat_propagateNaNF32UI(uint_fast32_t uiA, uint_fast32_t uiB);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB); uint_fast64_t
softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 80-bit extended floating-point NaN. | The bit pattern for a default generated 80-bit extended floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNExtF80UI64 0x7FFF #define defaultNaNExtF80UI64 0x7FFF
#define defaultNaNExtF80UI0 UINT64_C(0xC000000000000000) #define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when the 80-bit unsigned integer formed from concatenating | Returns true when the 80-bit unsigned integer formed from concatenating
@ -198,8 +192,7 @@ uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB);
| floating-point signaling NaN. | floating-point signaling NaN.
| Note: This macro evaluates its arguments more than once. | Note: This macro evaluates its arguments more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNExtF80UI(uiA64, uiA0) \ #define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF )))
((((uiA64)&0x7FFF) == 0x7FFF) && !((uiA0)&UINT64_C(0x4000000000000000)) && ((uiA0)&UINT64_C(0x3FFFFFFFFFFFFFFF)))
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
@ -215,25 +208,24 @@ uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_extF80UIToCommonNaN(uiA64, uiA0, zPtr) \ #define softfloat_extF80UIToCommonNaN( uiA64, uiA0, zPtr ) if ( ! ((uiA0) & UINT64_C( 0x4000000000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid )
if(!((uiA0)&UINT64_C(0x4000000000000000))) \
softfloat_raiseFlags(softfloat_flag_invalid)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended | Converts the common NaN pointed to by 'aPtr' into an 80-bit extended
| floating-point NaN, and returns the bit pattern of this value as an unsigned | floating-point NaN, and returns the bit pattern of this value as an unsigned
| integer. | integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE && !defined softfloat_commonNaNToExtF80UI #if defined INLINE && ! defined softfloat_commonNaNToExtF80UI
INLINE INLINE
struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr) { struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr )
{
struct uint128 uiZ; struct uint128 uiZ;
uiZ.v64 = defaultNaNExtF80UI64; uiZ.v64 = defaultNaNExtF80UI64;
uiZ.v0 = defaultNaNExtF80UI0; uiZ.v0 = defaultNaNExtF80UI0;
return uiZ; return uiZ;
} }
#else #else
struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr); struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr );
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -245,13 +237,19 @@ struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr);
| result. If either original floating-point value is a signaling NaN, the | result. If either original floating-point value is a signaling NaN, the
| invalid exception is raised. | invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t uiA0, uint_fast16_t uiB64, uint_fast64_t uiB0); struct uint128
softfloat_propagateNaNExtF80UI(
uint_fast16_t uiA64,
uint_fast64_t uiA0,
uint_fast16_t uiB64,
uint_fast64_t uiB0
);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 128-bit floating-point NaN. | The bit pattern for a default generated 128-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNF128UI64 UINT64_C(0x7FFF800000000000) #define defaultNaNF128UI64 UINT64_C( 0x7FFF800000000000 )
#define defaultNaNF128UI0 UINT64_C(0) #define defaultNaNF128UI0 UINT64_C( 0 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when the 128-bit unsigned integer formed from concatenating | Returns true when the 128-bit unsigned integer formed from concatenating
@ -259,8 +257,7 @@ struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t
| point signaling NaN. | point signaling NaN.
| Note: This macro evaluates its arguments more than once. | Note: This macro evaluates its arguments more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF128UI(uiA64, uiA0) \ #define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF ))))
((((uiA64)&UINT64_C(0x7FFF800000000000)) == UINT64_C(0x7FFF000000000000)) && ((uiA0) || ((uiA64)&UINT64_C(0x00007FFFFFFFFFFF))))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' | Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0'
@ -269,24 +266,23 @@ struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t
| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception | pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception
| is raised. | is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_f128UIToCommonNaN(uiA64, uiA0, zPtr) \ #define softfloat_f128UIToCommonNaN( uiA64, uiA0, zPtr ) if ( ! ((uiA64) & UINT64_C( 0x0000800000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid )
if(!((uiA64)&UINT64_C(0x0000800000000000))) \
softfloat_raiseFlags(softfloat_flag_invalid)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE && !defined softfloat_commonNaNToF128UI #if defined INLINE && ! defined softfloat_commonNaNToF128UI
INLINE INLINE
struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN* aPtr) { struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr )
{
struct uint128 uiZ; struct uint128 uiZ;
uiZ.v64 = defaultNaNF128UI64; uiZ.v64 = defaultNaNF128UI64;
uiZ.v0 = defaultNaNF128UI0; uiZ.v0 = defaultNaNF128UI0;
return uiZ; return uiZ;
} }
#else #else
struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN*); struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * );
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -298,7 +294,13 @@ struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN*);
| If either original floating-point value is a signaling NaN, the invalid | If either original floating-point value is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_propagateNaNF128UI(uint_fast64_t uiA64, uint_fast64_t uiA0, uint_fast64_t uiB64, uint_fast64_t uiB0); struct uint128
softfloat_propagateNaNF128UI(
uint_fast64_t uiA64,
uint_fast64_t uiA0,
uint_fast64_t uiB64,
uint_fast64_t uiB0
);
#else #else
@ -313,23 +315,26 @@ struct uint128 softfloat_propagateNaNF128UI(uint_fast64_t uiA64, uint_fast64_t u
| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling | common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling
| NaN, the invalid exception is raised. | NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_extF80MToCommonNaN(aSPtr, zPtr) \ #define softfloat_extF80MToCommonNaN( aSPtr, zPtr ) if ( ! ((aSPtr)->signif & UINT64_C( 0x4000000000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid )
if(!((aSPtr)->signif & UINT64_C(0x4000000000000000))) \
softfloat_raiseFlags(softfloat_flag_invalid)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended | Converts the common NaN pointed to by 'aPtr' into an 80-bit extended
| floating-point NaN, and stores this NaN at the location pointed to by | floating-point NaN, and stores this NaN at the location pointed to by
| 'zSPtr'. | 'zSPtr'.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE && !defined softfloat_commonNaNToExtF80M #if defined INLINE && ! defined softfloat_commonNaNToExtF80M
INLINE INLINE
void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat80M* zSPtr) { void
softfloat_commonNaNToExtF80M(
const struct commonNaN *aPtr, struct extFloat80M *zSPtr )
{
zSPtr->signExp = defaultNaNExtF80UI64; zSPtr->signExp = defaultNaNExtF80UI64;
zSPtr->signif = defaultNaNExtF80UI0; zSPtr->signif = defaultNaNExtF80UI0;
} }
#else #else
void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat80M* zSPtr); void
softfloat_commonNaNToExtF80M(
const struct commonNaN *aPtr, struct extFloat80M *zSPtr );
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -338,7 +343,12 @@ void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat8
| at the location pointed to by 'zSPtr'. If either original floating-point | at the location pointed to by 'zSPtr'. If either original floating-point
| value is a signaling NaN, the invalid exception is raised. | value is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct extFloat80M* bSPtr, struct extFloat80M* zSPtr); void
softfloat_propagateNaNExtF80M(
const struct extFloat80M *aSPtr,
const struct extFloat80M *bSPtr,
struct extFloat80M *zSPtr
);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 128-bit floating-point NaN. | The bit pattern for a default generated 128-bit floating-point NaN.
@ -346,7 +356,7 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
#define defaultNaNF128UI96 0x7FFF8000 #define defaultNaNF128UI96 0x7FFF8000
#define defaultNaNF128UI64 0 #define defaultNaNF128UI64 0
#define defaultNaNF128UI32 0 #define defaultNaNF128UI32 0
#define defaultNaNF128UI0 0 #define defaultNaNF128UI0 0
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, | Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN,
@ -356,9 +366,7 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
| four 32-bit elements that concatenate in the platform's normal endian order | four 32-bit elements that concatenate in the platform's normal endian order
| to form a 128-bit floating-point value. | to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_f128MToCommonNaN(aWPtr, zPtr) \ #define softfloat_f128MToCommonNaN( aWPtr, zPtr ) if ( ! ((aWPtr)[indexWordHi( 4 )] & UINT64_C( 0x0000800000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid )
if(!((aWPtr)[indexWordHi(4)] & UINT64_C(0x0000800000000000))) \
softfloat_raiseFlags(softfloat_flag_invalid)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point
@ -366,16 +374,19 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
| 'zWPtr' points to an array of four 32-bit elements that concatenate in the | 'zWPtr' points to an array of four 32-bit elements that concatenate in the
| platform's normal endian order to form a 128-bit floating-point value. | platform's normal endian order to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE && !defined softfloat_commonNaNToF128M #if defined INLINE && ! defined softfloat_commonNaNToF128M
INLINE INLINE
void softfloat_commonNaNToF128M(const struct commonNaN* aPtr, uint32_t* zWPtr) { void
zWPtr[indexWord(4, 3)] = defaultNaNF128UI96; softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr )
zWPtr[indexWord(4, 2)] = defaultNaNF128UI64; {
zWPtr[indexWord(4, 1)] = defaultNaNF128UI32; zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96;
zWPtr[indexWord(4, 0)] = defaultNaNF128UI0; zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64;
zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32;
zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0;
} }
#else #else
void softfloat_commonNaNToF128M(const struct commonNaN* aPtr, uint32_t* zWPtr); void
softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr );
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -386,8 +397,11 @@ void softfloat_commonNaNToF128M(const struct commonNaN* aPtr, uint32_t* zWPtr);
| and 'zWPtr' points to an array of four 32-bit elements that concatenate in | and 'zWPtr' points to an array of four 32-bit elements that concatenate in
| the platform's normal endian order to form a 128-bit floating-point value. | the platform's normal endian order to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_propagateNaNF128M(const uint32_t* aWPtr, const uint32_t* bWPtr, uint32_t* zWPtr); void
softfloat_propagateNaNF128M(
const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr );
#endif #endif
#endif #endif

View File

@ -37,10 +37,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef specialize_h #ifndef specialize_h
#define specialize_h 1 #define specialize_h 1
#include "primitiveTypes.h"
#include "softfloat.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "primitiveTypes.h"
#include "softfloat.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Default value for 'softfloat_detectTininess'. | Default value for 'softfloat_detectTininess'.
@ -53,21 +53,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define ui32_fromPosOverflow 0xFFFFFFFF #define ui32_fromPosOverflow 0xFFFFFFFF
#define ui32_fromNegOverflow 0 #define ui32_fromNegOverflow 0
#define ui32_fromNaN 0 #define ui32_fromNaN 0
#define i32_fromPosOverflow 0x7FFFFFFF #define i32_fromPosOverflow 0x7FFFFFFF
#define i32_fromNegOverflow (-0x7FFFFFFF - 1) #define i32_fromNegOverflow (-0x7FFFFFFF - 1)
#define i32_fromNaN 0 #define i32_fromNaN 0
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The values to return on conversions to 64-bit integer formats that raise an | The values to return on conversions to 64-bit integer formats that raise an
| invalid exception. | invalid exception.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define ui64_fromPosOverflow UINT64_C(0xFFFFFFFFFFFFFFFF) #define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF )
#define ui64_fromNegOverflow 0 #define ui64_fromNegOverflow 0
#define ui64_fromNaN 0 #define ui64_fromNaN 0
#define i64_fromPosOverflow INT64_C(0x7FFFFFFFFFFFFFFF) #define i64_fromPosOverflow INT64_C( 0x7FFFFFFFFFFFFFFF )
#define i64_fromNegOverflow (-INT64_C(0x7FFFFFFFFFFFFFFF) - 1) #define i64_fromNegOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1)
#define i64_fromNaN 0 #define i64_fromNaN 0
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| "Common NaN" structure, used to transfer NaN representations from one format | "Common NaN" structure, used to transfer NaN representations from one format
@ -92,7 +92,7 @@ struct commonNaN {
| 16-bit floating-point signaling NaN. | 16-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF16UI(uiA) ((((uiA)&0x7E00) == 0x7C00) && ((uiA)&0x01FF)) #define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts
@ -100,13 +100,13 @@ struct commonNaN {
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f16UIToCommonNaN(uint_fast16_t uiA, struct commonNaN* zPtr); void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast16_t softfloat_commonNaNToF16UI(const struct commonNaN* aPtr); uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating-
@ -114,7 +114,8 @@ uint_fast16_t softfloat_commonNaNToF16UI(const struct commonNaN* aPtr);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB); uint_fast16_t
softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 32-bit floating-point NaN. | The bit pattern for a default generated 32-bit floating-point NaN.
@ -126,7 +127,7 @@ uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
| 32-bit floating-point signaling NaN. | 32-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF32UI(uiA) ((((uiA)&0x7FC00000) == 0x7F800000) && ((uiA)&0x003FFFFF)) #define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts
@ -134,13 +135,13 @@ uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f32UIToCommonNaN(uint_fast32_t uiA, struct commonNaN* zPtr); void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast32_t softfloat_commonNaNToF32UI(const struct commonNaN* aPtr); uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating-
@ -148,20 +149,20 @@ uint_fast32_t softfloat_commonNaNToF32UI(const struct commonNaN* aPtr);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast32_t softfloat_propagateNaNF32UI(uint_fast32_t uiA, uint_fast32_t uiB); uint_fast32_t
softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 64-bit floating-point NaN. | The bit pattern for a default generated 64-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNF64UI UINT64_C(0x7FF8000000000000) #define defaultNaNF64UI UINT64_C( 0x7FF8000000000000 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a | Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a
| 64-bit floating-point signaling NaN. | 64-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF64UI(uiA) \ #define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF )))
((((uiA)&UINT64_C(0x7FF8000000000000)) == UINT64_C(0x7FF0000000000000)) && ((uiA)&UINT64_C(0x0007FFFFFFFFFFFF)))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts
@ -169,13 +170,13 @@ uint_fast32_t softfloat_propagateNaNF32UI(uint_fast32_t uiA, uint_fast32_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f64UIToCommonNaN(uint_fast64_t uiA, struct commonNaN* zPtr); void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast64_t softfloat_commonNaNToF64UI(const struct commonNaN* aPtr); uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating-
@ -183,13 +184,14 @@ uint_fast64_t softfloat_commonNaNToF64UI(const struct commonNaN* aPtr);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB); uint_fast64_t
softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 80-bit extended floating-point NaN. | The bit pattern for a default generated 80-bit extended floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNExtF80UI64 0x7FFF #define defaultNaNExtF80UI64 0x7FFF
#define defaultNaNExtF80UI0 UINT64_C(0xC000000000000000) #define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when the 80-bit unsigned integer formed from concatenating | Returns true when the 80-bit unsigned integer formed from concatenating
@ -197,8 +199,7 @@ uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB);
| floating-point signaling NaN. | floating-point signaling NaN.
| Note: This macro evaluates its arguments more than once. | Note: This macro evaluates its arguments more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNExtF80UI(uiA64, uiA0) \ #define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF )))
((((uiA64)&0x7FFF) == 0x7FFF) && !((uiA0)&UINT64_C(0x4000000000000000)) && ((uiA0)&UINT64_C(0x3FFFFFFFFFFFFFFF)))
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
@ -214,14 +215,16 @@ uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_extF80UIToCommonNaN(uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN* zPtr); void
softfloat_extF80UIToCommonNaN(
uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended | Converts the common NaN pointed to by 'aPtr' into an 80-bit extended
| floating-point NaN, and returns the bit pattern of this value as an unsigned | floating-point NaN, and returns the bit pattern of this value as an unsigned
| integer. | integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr); struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting the unsigned integer formed from concatenating 'uiA64' and | Interpreting the unsigned integer formed from concatenating 'uiA64' and
@ -232,13 +235,19 @@ struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr);
| result. If either original floating-point value is a signaling NaN, the | result. If either original floating-point value is a signaling NaN, the
| invalid exception is raised. | invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t uiA0, uint_fast16_t uiB64, uint_fast64_t uiB0); struct uint128
softfloat_propagateNaNExtF80UI(
uint_fast16_t uiA64,
uint_fast64_t uiA0,
uint_fast16_t uiB64,
uint_fast64_t uiB0
);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 128-bit floating-point NaN. | The bit pattern for a default generated 128-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNF128UI64 UINT64_C(0x7FFF800000000000) #define defaultNaNF128UI64 UINT64_C( 0x7FFF800000000000 )
#define defaultNaNF128UI0 UINT64_C(0) #define defaultNaNF128UI0 UINT64_C( 0 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when the 128-bit unsigned integer formed from concatenating | Returns true when the 128-bit unsigned integer formed from concatenating
@ -246,8 +255,7 @@ struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t
| point signaling NaN. | point signaling NaN.
| Note: This macro evaluates its arguments more than once. | Note: This macro evaluates its arguments more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF128UI(uiA64, uiA0) \ #define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF ))))
((((uiA64)&UINT64_C(0x7FFF800000000000)) == UINT64_C(0x7FFF000000000000)) && ((uiA0) || ((uiA64)&UINT64_C(0x00007FFFFFFFFFFF))))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' | Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0'
@ -256,13 +264,15 @@ struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t
| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception | pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception
| is raised. | is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f128UIToCommonNaN(uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN* zPtr); void
softfloat_f128UIToCommonNaN(
uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN*); struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting the unsigned integer formed from concatenating 'uiA64' and | Interpreting the unsigned integer formed from concatenating 'uiA64' and
@ -273,7 +283,13 @@ struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN*);
| If either original floating-point value is a signaling NaN, the invalid | If either original floating-point value is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_propagateNaNF128UI(uint_fast64_t uiA64, uint_fast64_t uiA0, uint_fast64_t uiB64, uint_fast64_t uiB0); struct uint128
softfloat_propagateNaNF128UI(
uint_fast64_t uiA64,
uint_fast64_t uiA0,
uint_fast64_t uiB64,
uint_fast64_t uiB0
);
#else #else
@ -288,14 +304,18 @@ struct uint128 softfloat_propagateNaNF128UI(uint_fast64_t uiA64, uint_fast64_t u
| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling | common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling
| NaN, the invalid exception is raised. | NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_extF80MToCommonNaN(const struct extFloat80M* aSPtr, struct commonNaN* zPtr); void
softfloat_extF80MToCommonNaN(
const struct extFloat80M *aSPtr, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended | Converts the common NaN pointed to by 'aPtr' into an 80-bit extended
| floating-point NaN, and stores this NaN at the location pointed to by | floating-point NaN, and stores this NaN at the location pointed to by
| 'zSPtr'. | 'zSPtr'.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat80M* zSPtr); void
softfloat_commonNaNToExtF80M(
const struct commonNaN *aPtr, struct extFloat80M *zSPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming at least one of the two 80-bit extended floating-point values | Assuming at least one of the two 80-bit extended floating-point values
@ -303,7 +323,12 @@ void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat8
| at the location pointed to by 'zSPtr'. If either original floating-point | at the location pointed to by 'zSPtr'. If either original floating-point
| value is a signaling NaN, the invalid exception is raised. | value is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct extFloat80M* bSPtr, struct extFloat80M* zSPtr); void
softfloat_propagateNaNExtF80M(
const struct extFloat80M *aSPtr,
const struct extFloat80M *bSPtr,
struct extFloat80M *zSPtr
);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 128-bit floating-point NaN. | The bit pattern for a default generated 128-bit floating-point NaN.
@ -311,7 +336,7 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
#define defaultNaNF128UI96 0x7FFF8000 #define defaultNaNF128UI96 0x7FFF8000
#define defaultNaNF128UI64 0 #define defaultNaNF128UI64 0
#define defaultNaNF128UI32 0 #define defaultNaNF128UI32 0
#define defaultNaNF128UI0 0 #define defaultNaNF128UI0 0
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, | Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN,
@ -321,7 +346,8 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
| four 32-bit elements that concatenate in the platform's normal endian order | four 32-bit elements that concatenate in the platform's normal endian order
| to form a 128-bit floating-point value. | to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f128MToCommonNaN(const uint32_t* aWPtr, struct commonNaN* zPtr); void
softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point
@ -329,7 +355,8 @@ void softfloat_f128MToCommonNaN(const uint32_t* aWPtr, struct commonNaN* zPtr);
| 'zWPtr' points to an array of four 32-bit elements that concatenate in the | 'zWPtr' points to an array of four 32-bit elements that concatenate in the
| platform's normal endian order to form a 128-bit floating-point value. | platform's normal endian order to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_commonNaNToF128M(const struct commonNaN* aPtr, uint32_t* zWPtr); void
softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming at least one of the two 128-bit floating-point values pointed to by | Assuming at least one of the two 128-bit floating-point values pointed to by
@ -339,8 +366,11 @@ void softfloat_commonNaNToF128M(const struct commonNaN* aPtr, uint32_t* zWPtr);
| and 'zWPtr' points to an array of four 32-bit elements that concatenate in | and 'zWPtr' points to an array of four 32-bit elements that concatenate in
| the platform's normal endian order to form a 128-bit floating-point value. | the platform's normal endian order to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_propagateNaNF128M(const uint32_t* aWPtr, const uint32_t* bWPtr, uint32_t* zWPtr); void
softfloat_propagateNaNF128M(
const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr );
#endif #endif
#endif #endif

View File

@ -37,10 +37,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef specialize_h #ifndef specialize_h
#define specialize_h 1 #define specialize_h 1
#include "primitiveTypes.h"
#include "softfloat.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "primitiveTypes.h"
#include "softfloat.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Default value for 'softfloat_detectTininess'. | Default value for 'softfloat_detectTininess'.
@ -53,21 +53,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define ui32_fromPosOverflow UINT32_C(0xFFFFFFFF) #define ui32_fromPosOverflow UINT32_C(0xFFFFFFFF)
#define ui32_fromNegOverflow UINT32_C(0x0) #define ui32_fromNegOverflow UINT32_C(0x0)
#define ui32_fromNaN UINT32_C(0xFFFFFFFF) #define ui32_fromNaN UINT32_C(0xFFFFFFFF)
#define i32_fromPosOverflow INT64_C(0x7FFFFFFF) #define i32_fromPosOverflow INT64_C(0x7FFFFFFF)
#define i32_fromNegOverflow (-INT64_C(0x7FFFFFFF) - 1) #define i32_fromNegOverflow (-INT64_C(0x7FFFFFFF)-1)
#define i32_fromNaN INT64_C(0x7FFFFFFF) #define i32_fromNaN INT64_C(0x7FFFFFFF)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The values to return on conversions to 64-bit integer formats that raise an | The values to return on conversions to 64-bit integer formats that raise an
| invalid exception. | invalid exception.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define ui64_fromPosOverflow UINT64_C(0xFFFFFFFFFFFFFFFF) #define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF )
#define ui64_fromNegOverflow UINT64_C(0x0) #define ui64_fromNegOverflow UINT64_C( 0x0 )
#define ui64_fromNaN UINT64_C(0xFFFFFFFFFFFFFFFF) #define ui64_fromNaN UINT64_C( 0xFFFFFFFFFFFFFFFF)
#define i64_fromPosOverflow INT64_C(0x7FFFFFFFFFFFFFFF) #define i64_fromPosOverflow INT64_C( 0x7FFFFFFFFFFFFFFF)
#define i64_fromNegOverflow (-INT64_C(0x7FFFFFFFFFFFFFFF) - 1) #define i64_fromNegOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF)-1)
#define i64_fromNaN INT64_C(0x7FFFFFFFFFFFFFFF) #define i64_fromNaN INT64_C( 0x7FFFFFFFFFFFFFFF)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| "Common NaN" structure, used to transfer NaN representations from one format | "Common NaN" structure, used to transfer NaN representations from one format
@ -92,7 +92,7 @@ struct commonNaN {
| 16-bit floating-point signaling NaN. | 16-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF16UI(uiA) ((((uiA)&0x7E00) == 0x7C00) && ((uiA)&0x01FF)) #define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts
@ -100,13 +100,13 @@ struct commonNaN {
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f16UIToCommonNaN(uint_fast16_t uiA, struct commonNaN* zPtr); void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast16_t softfloat_commonNaNToF16UI(const struct commonNaN* aPtr); uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating-
@ -114,7 +114,8 @@ uint_fast16_t softfloat_commonNaNToF16UI(const struct commonNaN* aPtr);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB); uint_fast16_t
softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 32-bit floating-point NaN. | The bit pattern for a default generated 32-bit floating-point NaN.
@ -126,7 +127,7 @@ uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
| 32-bit floating-point signaling NaN. | 32-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF32UI(uiA) ((((uiA)&0x7FC00000) == 0x7F800000) && ((uiA)&0x003FFFFF)) #define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts
@ -134,13 +135,13 @@ uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f32UIToCommonNaN(uint_fast32_t uiA, struct commonNaN* zPtr); void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast32_t softfloat_commonNaNToF32UI(const struct commonNaN* aPtr); uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating-
@ -148,20 +149,20 @@ uint_fast32_t softfloat_commonNaNToF32UI(const struct commonNaN* aPtr);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast32_t softfloat_propagateNaNF32UI(uint_fast32_t uiA, uint_fast32_t uiB); uint_fast32_t
softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 64-bit floating-point NaN. | The bit pattern for a default generated 64-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNF64UI UINT64_C(0x7FF8000000000000) #define defaultNaNF64UI UINT64_C( 0x7FF8000000000000 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a | Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a
| 64-bit floating-point signaling NaN. | 64-bit floating-point signaling NaN.
| Note: This macro evaluates its argument more than once. | Note: This macro evaluates its argument more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF64UI(uiA) \ #define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF )))
((((uiA)&UINT64_C(0x7FF8000000000000)) == UINT64_C(0x7FF0000000000000)) && ((uiA)&UINT64_C(0x0007FFFFFFFFFFFF)))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts | Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts
@ -169,13 +170,13 @@ uint_fast32_t softfloat_propagateNaNF32UI(uint_fast32_t uiA, uint_fast32_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f64UIToCommonNaN(uint_fast64_t uiA, struct commonNaN* zPtr); void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast64_t softfloat_commonNaNToF64UI(const struct commonNaN* aPtr); uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating-
@ -183,13 +184,14 @@ uint_fast64_t softfloat_commonNaNToF64UI(const struct commonNaN* aPtr);
| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a | the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a
| signaling NaN, the invalid exception is raised. | signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB); uint_fast64_t
softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 80-bit extended floating-point NaN. | The bit pattern for a default generated 80-bit extended floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNExtF80UI64 0xFFFF #define defaultNaNExtF80UI64 0xFFFF
#define defaultNaNExtF80UI0 UINT64_C(0xC000000000000000) #define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when the 80-bit unsigned integer formed from concatenating | Returns true when the 80-bit unsigned integer formed from concatenating
@ -197,8 +199,7 @@ uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB);
| floating-point signaling NaN. | floating-point signaling NaN.
| Note: This macro evaluates its arguments more than once. | Note: This macro evaluates its arguments more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNExtF80UI(uiA64, uiA0) \ #define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF )))
((((uiA64)&0x7FFF) == 0x7FFF) && !((uiA0)&UINT64_C(0x4000000000000000)) && ((uiA0)&UINT64_C(0x3FFFFFFFFFFFFFFF)))
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
@ -214,14 +215,16 @@ uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB);
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_extF80UIToCommonNaN(uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN* zPtr); void
softfloat_extF80UIToCommonNaN(
uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended | Converts the common NaN pointed to by 'aPtr' into an 80-bit extended
| floating-point NaN, and returns the bit pattern of this value as an unsigned | floating-point NaN, and returns the bit pattern of this value as an unsigned
| integer. | integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr); struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting the unsigned integer formed from concatenating 'uiA64' and | Interpreting the unsigned integer formed from concatenating 'uiA64' and
@ -232,13 +235,19 @@ struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr);
| result. If either original floating-point value is a signaling NaN, the | result. If either original floating-point value is a signaling NaN, the
| invalid exception is raised. | invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t uiA0, uint_fast16_t uiB64, uint_fast64_t uiB0); struct uint128
softfloat_propagateNaNExtF80UI(
uint_fast16_t uiA64,
uint_fast64_t uiA0,
uint_fast16_t uiB64,
uint_fast64_t uiB0
);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 128-bit floating-point NaN. | The bit pattern for a default generated 128-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNF128UI64 UINT64_C(0xFFFF800000000000) #define defaultNaNF128UI64 UINT64_C( 0xFFFF800000000000 )
#define defaultNaNF128UI0 UINT64_C(0) #define defaultNaNF128UI0 UINT64_C( 0 )
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when the 128-bit unsigned integer formed from concatenating | Returns true when the 128-bit unsigned integer formed from concatenating
@ -246,8 +255,7 @@ struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t
| point signaling NaN. | point signaling NaN.
| Note: This macro evaluates its arguments more than once. | Note: This macro evaluates its arguments more than once.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF128UI(uiA64, uiA0) \ #define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF ))))
((((uiA64)&UINT64_C(0x7FFF800000000000)) == UINT64_C(0x7FFF000000000000)) && ((uiA0) || ((uiA64)&UINT64_C(0x00007FFFFFFFFFFF))))
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' | Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0'
@ -256,13 +264,15 @@ struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t
| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception | pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception
| is raised. | is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f128UIToCommonNaN(uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN* zPtr); void
softfloat_f128UIToCommonNaN(
uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point
| NaN, and returns the bit pattern of this value as an unsigned integer. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN*); struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting the unsigned integer formed from concatenating 'uiA64' and | Interpreting the unsigned integer formed from concatenating 'uiA64' and
@ -273,7 +283,13 @@ struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN*);
| If either original floating-point value is a signaling NaN, the invalid | If either original floating-point value is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_propagateNaNF128UI(uint_fast64_t uiA64, uint_fast64_t uiA0, uint_fast64_t uiB64, uint_fast64_t uiB0); struct uint128
softfloat_propagateNaNF128UI(
uint_fast64_t uiA64,
uint_fast64_t uiA0,
uint_fast64_t uiB64,
uint_fast64_t uiB0
);
#else #else
@ -288,14 +304,18 @@ struct uint128 softfloat_propagateNaNF128UI(uint_fast64_t uiA64, uint_fast64_t u
| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling | common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling
| NaN, the invalid exception is raised. | NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_extF80MToCommonNaN(const struct extFloat80M* aSPtr, struct commonNaN* zPtr); void
softfloat_extF80MToCommonNaN(
const struct extFloat80M *aSPtr, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended | Converts the common NaN pointed to by 'aPtr' into an 80-bit extended
| floating-point NaN, and stores this NaN at the location pointed to by | floating-point NaN, and stores this NaN at the location pointed to by
| 'zSPtr'. | 'zSPtr'.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat80M* zSPtr); void
softfloat_commonNaNToExtF80M(
const struct commonNaN *aPtr, struct extFloat80M *zSPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming at least one of the two 80-bit extended floating-point values | Assuming at least one of the two 80-bit extended floating-point values
@ -303,7 +323,12 @@ void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat8
| at the location pointed to by 'zSPtr'. If either original floating-point | at the location pointed to by 'zSPtr'. If either original floating-point
| value is a signaling NaN, the invalid exception is raised. | value is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct extFloat80M* bSPtr, struct extFloat80M* zSPtr); void
softfloat_propagateNaNExtF80M(
const struct extFloat80M *aSPtr,
const struct extFloat80M *bSPtr,
struct extFloat80M *zSPtr
);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 128-bit floating-point NaN. | The bit pattern for a default generated 128-bit floating-point NaN.
@ -311,7 +336,7 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
#define defaultNaNF128UI96 0xFFFF8000 #define defaultNaNF128UI96 0xFFFF8000
#define defaultNaNF128UI64 0 #define defaultNaNF128UI64 0
#define defaultNaNF128UI32 0 #define defaultNaNF128UI32 0
#define defaultNaNF128UI0 0 #define defaultNaNF128UI0 0
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, | Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN,
@ -321,7 +346,8 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
| four 32-bit elements that concatenate in the platform's normal endian order | four 32-bit elements that concatenate in the platform's normal endian order
| to form a 128-bit floating-point value. | to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_f128MToCommonNaN(const uint32_t* aWPtr, struct commonNaN* zPtr); void
softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point | Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point
@ -329,7 +355,8 @@ void softfloat_f128MToCommonNaN(const uint32_t* aWPtr, struct commonNaN* zPtr);
| 'zWPtr' points to an array of four 32-bit elements that concatenate in the | 'zWPtr' points to an array of four 32-bit elements that concatenate in the
| platform's normal endian order to form a 128-bit floating-point value. | platform's normal endian order to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_commonNaNToF128M(const struct commonNaN* aPtr, uint32_t* zWPtr); void
softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming at least one of the two 128-bit floating-point values pointed to by | Assuming at least one of the two 128-bit floating-point values pointed to by
@ -339,8 +366,11 @@ void softfloat_commonNaNToF128M(const struct commonNaN* aPtr, uint32_t* zWPtr);
| and 'zWPtr' points to an array of four 32-bit elements that concatenate in | and 'zWPtr' points to an array of four 32-bit elements that concatenate in
| the platform's normal endian order to form a 128-bit floating-point value. | the platform's normal endian order to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_propagateNaNF128M(const uint32_t* aWPtr, const uint32_t* bWPtr, uint32_t* zWPtr); void
softfloat_propagateNaNF128M(
const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr );
#endif #endif
#endif #endif

View File

@ -37,205 +37,242 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef internals_h #ifndef internals_h
#define internals_h 1 #define internals_h 1
#include "primitives.h"
#include "softfloat_types.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "primitives.h"
#include "softfloat_types.h"
union ui16_f16 { union ui16_f16 { uint16_t ui; float16_t f; };
uint16_t ui; union ui32_f32 { uint32_t ui; float32_t f; };
float16_t f; union ui64_f64 { uint64_t ui; float64_t f; };
};
union ui32_f32 {
uint32_t ui;
float32_t f;
};
union ui64_f64 {
uint64_t ui;
float64_t f;
};
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
union extF80M_extF80 { union extF80M_extF80 { struct extFloat80M fM; extFloat80_t f; };
struct extFloat80M fM; union ui128_f128 { struct uint128 ui; float128_t f; };
extFloat80_t f;
};
union ui128_f128 {
struct uint128 ui;
float128_t f;
};
#endif #endif
enum { softfloat_mulAdd_subC = 1, softfloat_mulAdd_subProd = 2 }; enum {
softfloat_mulAdd_subC = 1,
softfloat_mulAdd_subProd = 2
};
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast32_t softfloat_roundToUI32(bool, uint_fast64_t, uint_fast8_t, bool); uint_fast32_t softfloat_roundToUI32( bool, uint_fast64_t, uint_fast8_t, bool );
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
uint_fast64_t softfloat_roundToUI64(bool, uint_fast64_t, uint_fast64_t, uint_fast8_t, bool); uint_fast64_t
softfloat_roundToUI64(
bool, uint_fast64_t, uint_fast64_t, uint_fast8_t, bool );
#else #else
uint_fast64_t softfloat_roundMToUI64(bool, uint32_t*, uint_fast8_t, bool); uint_fast64_t softfloat_roundMToUI64( bool, uint32_t *, uint_fast8_t, bool );
#endif #endif
int_fast32_t softfloat_roundToI32(bool, uint_fast64_t, uint_fast8_t, bool); int_fast32_t softfloat_roundToI32( bool, uint_fast64_t, uint_fast8_t, bool );
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
int_fast64_t softfloat_roundToI64(bool, uint_fast64_t, uint_fast64_t, uint_fast8_t, bool); int_fast64_t
softfloat_roundToI64(
bool, uint_fast64_t, uint_fast64_t, uint_fast8_t, bool );
#else #else
int_fast64_t softfloat_roundMToI64(bool, uint32_t*, uint_fast8_t, bool); int_fast64_t softfloat_roundMToI64( bool, uint32_t *, uint_fast8_t, bool );
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define signF16UI(a) ((bool)((uint16_t)(a) >> 15)) #define signF16UI( a ) ((bool) ((uint16_t) (a)>>15))
#define expF16UI(a) ((int_fast8_t)((a) >> 10) & 0x1F) #define expF16UI( a ) ((int_fast8_t) ((a)>>10) & 0x1F)
#define fracF16UI(a) ((a)&0x03FF) #define fracF16UI( a ) ((a) & 0x03FF)
#define packToF16UI(sign, exp, sig) (((uint16_t)(sign) << 15) + ((uint16_t)(exp) << 10) + (sig)) #define packToF16UI( sign, exp, sig ) (((uint16_t) (sign)<<15) + ((uint16_t) (exp)<<10) + (sig))
#define isNaNF16UI(a) (((~(a)&0x7C00) == 0) && ((a)&0x03FF)) #define isNaNF16UI( a ) (((~(a) & 0x7C00) == 0) && ((a) & 0x03FF))
struct exp8_sig16 { struct exp8_sig16 { int_fast8_t exp; uint_fast16_t sig; };
int_fast8_t exp; struct exp8_sig16 softfloat_normSubnormalF16Sig( uint_fast16_t );
uint_fast16_t sig;
};
struct exp8_sig16 softfloat_normSubnormalF16Sig(uint_fast16_t);
float16_t softfloat_roundPackToF16(bool, int_fast16_t, uint_fast16_t); float16_t softfloat_roundPackToF16( bool, int_fast16_t, uint_fast16_t );
float16_t softfloat_normRoundPackToF16(bool, int_fast16_t, uint_fast16_t); float16_t softfloat_normRoundPackToF16( bool, int_fast16_t, uint_fast16_t );
float16_t softfloat_addMagsF16(uint_fast16_t, uint_fast16_t); float16_t softfloat_addMagsF16( uint_fast16_t, uint_fast16_t );
float16_t softfloat_subMagsF16(uint_fast16_t, uint_fast16_t); float16_t softfloat_subMagsF16( uint_fast16_t, uint_fast16_t );
float16_t softfloat_mulAddF16(uint_fast16_t, uint_fast16_t, uint_fast16_t, uint_fast8_t); float16_t
softfloat_mulAddF16(
uint_fast16_t, uint_fast16_t, uint_fast16_t, uint_fast8_t );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define signF32UI(a) ((bool)((uint32_t)(a) >> 31)) #define signF32UI( a ) ((bool) ((uint32_t) (a)>>31))
#define expF32UI(a) ((int_fast16_t)((a) >> 23) & 0xFF) #define expF32UI( a ) ((int_fast16_t) ((a)>>23) & 0xFF)
#define fracF32UI(a) ((a)&0x007FFFFF) #define fracF32UI( a ) ((a) & 0x007FFFFF)
#define packToF32UI(sign, exp, sig) (((uint32_t)(sign) << 31) + ((uint32_t)(exp) << 23) + (sig)) #define packToF32UI( sign, exp, sig ) (((uint32_t) (sign)<<31) + ((uint32_t) (exp)<<23) + (sig))
#define isNaNF32UI(a) (((~(a)&0x7F800000) == 0) && ((a)&0x007FFFFF)) #define isNaNF32UI( a ) (((~(a) & 0x7F800000) == 0) && ((a) & 0x007FFFFF))
struct exp16_sig32 { struct exp16_sig32 { int_fast16_t exp; uint_fast32_t sig; };
int_fast16_t exp; struct exp16_sig32 softfloat_normSubnormalF32Sig( uint_fast32_t );
uint_fast32_t sig;
};
struct exp16_sig32 softfloat_normSubnormalF32Sig(uint_fast32_t);
float32_t softfloat_roundPackToF32(bool, int_fast16_t, uint_fast32_t); float32_t softfloat_roundPackToF32( bool, int_fast16_t, uint_fast32_t );
float32_t softfloat_normRoundPackToF32(bool, int_fast16_t, uint_fast32_t); float32_t softfloat_normRoundPackToF32( bool, int_fast16_t, uint_fast32_t );
float32_t softfloat_addMagsF32(uint_fast32_t, uint_fast32_t); float32_t softfloat_addMagsF32( uint_fast32_t, uint_fast32_t );
float32_t softfloat_subMagsF32(uint_fast32_t, uint_fast32_t); float32_t softfloat_subMagsF32( uint_fast32_t, uint_fast32_t );
float32_t softfloat_mulAddF32(uint_fast32_t, uint_fast32_t, uint_fast32_t, uint_fast8_t); float32_t
softfloat_mulAddF32(
uint_fast32_t, uint_fast32_t, uint_fast32_t, uint_fast8_t );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define signF64UI(a) ((bool)((uint64_t)(a) >> 63)) #define signF64UI( a ) ((bool) ((uint64_t) (a)>>63))
#define expF64UI(a) ((int_fast16_t)((a) >> 52) & 0x7FF) #define expF64UI( a ) ((int_fast16_t) ((a)>>52) & 0x7FF)
#define fracF64UI(a) ((a)&UINT64_C(0x000FFFFFFFFFFFFF)) #define fracF64UI( a ) ((a) & UINT64_C( 0x000FFFFFFFFFFFFF ))
#define packToF64UI(sign, exp, sig) ((uint64_t)(((uint_fast64_t)(sign) << 63) + ((uint_fast64_t)(exp) << 52) + (sig))) #define packToF64UI( sign, exp, sig ) ((uint64_t) (((uint_fast64_t) (sign)<<63) + ((uint_fast64_t) (exp)<<52) + (sig)))
#define isNaNF64UI(a) (((~(a)&UINT64_C(0x7FF0000000000000)) == 0) && ((a)&UINT64_C(0x000FFFFFFFFFFFFF))) #define isNaNF64UI( a ) (((~(a) & UINT64_C( 0x7FF0000000000000 )) == 0) && ((a) & UINT64_C( 0x000FFFFFFFFFFFFF )))
struct exp16_sig64 { struct exp16_sig64 { int_fast16_t exp; uint_fast64_t sig; };
int_fast16_t exp; struct exp16_sig64 softfloat_normSubnormalF64Sig( uint_fast64_t );
uint_fast64_t sig;
};
struct exp16_sig64 softfloat_normSubnormalF64Sig(uint_fast64_t);
float64_t softfloat_roundPackToF64(bool, int_fast16_t, uint_fast64_t); float64_t softfloat_roundPackToF64( bool, int_fast16_t, uint_fast64_t );
float64_t softfloat_normRoundPackToF64(bool, int_fast16_t, uint_fast64_t); float64_t softfloat_normRoundPackToF64( bool, int_fast16_t, uint_fast64_t );
float64_t softfloat_addMagsF64(uint_fast64_t, uint_fast64_t, bool); float64_t softfloat_addMagsF64( uint_fast64_t, uint_fast64_t, bool );
float64_t softfloat_subMagsF64(uint_fast64_t, uint_fast64_t, bool); float64_t softfloat_subMagsF64( uint_fast64_t, uint_fast64_t, bool );
float64_t softfloat_mulAddF64(uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast8_t); float64_t
softfloat_mulAddF64(
uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast8_t );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define signExtF80UI64(a64) ((bool)((uint16_t)(a64) >> 15)) #define signExtF80UI64( a64 ) ((bool) ((uint16_t) (a64)>>15))
#define expExtF80UI64(a64) ((a64)&0x7FFF) #define expExtF80UI64( a64 ) ((a64) & 0x7FFF)
#define packToExtF80UI64(sign, exp) ((uint_fast16_t)(sign) << 15 | (exp)) #define packToExtF80UI64( sign, exp ) ((uint_fast16_t) (sign)<<15 | (exp))
#define isNaNExtF80UI(a64, a0) ((((a64)&0x7FFF) == 0x7FFF) && ((a0)&UINT64_C(0x7FFFFFFFFFFFFFFF))) #define isNaNExtF80UI( a64, a0 ) ((((a64) & 0x7FFF) == 0x7FFF) && ((a0) & UINT64_C( 0x7FFFFFFFFFFFFFFF )))
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct exp32_sig64 { struct exp32_sig64 { int_fast32_t exp; uint64_t sig; };
int_fast32_t exp; struct exp32_sig64 softfloat_normSubnormalExtF80Sig( uint_fast64_t );
uint64_t sig;
};
struct exp32_sig64 softfloat_normSubnormalExtF80Sig(uint_fast64_t);
extFloat80_t softfloat_roundPackToExtF80(bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast8_t); extFloat80_t
extFloat80_t softfloat_normRoundPackToExtF80(bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast8_t); softfloat_roundPackToExtF80(
bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast8_t );
extFloat80_t
softfloat_normRoundPackToExtF80(
bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast8_t );
extFloat80_t softfloat_addMagsExtF80(uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool); extFloat80_t
extFloat80_t softfloat_subMagsExtF80(uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool); softfloat_addMagsExtF80(
uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool );
extFloat80_t
softfloat_subMagsExtF80(
uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define signF128UI64(a64) ((bool)((uint64_t)(a64) >> 63)) #define signF128UI64( a64 ) ((bool) ((uint64_t) (a64)>>63))
#define expF128UI64(a64) ((int_fast32_t)((a64) >> 48) & 0x7FFF) #define expF128UI64( a64 ) ((int_fast32_t) ((a64)>>48) & 0x7FFF)
#define fracF128UI64(a64) ((a64)&UINT64_C(0x0000FFFFFFFFFFFF)) #define fracF128UI64( a64 ) ((a64) & UINT64_C( 0x0000FFFFFFFFFFFF ))
#define packToF128UI64(sign, exp, sig64) (((uint_fast64_t)(sign) << 63) + ((uint_fast64_t)(exp) << 48) + (sig64)) #define packToF128UI64( sign, exp, sig64 ) (((uint_fast64_t) (sign)<<63) + ((uint_fast64_t) (exp)<<48) + (sig64))
#define isNaNF128UI(a64, a0) (((~(a64)&UINT64_C(0x7FFF000000000000)) == 0) && (a0 || ((a64)&UINT64_C(0x0000FFFFFFFFFFFF)))) #define isNaNF128UI( a64, a0 ) (((~(a64) & UINT64_C( 0x7FFF000000000000 )) == 0) && (a0 || ((a64) & UINT64_C( 0x0000FFFFFFFFFFFF ))))
struct exp32_sig128 { struct exp32_sig128 { int_fast32_t exp; struct uint128 sig; };
int_fast32_t exp; struct exp32_sig128
struct uint128 sig; softfloat_normSubnormalF128Sig( uint_fast64_t, uint_fast64_t );
};
struct exp32_sig128 softfloat_normSubnormalF128Sig(uint_fast64_t, uint_fast64_t);
float128_t softfloat_roundPackToF128(bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast64_t); float128_t
float128_t softfloat_normRoundPackToF128(bool, int_fast32_t, uint_fast64_t, uint_fast64_t); softfloat_roundPackToF128(
bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast64_t );
float128_t
softfloat_normRoundPackToF128(
bool, int_fast32_t, uint_fast64_t, uint_fast64_t );
float128_t softfloat_addMagsF128(uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool); float128_t
float128_t softfloat_subMagsF128(uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool); softfloat_addMagsF128(
float128_t softfloat_mulAddF128(uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast8_t); uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool );
float128_t
softfloat_subMagsF128(
uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool );
float128_t
softfloat_mulAddF128(
uint_fast64_t,
uint_fast64_t,
uint_fast64_t,
uint_fast64_t,
uint_fast64_t,
uint_fast64_t,
uint_fast8_t
);
#else #else
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
bool softfloat_tryPropagateNaNExtF80M(const struct extFloat80M*, const struct extFloat80M*, struct extFloat80M*); bool
void softfloat_invalidExtF80M(struct extFloat80M*); softfloat_tryPropagateNaNExtF80M(
const struct extFloat80M *,
const struct extFloat80M *,
struct extFloat80M *
);
void softfloat_invalidExtF80M( struct extFloat80M * );
int softfloat_normExtF80SigM(uint64_t*); int softfloat_normExtF80SigM( uint64_t * );
void softfloat_roundPackMToExtF80M(bool, int32_t, uint32_t*, uint_fast8_t, struct extFloat80M*); void
void softfloat_normRoundPackMToExtF80M(bool, int32_t, uint32_t*, uint_fast8_t, struct extFloat80M*); softfloat_roundPackMToExtF80M(
bool, int32_t, uint32_t *, uint_fast8_t, struct extFloat80M * );
void
softfloat_normRoundPackMToExtF80M(
bool, int32_t, uint32_t *, uint_fast8_t, struct extFloat80M * );
void softfloat_addExtF80M(const struct extFloat80M*, const struct extFloat80M*, struct extFloat80M*, bool); void
softfloat_addExtF80M(
const struct extFloat80M *,
const struct extFloat80M *,
struct extFloat80M *,
bool
);
int softfloat_compareNonnormExtF80M(const struct extFloat80M*, const struct extFloat80M*); int
softfloat_compareNonnormExtF80M(
const struct extFloat80M *, const struct extFloat80M * );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define signF128UI96(a96) ((bool)((uint32_t)(a96) >> 31)) #define signF128UI96( a96 ) ((bool) ((uint32_t) (a96)>>31))
#define expF128UI96(a96) ((int32_t)((a96) >> 16) & 0x7FFF) #define expF128UI96( a96 ) ((int32_t) ((a96)>>16) & 0x7FFF)
#define fracF128UI96(a96) ((a96)&0x0000FFFF) #define fracF128UI96( a96 ) ((a96) & 0x0000FFFF)
#define packToF128UI96(sign, exp, sig96) (((uint32_t)(sign) << 31) + ((uint32_t)(exp) << 16) + (sig96)) #define packToF128UI96( sign, exp, sig96 ) (((uint32_t) (sign)<<31) + ((uint32_t) (exp)<<16) + (sig96))
bool softfloat_isNaNF128M(const uint32_t*); bool softfloat_isNaNF128M( const uint32_t * );
bool softfloat_tryPropagateNaNF128M(const uint32_t*, const uint32_t*, uint32_t*); bool
void softfloat_invalidF128M(uint32_t*); softfloat_tryPropagateNaNF128M(
const uint32_t *, const uint32_t *, uint32_t * );
void softfloat_invalidF128M( uint32_t * );
int softfloat_shiftNormSigF128M(const uint32_t*, uint_fast8_t, uint32_t*); int softfloat_shiftNormSigF128M( const uint32_t *, uint_fast8_t, uint32_t * );
void softfloat_roundPackMToF128M(bool, int32_t, uint32_t*, uint32_t*); void softfloat_roundPackMToF128M( bool, int32_t, uint32_t *, uint32_t * );
void softfloat_normRoundPackMToF128M(bool, int32_t, uint32_t*, uint32_t*); void softfloat_normRoundPackMToF128M( bool, int32_t, uint32_t *, uint32_t * );
void softfloat_addF128M(const uint32_t*, const uint32_t*, uint32_t*, bool); void
void softfloat_mulAddF128M(const uint32_t*, const uint32_t*, const uint32_t*, uint32_t*, uint_fast8_t); softfloat_addF128M( const uint32_t *, const uint32_t *, uint32_t *, bool );
void
softfloat_mulAddF128M(
const uint32_t *,
const uint32_t *,
const uint32_t *,
uint32_t *,
uint_fast8_t
);
#endif #endif
#endif #endif

View File

@ -39,70 +39,70 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef INLINE #ifdef INLINE
#include "primitiveTypes.h"
#include <stdint.h> #include <stdint.h>
#include "primitiveTypes.h"
#ifdef SOFTFLOAT_BUILTIN_CLZ #ifdef SOFTFLOAT_BUILTIN_CLZ
INLINE uint_fast8_t softfloat_countLeadingZeros16(uint16_t a) { return a ? __builtin_clz(a) - 16 : 16; } INLINE uint_fast8_t softfloat_countLeadingZeros16( uint16_t a )
{ return a ? __builtin_clz( a ) - 16 : 16; }
#define softfloat_countLeadingZeros16 softfloat_countLeadingZeros16 #define softfloat_countLeadingZeros16 softfloat_countLeadingZeros16
INLINE uint_fast8_t softfloat_countLeadingZeros32(uint32_t a) { return a ? __builtin_clz(a) : 32; } INLINE uint_fast8_t softfloat_countLeadingZeros32( uint32_t a )
{ return a ? __builtin_clz( a ) : 32; }
#define softfloat_countLeadingZeros32 softfloat_countLeadingZeros32 #define softfloat_countLeadingZeros32 softfloat_countLeadingZeros32
INLINE uint_fast8_t softfloat_countLeadingZeros64(uint64_t a) { return a ? __builtin_clzll(a) : 64; } INLINE uint_fast8_t softfloat_countLeadingZeros64( uint64_t a )
{ return a ? __builtin_clzll( a ) : 64; }
#define softfloat_countLeadingZeros64 softfloat_countLeadingZeros64 #define softfloat_countLeadingZeros64 softfloat_countLeadingZeros64
#endif #endif
#ifdef SOFTFLOAT_INTRINSIC_INT128 #ifdef SOFTFLOAT_INTRINSIC_INT128
INLINE struct uint128 softfloat_mul64ByShifted32To128(uint64_t a, uint32_t b) { INLINE struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b )
union { {
unsigned __int128 ui; union { unsigned __int128 ui; struct uint128 s; } uZ;
struct uint128 s; uZ.ui = (unsigned __int128) a * ((uint_fast64_t) b<<32);
} uZ;
uZ.ui = (unsigned __int128)a * ((uint_fast64_t)b << 32);
return uZ.s; return uZ.s;
} }
#define softfloat_mul64ByShifted32To128 softfloat_mul64ByShifted32To128 #define softfloat_mul64ByShifted32To128 softfloat_mul64ByShifted32To128
INLINE struct uint128 softfloat_mul64To128(uint64_t a, uint64_t b) { INLINE struct uint128 softfloat_mul64To128( uint64_t a, uint64_t b )
union { {
unsigned __int128 ui; union { unsigned __int128 ui; struct uint128 s; } uZ;
struct uint128 s; uZ.ui = (unsigned __int128) a * b;
} uZ;
uZ.ui = (unsigned __int128)a * b;
return uZ.s; return uZ.s;
} }
#define softfloat_mul64To128 softfloat_mul64To128 #define softfloat_mul64To128 softfloat_mul64To128
INLINE INLINE
struct uint128 softfloat_mul128By32(uint64_t a64, uint64_t a0, uint32_t b) { struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b )
union { {
unsigned __int128 ui; union { unsigned __int128 ui; struct uint128 s; } uZ;
struct uint128 s; uZ.ui = ((unsigned __int128) a64<<64 | a0) * b;
} uZ;
uZ.ui = ((unsigned __int128)a64 << 64 | a0) * b;
return uZ.s; return uZ.s;
} }
#define softfloat_mul128By32 softfloat_mul128By32 #define softfloat_mul128By32 softfloat_mul128By32
INLINE INLINE
void softfloat_mul128To256M(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0, uint64_t* zPtr) { void
softfloat_mul128To256M(
uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0, uint64_t *zPtr )
{
unsigned __int128 z0, mid1, mid, z128; unsigned __int128 z0, mid1, mid, z128;
z0 = (unsigned __int128)a0 * b0; z0 = (unsigned __int128) a0 * b0;
mid1 = (unsigned __int128)a64 * b0; mid1 = (unsigned __int128) a64 * b0;
mid = mid1 + (unsigned __int128)a0 * b64; mid = mid1 + (unsigned __int128) a0 * b64;
z128 = (unsigned __int128)a64 * b64; z128 = (unsigned __int128) a64 * b64;
z128 += (unsigned __int128)(mid < mid1) << 64 | mid >> 64; z128 += (unsigned __int128) (mid < mid1)<<64 | mid>>64;
mid <<= 64; mid <<= 64;
z0 += mid; z0 += mid;
z128 += (z0 < mid); z128 += (z0 < mid);
zPtr[indexWord(4, 0)] = z0; zPtr[indexWord( 4, 0 )] = z0;
zPtr[indexWord(4, 1)] = z0 >> 64; zPtr[indexWord( 4, 1 )] = z0>>64;
zPtr[indexWord(4, 2)] = z128; zPtr[indexWord( 4, 2 )] = z128;
zPtr[indexWord(4, 3)] = z128 >> 64; zPtr[indexWord( 4, 3 )] = z128>>64;
} }
#define softfloat_mul128To256M softfloat_mul128To256M #define softfloat_mul128To256M softfloat_mul128To256M
@ -111,3 +111,4 @@ void softfloat_mul128To256M(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0
#endif #endif
#endif #endif

View File

@ -42,27 +42,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
#ifdef LITTLEENDIAN #ifdef LITTLEENDIAN
struct uint128 { struct uint128 { uint64_t v0, v64; };
uint64_t v0, v64; struct uint64_extra { uint64_t extra, v; };
}; struct uint128_extra { uint64_t extra; struct uint128 v; };
struct uint64_extra {
uint64_t extra, v;
};
struct uint128_extra {
uint64_t extra;
struct uint128 v;
};
#else #else
struct uint128 { struct uint128 { uint64_t v64, v0; };
uint64_t v64, v0; struct uint64_extra { uint64_t v, extra; };
}; struct uint128_extra { struct uint128 v; uint64_t extra; };
struct uint64_extra {
uint64_t v, extra;
};
struct uint128_extra {
struct uint128 v;
uint64_t extra;
};
#endif #endif
#endif #endif
@ -73,28 +59,27 @@ struct uint128_extra {
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef LITTLEENDIAN #ifdef LITTLEENDIAN
#define wordIncr 1 #define wordIncr 1
#define indexWord(total, n) (n) #define indexWord( total, n ) (n)
#define indexWordHi(total) ((total)-1) #define indexWordHi( total ) ((total) - 1)
#define indexWordLo(total) 0 #define indexWordLo( total ) 0
#define indexMultiword(total, m, n) (n) #define indexMultiword( total, m, n ) (n)
#define indexMultiwordHi(total, n) ((total) - (n)) #define indexMultiwordHi( total, n ) ((total) - (n))
#define indexMultiwordLo(total, n) 0 #define indexMultiwordLo( total, n ) 0
#define indexMultiwordHiBut(total, n) (n) #define indexMultiwordHiBut( total, n ) (n)
#define indexMultiwordLoBut(total, n) 0 #define indexMultiwordLoBut( total, n ) 0
#define INIT_UINTM4(v3, v2, v1, v0) \ #define INIT_UINTM4( v3, v2, v1, v0 ) { v0, v1, v2, v3 }
{ v0, v1, v2, v3 }
#else #else
#define wordIncr -1 #define wordIncr -1
#define indexWord(total, n) ((total)-1 - (n)) #define indexWord( total, n ) ((total) - 1 - (n))
#define indexWordHi(total) 0 #define indexWordHi( total ) 0
#define indexWordLo(total) ((total)-1) #define indexWordLo( total ) ((total) - 1)
#define indexMultiword(total, m, n) ((total)-1 - (m)) #define indexMultiword( total, m, n ) ((total) - 1 - (m))
#define indexMultiwordHi(total, n) 0 #define indexMultiwordHi( total, n ) 0
#define indexMultiwordLo(total, n) ((total) - (n)) #define indexMultiwordLo( total, n ) ((total) - (n))
#define indexMultiwordHiBut(total, n) 0 #define indexMultiwordHiBut( total, n ) 0
#define indexMultiwordLoBut(total, n) (n) #define indexMultiwordLoBut( total, n ) (n)
#define INIT_UINTM4(v3, v2, v1, v0) \ #define INIT_UINTM4( v3, v2, v1, v0 ) { v3, v2, v1, v0 }
{ v3, v2, v1, v0 }
#endif #endif
#endif #endif

View File

@ -37,9 +37,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef primitives_h #ifndef primitives_h
#define primitives_h 1 #define primitives_h 1
#include "primitiveTypes.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "primitiveTypes.h"
#ifndef softfloat_shortShiftRightJam64 #ifndef softfloat_shortShiftRightJam64
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -50,9 +50,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL)
INLINE INLINE
uint64_t softfloat_shortShiftRightJam64(uint64_t a, uint_fast8_t dist) { return a >> dist | ((a & (((uint_fast64_t)1 << dist) - 1)) != 0); } uint64_t softfloat_shortShiftRightJam64( uint64_t a, uint_fast8_t dist )
{ return a>>dist | ((a & (((uint_fast64_t) 1<<dist) - 1)) != 0); }
#else #else
uint64_t softfloat_shortShiftRightJam64(uint64_t a, uint_fast8_t dist); uint64_t softfloat_shortShiftRightJam64( uint64_t a, uint_fast8_t dist );
#endif #endif
#endif #endif
@ -67,11 +68,13 @@ uint64_t softfloat_shortShiftRightJam64(uint64_t a, uint_fast8_t dist);
| is zero or nonzero. | is zero or nonzero.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL)
INLINE uint32_t softfloat_shiftRightJam32(uint32_t a, uint_fast16_t dist) { INLINE uint32_t softfloat_shiftRightJam32( uint32_t a, uint_fast16_t dist )
return (dist < 31) ? a >> dist | ((uint32_t)(a << (-dist & 31)) != 0) : (a != 0); {
return
(dist < 31) ? a>>dist | ((uint32_t) (a<<(-dist & 31)) != 0) : (a != 0);
} }
#else #else
uint32_t softfloat_shiftRightJam32(uint32_t a, uint_fast16_t dist); uint32_t softfloat_shiftRightJam32( uint32_t a, uint_fast16_t dist );
#endif #endif
#endif #endif
@ -86,11 +89,13 @@ uint32_t softfloat_shiftRightJam32(uint32_t a, uint_fast16_t dist);
| is zero or nonzero. | is zero or nonzero.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (3 <= INLINE_LEVEL)
INLINE uint64_t softfloat_shiftRightJam64(uint64_t a, uint_fast32_t dist) { INLINE uint64_t softfloat_shiftRightJam64( uint64_t a, uint_fast32_t dist )
return (dist < 63) ? a >> dist | ((uint64_t)(a << (-dist & 63)) != 0) : (a != 0); {
return
(dist < 63) ? a>>dist | ((uint64_t) (a<<(-dist & 63)) != 0) : (a != 0);
} }
#else #else
uint64_t softfloat_shiftRightJam64(uint64_t a, uint_fast32_t dist); uint64_t softfloat_shiftRightJam64( uint64_t a, uint_fast32_t dist );
#endif #endif
#endif #endif
@ -107,9 +112,10 @@ extern const uint_least8_t softfloat_countLeadingZeros8[256];
| 'a'. If 'a' is zero, 16 is returned. | 'a'. If 'a' is zero, 16 is returned.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL)
INLINE uint_fast8_t softfloat_countLeadingZeros16(uint16_t a) { INLINE uint_fast8_t softfloat_countLeadingZeros16( uint16_t a )
{
uint_fast8_t count = 8; uint_fast8_t count = 8;
if(0x100 <= a) { if ( 0x100 <= a ) {
count = 0; count = 0;
a >>= 8; a >>= 8;
} }
@ -117,7 +123,7 @@ INLINE uint_fast8_t softfloat_countLeadingZeros16(uint16_t a) {
return count; return count;
} }
#else #else
uint_fast8_t softfloat_countLeadingZeros16(uint16_t a); uint_fast8_t softfloat_countLeadingZeros16( uint16_t a );
#endif #endif
#endif #endif
@ -127,21 +133,22 @@ uint_fast8_t softfloat_countLeadingZeros16(uint16_t a);
| 'a'. If 'a' is zero, 32 is returned. | 'a'. If 'a' is zero, 32 is returned.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (3 <= INLINE_LEVEL)
INLINE uint_fast8_t softfloat_countLeadingZeros32(uint32_t a) { INLINE uint_fast8_t softfloat_countLeadingZeros32( uint32_t a )
{
uint_fast8_t count = 0; uint_fast8_t count = 0;
if(a < 0x10000) { if ( a < 0x10000 ) {
count = 16; count = 16;
a <<= 16; a <<= 16;
} }
if(a < 0x1000000) { if ( a < 0x1000000 ) {
count += 8; count += 8;
a <<= 8; a <<= 8;
} }
count += softfloat_countLeadingZeros8[a >> 24]; count += softfloat_countLeadingZeros8[a>>24];
return count; return count;
} }
#else #else
uint_fast8_t softfloat_countLeadingZeros32(uint32_t a); uint_fast8_t softfloat_countLeadingZeros32( uint32_t a );
#endif #endif
#endif #endif
@ -150,7 +157,7 @@ uint_fast8_t softfloat_countLeadingZeros32(uint32_t a);
| Returns the number of leading 0 bits before the most-significant 1 bit of | Returns the number of leading 0 bits before the most-significant 1 bit of
| 'a'. If 'a' is zero, 64 is returned. | 'a'. If 'a' is zero, 64 is returned.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast8_t softfloat_countLeadingZeros64(uint64_t a); uint_fast8_t softfloat_countLeadingZeros64( uint64_t a );
#endif #endif
extern const uint16_t softfloat_approxRecip_1k0s[16]; extern const uint16_t softfloat_approxRecip_1k0s[16];
@ -169,9 +176,9 @@ extern const uint16_t softfloat_approxRecip_1k1s[16];
| (units in the last place). | (units in the last place).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef SOFTFLOAT_FAST_DIV64TO32 #ifdef SOFTFLOAT_FAST_DIV64TO32
#define softfloat_approxRecip32_1(a) ((uint32_t)(UINT64_C(0x7FFFFFFFFFFFFFFF) / (uint32_t)(a))) #define softfloat_approxRecip32_1( a ) ((uint32_t) (UINT64_C( 0x7FFFFFFFFFFFFFFF ) / (uint32_t) (a)))
#else #else
uint32_t softfloat_approxRecip32_1(uint32_t a); uint32_t softfloat_approxRecip32_1( uint32_t a );
#endif #endif
#endif #endif
@ -197,7 +204,7 @@ extern const uint16_t softfloat_approxRecipSqrt_1k1s[16];
| returned is also always within the range 0.5 to 1; thus, the most- | returned is also always within the range 0.5 to 1; thus, the most-
| significant bit of the result is always set. | significant bit of the result is always set.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint32_t softfloat_approxRecipSqrt32_1(unsigned int oddExpA, uint32_t a); uint32_t softfloat_approxRecipSqrt32_1( unsigned int oddExpA, uint32_t a );
#endif #endif
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
@ -215,9 +222,10 @@ uint32_t softfloat_approxRecipSqrt32_1(unsigned int oddExpA, uint32_t a);
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (1 <= INLINE_LEVEL)
INLINE INLINE
bool softfloat_eq128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0) { return (a64 == b64) && (a0 == b0); } bool softfloat_eq128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
{ return (a64 == b64) && (a0 == b0); }
#else #else
bool softfloat_eq128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0); bool softfloat_eq128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 );
#endif #endif
#endif #endif
@ -229,9 +237,10 @@ bool softfloat_eq128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0);
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL)
INLINE INLINE
bool softfloat_le128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0) { return (a64 < b64) || ((a64 == b64) && (a0 <= b0)); } bool softfloat_le128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
{ return (a64 < b64) || ((a64 == b64) && (a0 <= b0)); }
#else #else
bool softfloat_le128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0); bool softfloat_le128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 );
#endif #endif
#endif #endif
@ -243,9 +252,10 @@ bool softfloat_le128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0);
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL)
INLINE INLINE
bool softfloat_lt128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0) { return (a64 < b64) || ((a64 == b64) && (a0 < b0)); } bool softfloat_lt128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
{ return (a64 < b64) || ((a64 == b64) && (a0 < b0)); }
#else #else
bool softfloat_lt128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0); bool softfloat_lt128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 );
#endif #endif
#endif #endif
@ -256,14 +266,17 @@ bool softfloat_lt128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0);
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL)
INLINE INLINE
struct uint128 softfloat_shortShiftLeft128(uint64_t a64, uint64_t a0, uint_fast8_t dist) { struct uint128
softfloat_shortShiftLeft128( uint64_t a64, uint64_t a0, uint_fast8_t dist )
{
struct uint128 z; struct uint128 z;
z.v64 = a64 << dist | a0 >> (-dist & 63); z.v64 = a64<<dist | a0>>(-dist & 63);
z.v0 = a0 << dist; z.v0 = a0<<dist;
return z; return z;
} }
#else #else
struct uint128 softfloat_shortShiftLeft128(uint64_t a64, uint64_t a0, uint_fast8_t dist); struct uint128
softfloat_shortShiftLeft128( uint64_t a64, uint64_t a0, uint_fast8_t dist );
#endif #endif
#endif #endif
@ -274,14 +287,17 @@ struct uint128 softfloat_shortShiftLeft128(uint64_t a64, uint64_t a0, uint_fast8
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL)
INLINE INLINE
struct uint128 softfloat_shortShiftRight128(uint64_t a64, uint64_t a0, uint_fast8_t dist) { struct uint128
softfloat_shortShiftRight128( uint64_t a64, uint64_t a0, uint_fast8_t dist )
{
struct uint128 z; struct uint128 z;
z.v64 = a64 >> dist; z.v64 = a64>>dist;
z.v0 = a64 << (-dist & 63) | a0 >> dist; z.v0 = a64<<(-dist & 63) | a0>>dist;
return z; return z;
} }
#else #else
struct uint128 softfloat_shortShiftRight128(uint64_t a64, uint64_t a0, uint_fast8_t dist); struct uint128
softfloat_shortShiftRight128( uint64_t a64, uint64_t a0, uint_fast8_t dist );
#endif #endif
#endif #endif
@ -292,14 +308,19 @@ struct uint128 softfloat_shortShiftRight128(uint64_t a64, uint64_t a0, uint_fast
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL)
INLINE INLINE
struct uint64_extra softfloat_shortShiftRightJam64Extra(uint64_t a, uint64_t extra, uint_fast8_t dist) { struct uint64_extra
softfloat_shortShiftRightJam64Extra(
uint64_t a, uint64_t extra, uint_fast8_t dist )
{
struct uint64_extra z; struct uint64_extra z;
z.v = a >> dist; z.v = a>>dist;
z.extra = a << (-dist & 63) | (extra != 0); z.extra = a<<(-dist & 63) | (extra != 0);
return z; return z;
} }
#else #else
struct uint64_extra softfloat_shortShiftRightJam64Extra(uint64_t a, uint64_t extra, uint_fast8_t dist); struct uint64_extra
softfloat_shortShiftRightJam64Extra(
uint64_t a, uint64_t extra, uint_fast8_t dist );
#endif #endif
#endif #endif
@ -313,15 +334,22 @@ struct uint64_extra softfloat_shortShiftRightJam64Extra(uint64_t a, uint64_t ext
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (3 <= INLINE_LEVEL)
INLINE INLINE
struct uint128 softfloat_shortShiftRightJam128(uint64_t a64, uint64_t a0, uint_fast8_t dist) { struct uint128
softfloat_shortShiftRightJam128(
uint64_t a64, uint64_t a0, uint_fast8_t dist )
{
uint_fast8_t negDist = -dist; uint_fast8_t negDist = -dist;
struct uint128 z; struct uint128 z;
z.v64 = a64 >> dist; z.v64 = a64>>dist;
z.v0 = a64 << (negDist & 63) | a0 >> dist | ((uint64_t)(a0 << (negDist & 63)) != 0); z.v0 =
a64<<(negDist & 63) | a0>>dist
| ((uint64_t) (a0<<(negDist & 63)) != 0);
return z; return z;
} }
#else #else
struct uint128 softfloat_shortShiftRightJam128(uint64_t a64, uint64_t a0, uint_fast8_t dist); struct uint128
softfloat_shortShiftRightJam128(
uint64_t a64, uint64_t a0, uint_fast8_t dist );
#endif #endif
#endif #endif
@ -332,16 +360,21 @@ struct uint128 softfloat_shortShiftRightJam128(uint64_t a64, uint64_t a0, uint_f
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (3 <= INLINE_LEVEL)
INLINE INLINE
struct uint128_extra softfloat_shortShiftRightJam128Extra(uint64_t a64, uint64_t a0, uint64_t extra, uint_fast8_t dist) { struct uint128_extra
softfloat_shortShiftRightJam128Extra(
uint64_t a64, uint64_t a0, uint64_t extra, uint_fast8_t dist )
{
uint_fast8_t negDist = -dist; uint_fast8_t negDist = -dist;
struct uint128_extra z; struct uint128_extra z;
z.v.v64 = a64 >> dist; z.v.v64 = a64>>dist;
z.v.v0 = a64 << (negDist & 63) | a0 >> dist; z.v.v0 = a64<<(negDist & 63) | a0>>dist;
z.extra = a0 << (negDist & 63) | (extra != 0); z.extra = a0<<(negDist & 63) | (extra != 0);
return z; return z;
} }
#else #else
struct uint128_extra softfloat_shortShiftRightJam128Extra(uint64_t a64, uint64_t a0, uint64_t extra, uint_fast8_t dist); struct uint128_extra
softfloat_shortShiftRightJam128Extra(
uint64_t a64, uint64_t a0, uint64_t extra, uint_fast8_t dist );
#endif #endif
#endif #endif
@ -364,11 +397,14 @@ struct uint128_extra softfloat_shortShiftRightJam128Extra(uint64_t a64, uint64_t
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (4 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (4 <= INLINE_LEVEL)
INLINE INLINE
struct uint64_extra softfloat_shiftRightJam64Extra(uint64_t a, uint64_t extra, uint_fast32_t dist) { struct uint64_extra
softfloat_shiftRightJam64Extra(
uint64_t a, uint64_t extra, uint_fast32_t dist )
{
struct uint64_extra z; struct uint64_extra z;
if(dist < 64) { if ( dist < 64 ) {
z.v = a >> dist; z.v = a>>dist;
z.extra = a << (-dist & 63); z.extra = a<<(-dist & 63);
} else { } else {
z.v = 0; z.v = 0;
z.extra = (dist == 64) ? a : (a != 0); z.extra = (dist == 64) ? a : (a != 0);
@ -377,7 +413,9 @@ struct uint64_extra softfloat_shiftRightJam64Extra(uint64_t a, uint64_t extra, u
return z; return z;
} }
#else #else
struct uint64_extra softfloat_shiftRightJam64Extra(uint64_t a, uint64_t extra, uint_fast32_t dist); struct uint64_extra
softfloat_shiftRightJam64Extra(
uint64_t a, uint64_t extra, uint_fast32_t dist );
#endif #endif
#endif #endif
@ -392,7 +430,8 @@ struct uint64_extra softfloat_shiftRightJam64Extra(uint64_t a, uint64_t extra, u
| greater than 128, the result will be either 0 or 1, depending on whether the | greater than 128, the result will be either 0 or 1, depending on whether the
| original 128 bits are all zeros. | original 128 bits are all zeros.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_shiftRightJam128(uint64_t a64, uint64_t a0, uint_fast32_t dist); struct uint128
softfloat_shiftRightJam128( uint64_t a64, uint64_t a0, uint_fast32_t dist );
#endif #endif
#ifndef softfloat_shiftRightJam128Extra #ifndef softfloat_shiftRightJam128Extra
@ -413,7 +452,9 @@ struct uint128 softfloat_shiftRightJam128(uint64_t a64, uint64_t a0, uint_fast32
| is modified as described above and returned in the 'extra' field of the | is modified as described above and returned in the 'extra' field of the
| result.) | result.)
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128_extra softfloat_shiftRightJam128Extra(uint64_t a64, uint64_t a0, uint64_t extra, uint_fast32_t dist); struct uint128_extra
softfloat_shiftRightJam128Extra(
uint64_t a64, uint64_t a0, uint64_t extra, uint_fast32_t dist );
#endif #endif
#ifndef softfloat_shiftRightJam256M #ifndef softfloat_shiftRightJam256M
@ -429,7 +470,9 @@ struct uint128_extra softfloat_shiftRightJam128Extra(uint64_t a64, uint64_t a0,
| is greater than 256, the stored result will be either 0 or 1, depending on | is greater than 256, the stored result will be either 0 or 1, depending on
| whether the original 256 bits are all zeros. | whether the original 256 bits are all zeros.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_shiftRightJam256M(const uint64_t* aPtr, uint_fast32_t dist, uint64_t* zPtr); void
softfloat_shiftRightJam256M(
const uint64_t *aPtr, uint_fast32_t dist, uint64_t *zPtr );
#endif #endif
#ifndef softfloat_add128 #ifndef softfloat_add128
@ -440,14 +483,17 @@ void softfloat_shiftRightJam256M(const uint64_t* aPtr, uint_fast32_t dist, uint6
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL)
INLINE INLINE
struct uint128 softfloat_add128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0) { struct uint128
softfloat_add128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
{
struct uint128 z; struct uint128 z;
z.v0 = a0 + b0; z.v0 = a0 + b0;
z.v64 = a64 + b64 + (z.v0 < a0); z.v64 = a64 + b64 + (z.v0 < a0);
return z; return z;
} }
#else #else
struct uint128 softfloat_add128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0); struct uint128
softfloat_add128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 );
#endif #endif
#endif #endif
@ -459,7 +505,9 @@ struct uint128 softfloat_add128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_
| an array of four 64-bit elements that concatenate in the platform's normal | an array of four 64-bit elements that concatenate in the platform's normal
| endian order to form a 256-bit integer. | endian order to form a 256-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_add256M(const uint64_t* aPtr, const uint64_t* bPtr, uint64_t* zPtr); void
softfloat_add256M(
const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr );
#endif #endif
#ifndef softfloat_sub128 #ifndef softfloat_sub128
@ -470,7 +518,9 @@ void softfloat_add256M(const uint64_t* aPtr, const uint64_t* bPtr, uint64_t* zPt
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL)
INLINE INLINE
struct uint128 softfloat_sub128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0) { struct uint128
softfloat_sub128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
{
struct uint128 z; struct uint128 z;
z.v0 = a0 - b0; z.v0 = a0 - b0;
z.v64 = a64 - b64; z.v64 = a64 - b64;
@ -478,7 +528,8 @@ struct uint128 softfloat_sub128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_
return z; return z;
} }
#else #else
struct uint128 softfloat_sub128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0); struct uint128
softfloat_sub128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 );
#endif #endif
#endif #endif
@ -491,7 +542,9 @@ struct uint128 softfloat_sub128(uint64_t a64, uint64_t a0, uint64_t b64, uint64_
| 64-bit elements that concatenate in the platform's normal endian order to | 64-bit elements that concatenate in the platform's normal endian order to
| form a 256-bit integer. | form a 256-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_sub256M(const uint64_t* aPtr, const uint64_t* bPtr, uint64_t* zPtr); void
softfloat_sub256M(
const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr );
#endif #endif
#ifndef softfloat_mul64ByShifted32To128 #ifndef softfloat_mul64ByShifted32To128
@ -499,16 +552,17 @@ void softfloat_sub256M(const uint64_t* aPtr, const uint64_t* bPtr, uint64_t* zPt
| Returns the 128-bit product of 'a', 'b', and 2^32. | Returns the 128-bit product of 'a', 'b', and 2^32.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (3 <= INLINE_LEVEL)
INLINE struct uint128 softfloat_mul64ByShifted32To128(uint64_t a, uint32_t b) { INLINE struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b )
{
uint_fast64_t mid; uint_fast64_t mid;
struct uint128 z; struct uint128 z;
mid = (uint_fast64_t)(uint32_t)a * b; mid = (uint_fast64_t) (uint32_t) a * b;
z.v0 = mid << 32; z.v0 = mid<<32;
z.v64 = (uint_fast64_t)(uint32_t)(a >> 32) * b + (mid >> 32); z.v64 = (uint_fast64_t) (uint32_t) (a>>32) * b + (mid>>32);
return z; return z;
} }
#else #else
struct uint128 softfloat_mul64ByShifted32To128(uint64_t a, uint32_t b); struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b );
#endif #endif
#endif #endif
@ -516,7 +570,7 @@ struct uint128 softfloat_mul64ByShifted32To128(uint64_t a, uint32_t b);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns the 128-bit product of 'a' and 'b'. | Returns the 128-bit product of 'a' and 'b'.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct uint128 softfloat_mul64To128(uint64_t a, uint64_t b); struct uint128 softfloat_mul64To128( uint64_t a, uint64_t b );
#endif #endif
#ifndef softfloat_mul128By32 #ifndef softfloat_mul128By32
@ -527,18 +581,19 @@ struct uint128 softfloat_mul64To128(uint64_t a, uint64_t b);
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (4 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (4 <= INLINE_LEVEL)
INLINE INLINE
struct uint128 softfloat_mul128By32(uint64_t a64, uint64_t a0, uint32_t b) { struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b )
{
struct uint128 z; struct uint128 z;
uint_fast64_t mid; uint_fast64_t mid;
uint_fast32_t carry; uint_fast32_t carry;
z.v0 = a0 * b; z.v0 = a0 * b;
mid = (uint_fast64_t)(uint32_t)(a0 >> 32) * b; mid = (uint_fast64_t) (uint32_t) (a0>>32) * b;
carry = (uint32_t)((uint_fast32_t)(z.v0 >> 32) - (uint_fast32_t)mid); carry = (uint32_t) ((uint_fast32_t) (z.v0>>32) - (uint_fast32_t) mid);
z.v64 = a64 * b + (uint_fast32_t)((mid + carry) >> 32); z.v64 = a64 * b + (uint_fast32_t) ((mid + carry)>>32);
return z; return z;
} }
#else #else
struct uint128 softfloat_mul128By32(uint64_t a64, uint64_t a0, uint32_t b); struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b );
#endif #endif
#endif #endif
@ -550,7 +605,9 @@ struct uint128 softfloat_mul128By32(uint64_t a64, uint64_t a0, uint32_t b);
| Argument 'zPtr' points to an array of four 64-bit elements that concatenate | Argument 'zPtr' points to an array of four 64-bit elements that concatenate
| in the platform's normal endian order to form a 256-bit integer. | in the platform's normal endian order to form a 256-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_mul128To256M(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0, uint64_t* zPtr); void
softfloat_mul128To256M(
uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0, uint64_t *zPtr );
#endif #endif
#else #else
@ -569,7 +626,7 @@ void softfloat_mul128To256M(uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0
| Each of 'aPtr' and 'bPtr' points to an array of three 32-bit elements that | Each of 'aPtr' and 'bPtr' points to an array of three 32-bit elements that
| concatenate in the platform's normal endian order to form a 96-bit integer. | concatenate in the platform's normal endian order to form a 96-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
int_fast8_t softfloat_compare96M(const uint32_t* aPtr, const uint32_t* bPtr); int_fast8_t softfloat_compare96M( const uint32_t *aPtr, const uint32_t *bPtr );
#endif #endif
#ifndef softfloat_compare128M #ifndef softfloat_compare128M
@ -581,7 +638,8 @@ int_fast8_t softfloat_compare96M(const uint32_t* aPtr, const uint32_t* bPtr);
| Each of 'aPtr' and 'bPtr' points to an array of four 32-bit elements that | Each of 'aPtr' and 'bPtr' points to an array of four 32-bit elements that
| concatenate in the platform's normal endian order to form a 128-bit integer. | concatenate in the platform's normal endian order to form a 128-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
int_fast8_t softfloat_compare128M(const uint32_t* aPtr, const uint32_t* bPtr); int_fast8_t
softfloat_compare128M( const uint32_t *aPtr, const uint32_t *bPtr );
#endif #endif
#ifndef softfloat_shortShiftLeft64To96M #ifndef softfloat_shortShiftLeft64To96M
@ -594,14 +652,19 @@ int_fast8_t softfloat_compare128M(const uint32_t* aPtr, const uint32_t* bPtr);
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL)
INLINE INLINE
void softfloat_shortShiftLeft64To96M(uint64_t a, uint_fast8_t dist, uint32_t* zPtr) { void
zPtr[indexWord(3, 0)] = (uint32_t)a << dist; softfloat_shortShiftLeft64To96M(
uint64_t a, uint_fast8_t dist, uint32_t *zPtr )
{
zPtr[indexWord( 3, 0 )] = (uint32_t) a<<dist;
a >>= 32 - dist; a >>= 32 - dist;
zPtr[indexWord(3, 2)] = a >> 32; zPtr[indexWord( 3, 2 )] = a>>32;
zPtr[indexWord(3, 1)] = a; zPtr[indexWord( 3, 1 )] = a;
} }
#else #else
void softfloat_shortShiftLeft64To96M(uint64_t a, uint_fast8_t dist, uint32_t* zPtr); void
softfloat_shortShiftLeft64To96M(
uint64_t a, uint_fast8_t dist, uint32_t *zPtr );
#endif #endif
#endif #endif
@ -615,7 +678,13 @@ void softfloat_shortShiftLeft64To96M(uint64_t a, uint_fast8_t dist, uint32_t* zP
| that concatenate in the platform's normal endian order to form an N-bit | that concatenate in the platform's normal endian order to form an N-bit
| integer. | integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_shortShiftLeftM(uint_fast8_t size_words, const uint32_t* aPtr, uint_fast8_t dist, uint32_t* zPtr); void
softfloat_shortShiftLeftM(
uint_fast8_t size_words,
const uint32_t *aPtr,
uint_fast8_t dist,
uint32_t *zPtr
);
#endif #endif
#ifndef softfloat_shortShiftLeft96M #ifndef softfloat_shortShiftLeft96M
@ -623,7 +692,7 @@ void softfloat_shortShiftLeftM(uint_fast8_t size_words, const uint32_t* aPtr, ui
| This function or macro is the same as 'softfloat_shortShiftLeftM' with | This function or macro is the same as 'softfloat_shortShiftLeftM' with
| 'size_words' = 3 (N = 96). | 'size_words' = 3 (N = 96).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_shortShiftLeft96M(aPtr, dist, zPtr) softfloat_shortShiftLeftM(3, aPtr, dist, zPtr) #define softfloat_shortShiftLeft96M( aPtr, dist, zPtr ) softfloat_shortShiftLeftM( 3, aPtr, dist, zPtr )
#endif #endif
#ifndef softfloat_shortShiftLeft128M #ifndef softfloat_shortShiftLeft128M
@ -631,7 +700,7 @@ void softfloat_shortShiftLeftM(uint_fast8_t size_words, const uint32_t* aPtr, ui
| This function or macro is the same as 'softfloat_shortShiftLeftM' with | This function or macro is the same as 'softfloat_shortShiftLeftM' with
| 'size_words' = 4 (N = 128). | 'size_words' = 4 (N = 128).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_shortShiftLeft128M(aPtr, dist, zPtr) softfloat_shortShiftLeftM(4, aPtr, dist, zPtr) #define softfloat_shortShiftLeft128M( aPtr, dist, zPtr ) softfloat_shortShiftLeftM( 4, aPtr, dist, zPtr )
#endif #endif
#ifndef softfloat_shortShiftLeft160M #ifndef softfloat_shortShiftLeft160M
@ -639,7 +708,7 @@ void softfloat_shortShiftLeftM(uint_fast8_t size_words, const uint32_t* aPtr, ui
| This function or macro is the same as 'softfloat_shortShiftLeftM' with | This function or macro is the same as 'softfloat_shortShiftLeftM' with
| 'size_words' = 5 (N = 160). | 'size_words' = 5 (N = 160).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_shortShiftLeft160M(aPtr, dist, zPtr) softfloat_shortShiftLeftM(5, aPtr, dist, zPtr) #define softfloat_shortShiftLeft160M( aPtr, dist, zPtr ) softfloat_shortShiftLeftM( 5, aPtr, dist, zPtr )
#endif #endif
#ifndef softfloat_shiftLeftM #ifndef softfloat_shiftLeftM
@ -653,7 +722,13 @@ void softfloat_shortShiftLeftM(uint_fast8_t size_words, const uint32_t* aPtr, ui
| The value of 'dist' can be arbitrarily large. In particular, if 'dist' is | The value of 'dist' can be arbitrarily large. In particular, if 'dist' is
| greater than N, the stored result will be 0. | greater than N, the stored result will be 0.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_shiftLeftM(uint_fast8_t size_words, const uint32_t* aPtr, uint32_t dist, uint32_t* zPtr); void
softfloat_shiftLeftM(
uint_fast8_t size_words,
const uint32_t *aPtr,
uint32_t dist,
uint32_t *zPtr
);
#endif #endif
#ifndef softfloat_shiftLeft96M #ifndef softfloat_shiftLeft96M
@ -661,7 +736,7 @@ void softfloat_shiftLeftM(uint_fast8_t size_words, const uint32_t* aPtr, uint32_
| This function or macro is the same as 'softfloat_shiftLeftM' with | This function or macro is the same as 'softfloat_shiftLeftM' with
| 'size_words' = 3 (N = 96). | 'size_words' = 3 (N = 96).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_shiftLeft96M(aPtr, dist, zPtr) softfloat_shiftLeftM(3, aPtr, dist, zPtr) #define softfloat_shiftLeft96M( aPtr, dist, zPtr ) softfloat_shiftLeftM( 3, aPtr, dist, zPtr )
#endif #endif
#ifndef softfloat_shiftLeft128M #ifndef softfloat_shiftLeft128M
@ -669,7 +744,7 @@ void softfloat_shiftLeftM(uint_fast8_t size_words, const uint32_t* aPtr, uint32_
| This function or macro is the same as 'softfloat_shiftLeftM' with | This function or macro is the same as 'softfloat_shiftLeftM' with
| 'size_words' = 4 (N = 128). | 'size_words' = 4 (N = 128).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_shiftLeft128M(aPtr, dist, zPtr) softfloat_shiftLeftM(4, aPtr, dist, zPtr) #define softfloat_shiftLeft128M( aPtr, dist, zPtr ) softfloat_shiftLeftM( 4, aPtr, dist, zPtr )
#endif #endif
#ifndef softfloat_shiftLeft160M #ifndef softfloat_shiftLeft160M
@ -677,7 +752,7 @@ void softfloat_shiftLeftM(uint_fast8_t size_words, const uint32_t* aPtr, uint32_
| This function or macro is the same as 'softfloat_shiftLeftM' with | This function or macro is the same as 'softfloat_shiftLeftM' with
| 'size_words' = 5 (N = 160). | 'size_words' = 5 (N = 160).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_shiftLeft160M(aPtr, dist, zPtr) softfloat_shiftLeftM(5, aPtr, dist, zPtr) #define softfloat_shiftLeft160M( aPtr, dist, zPtr ) softfloat_shiftLeftM( 5, aPtr, dist, zPtr )
#endif #endif
#ifndef softfloat_shortShiftRightM #ifndef softfloat_shortShiftRightM
@ -690,7 +765,13 @@ void softfloat_shiftLeftM(uint_fast8_t size_words, const uint32_t* aPtr, uint32_
| that concatenate in the platform's normal endian order to form an N-bit | that concatenate in the platform's normal endian order to form an N-bit
| integer. | integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_shortShiftRightM(uint_fast8_t size_words, const uint32_t* aPtr, uint_fast8_t dist, uint32_t* zPtr); void
softfloat_shortShiftRightM(
uint_fast8_t size_words,
const uint32_t *aPtr,
uint_fast8_t dist,
uint32_t *zPtr
);
#endif #endif
#ifndef softfloat_shortShiftRight128M #ifndef softfloat_shortShiftRight128M
@ -698,7 +779,7 @@ void softfloat_shortShiftRightM(uint_fast8_t size_words, const uint32_t* aPtr, u
| This function or macro is the same as 'softfloat_shortShiftRightM' with | This function or macro is the same as 'softfloat_shortShiftRightM' with
| 'size_words' = 4 (N = 128). | 'size_words' = 4 (N = 128).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_shortShiftRight128M(aPtr, dist, zPtr) softfloat_shortShiftRightM(4, aPtr, dist, zPtr) #define softfloat_shortShiftRight128M( aPtr, dist, zPtr ) softfloat_shortShiftRightM( 4, aPtr, dist, zPtr )
#endif #endif
#ifndef softfloat_shortShiftRight160M #ifndef softfloat_shortShiftRight160M
@ -706,7 +787,7 @@ void softfloat_shortShiftRightM(uint_fast8_t size_words, const uint32_t* aPtr, u
| This function or macro is the same as 'softfloat_shortShiftRightM' with | This function or macro is the same as 'softfloat_shortShiftRightM' with
| 'size_words' = 5 (N = 160). | 'size_words' = 5 (N = 160).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_shortShiftRight160M(aPtr, dist, zPtr) softfloat_shortShiftRightM(5, aPtr, dist, zPtr) #define softfloat_shortShiftRight160M( aPtr, dist, zPtr ) softfloat_shortShiftRightM( 5, aPtr, dist, zPtr )
#endif #endif
#ifndef softfloat_shortShiftRightJamM #ifndef softfloat_shortShiftRightJamM
@ -720,7 +801,9 @@ void softfloat_shortShiftRightM(uint_fast8_t size_words, const uint32_t* aPtr, u
| to a 'size_words'-long array of 32-bit elements that concatenate in the | to a 'size_words'-long array of 32-bit elements that concatenate in the
| platform's normal endian order to form an N-bit integer. | platform's normal endian order to form an N-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_shortShiftRightJamM(uint_fast8_t, const uint32_t*, uint_fast8_t, uint32_t*); void
softfloat_shortShiftRightJamM(
uint_fast8_t, const uint32_t *, uint_fast8_t, uint32_t * );
#endif #endif
#ifndef softfloat_shortShiftRightJam160M #ifndef softfloat_shortShiftRightJam160M
@ -728,7 +811,7 @@ void softfloat_shortShiftRightJamM(uint_fast8_t, const uint32_t*, uint_fast8_t,
| This function or macro is the same as 'softfloat_shortShiftRightJamM' with | This function or macro is the same as 'softfloat_shortShiftRightJamM' with
| 'size_words' = 5 (N = 160). | 'size_words' = 5 (N = 160).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_shortShiftRightJam160M(aPtr, dist, zPtr) softfloat_shortShiftRightJamM(5, aPtr, dist, zPtr) #define softfloat_shortShiftRightJam160M( aPtr, dist, zPtr ) softfloat_shortShiftRightJamM( 5, aPtr, dist, zPtr )
#endif #endif
#ifndef softfloat_shiftRightM #ifndef softfloat_shiftRightM
@ -742,7 +825,13 @@ void softfloat_shortShiftRightJamM(uint_fast8_t, const uint32_t*, uint_fast8_t,
| The value of 'dist' can be arbitrarily large. In particular, if 'dist' is | The value of 'dist' can be arbitrarily large. In particular, if 'dist' is
| greater than N, the stored result will be 0. | greater than N, the stored result will be 0.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_shiftRightM(uint_fast8_t size_words, const uint32_t* aPtr, uint32_t dist, uint32_t* zPtr); void
softfloat_shiftRightM(
uint_fast8_t size_words,
const uint32_t *aPtr,
uint32_t dist,
uint32_t *zPtr
);
#endif #endif
#ifndef softfloat_shiftRight96M #ifndef softfloat_shiftRight96M
@ -750,7 +839,7 @@ void softfloat_shiftRightM(uint_fast8_t size_words, const uint32_t* aPtr, uint32
| This function or macro is the same as 'softfloat_shiftRightM' with | This function or macro is the same as 'softfloat_shiftRightM' with
| 'size_words' = 3 (N = 96). | 'size_words' = 3 (N = 96).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_shiftRight96M(aPtr, dist, zPtr) softfloat_shiftRightM(3, aPtr, dist, zPtr) #define softfloat_shiftRight96M( aPtr, dist, zPtr ) softfloat_shiftRightM( 3, aPtr, dist, zPtr )
#endif #endif
#ifndef softfloat_shiftRightJamM #ifndef softfloat_shiftRightJamM
@ -767,7 +856,13 @@ void softfloat_shiftRightM(uint_fast8_t size_words, const uint32_t* aPtr, uint32
| is greater than N, the stored result will be either 0 or 1, depending on | is greater than N, the stored result will be either 0 or 1, depending on
| whether the original N bits are all zeros. | whether the original N bits are all zeros.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_shiftRightJamM(uint_fast8_t size_words, const uint32_t* aPtr, uint32_t dist, uint32_t* zPtr); void
softfloat_shiftRightJamM(
uint_fast8_t size_words,
const uint32_t *aPtr,
uint32_t dist,
uint32_t *zPtr
);
#endif #endif
#ifndef softfloat_shiftRightJam96M #ifndef softfloat_shiftRightJam96M
@ -775,7 +870,7 @@ void softfloat_shiftRightJamM(uint_fast8_t size_words, const uint32_t* aPtr, uin
| This function or macro is the same as 'softfloat_shiftRightJamM' with | This function or macro is the same as 'softfloat_shiftRightJamM' with
| 'size_words' = 3 (N = 96). | 'size_words' = 3 (N = 96).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_shiftRightJam96M(aPtr, dist, zPtr) softfloat_shiftRightJamM(3, aPtr, dist, zPtr) #define softfloat_shiftRightJam96M( aPtr, dist, zPtr ) softfloat_shiftRightJamM( 3, aPtr, dist, zPtr )
#endif #endif
#ifndef softfloat_shiftRightJam128M #ifndef softfloat_shiftRightJam128M
@ -783,7 +878,7 @@ void softfloat_shiftRightJamM(uint_fast8_t size_words, const uint32_t* aPtr, uin
| This function or macro is the same as 'softfloat_shiftRightJamM' with | This function or macro is the same as 'softfloat_shiftRightJamM' with
| 'size_words' = 4 (N = 128). | 'size_words' = 4 (N = 128).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_shiftRightJam128M(aPtr, dist, zPtr) softfloat_shiftRightJamM(4, aPtr, dist, zPtr) #define softfloat_shiftRightJam128M( aPtr, dist, zPtr ) softfloat_shiftRightJamM( 4, aPtr, dist, zPtr )
#endif #endif
#ifndef softfloat_shiftRightJam160M #ifndef softfloat_shiftRightJam160M
@ -791,7 +886,7 @@ void softfloat_shiftRightJamM(uint_fast8_t size_words, const uint32_t* aPtr, uin
| This function or macro is the same as 'softfloat_shiftRightJamM' with | This function or macro is the same as 'softfloat_shiftRightJamM' with
| 'size_words' = 5 (N = 160). | 'size_words' = 5 (N = 160).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_shiftRightJam160M(aPtr, dist, zPtr) softfloat_shiftRightJamM(5, aPtr, dist, zPtr) #define softfloat_shiftRightJam160M( aPtr, dist, zPtr ) softfloat_shiftRightJamM( 5, aPtr, dist, zPtr )
#endif #endif
#ifndef softfloat_addM #ifndef softfloat_addM
@ -803,7 +898,13 @@ void softfloat_shiftRightJamM(uint_fast8_t size_words, const uint32_t* aPtr, uin
| elements that concatenate in the platform's normal endian order to form an | elements that concatenate in the platform's normal endian order to form an
| N-bit integer. | N-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_addM(uint_fast8_t size_words, const uint32_t* aPtr, const uint32_t* bPtr, uint32_t* zPtr); void
softfloat_addM(
uint_fast8_t size_words,
const uint32_t *aPtr,
const uint32_t *bPtr,
uint32_t *zPtr
);
#endif #endif
#ifndef softfloat_add96M #ifndef softfloat_add96M
@ -811,7 +912,7 @@ void softfloat_addM(uint_fast8_t size_words, const uint32_t* aPtr, const uint32_
| This function or macro is the same as 'softfloat_addM' with 'size_words' | This function or macro is the same as 'softfloat_addM' with 'size_words'
| = 3 (N = 96). | = 3 (N = 96).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_add96M(aPtr, bPtr, zPtr) softfloat_addM(3, aPtr, bPtr, zPtr) #define softfloat_add96M( aPtr, bPtr, zPtr ) softfloat_addM( 3, aPtr, bPtr, zPtr )
#endif #endif
#ifndef softfloat_add128M #ifndef softfloat_add128M
@ -819,7 +920,7 @@ void softfloat_addM(uint_fast8_t size_words, const uint32_t* aPtr, const uint32_
| This function or macro is the same as 'softfloat_addM' with 'size_words' | This function or macro is the same as 'softfloat_addM' with 'size_words'
| = 4 (N = 128). | = 4 (N = 128).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_add128M(aPtr, bPtr, zPtr) softfloat_addM(4, aPtr, bPtr, zPtr) #define softfloat_add128M( aPtr, bPtr, zPtr ) softfloat_addM( 4, aPtr, bPtr, zPtr )
#endif #endif
#ifndef softfloat_add160M #ifndef softfloat_add160M
@ -827,7 +928,7 @@ void softfloat_addM(uint_fast8_t size_words, const uint32_t* aPtr, const uint32_
| This function or macro is the same as 'softfloat_addM' with 'size_words' | This function or macro is the same as 'softfloat_addM' with 'size_words'
| = 5 (N = 160). | = 5 (N = 160).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_add160M(aPtr, bPtr, zPtr) softfloat_addM(5, aPtr, bPtr, zPtr) #define softfloat_add160M( aPtr, bPtr, zPtr ) softfloat_addM( 5, aPtr, bPtr, zPtr )
#endif #endif
#ifndef softfloat_addCarryM #ifndef softfloat_addCarryM
@ -839,7 +940,14 @@ void softfloat_addM(uint_fast8_t size_words, const uint32_t* aPtr, const uint32_
| points to a 'size_words'-long array of 32-bit elements that concatenate in | points to a 'size_words'-long array of 32-bit elements that concatenate in
| the platform's normal endian order to form an N-bit integer. | the platform's normal endian order to form an N-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast8_t softfloat_addCarryM(uint_fast8_t size_words, const uint32_t* aPtr, const uint32_t* bPtr, uint_fast8_t carry, uint32_t* zPtr); uint_fast8_t
softfloat_addCarryM(
uint_fast8_t size_words,
const uint32_t *aPtr,
const uint32_t *bPtr,
uint_fast8_t carry,
uint32_t *zPtr
);
#endif #endif
#ifndef softfloat_addComplCarryM #ifndef softfloat_addComplCarryM
@ -848,8 +956,14 @@ uint_fast8_t softfloat_addCarryM(uint_fast8_t size_words, const uint32_t* aPtr,
| the value of the unsigned integer pointed to by 'bPtr' is bit-wise completed | the value of the unsigned integer pointed to by 'bPtr' is bit-wise completed
| before the addition. | before the addition.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast8_t softfloat_addComplCarryM(uint_fast8_t size_words, const uint32_t* aPtr, const uint32_t* bPtr, uint_fast8_t carry, uint_fast8_t
uint32_t* zPtr); softfloat_addComplCarryM(
uint_fast8_t size_words,
const uint32_t *aPtr,
const uint32_t *bPtr,
uint_fast8_t carry,
uint32_t *zPtr
);
#endif #endif
#ifndef softfloat_addComplCarry96M #ifndef softfloat_addComplCarry96M
@ -857,7 +971,7 @@ uint_fast8_t softfloat_addComplCarryM(uint_fast8_t size_words, const uint32_t* a
| This function or macro is the same as 'softfloat_addComplCarryM' with | This function or macro is the same as 'softfloat_addComplCarryM' with
| 'size_words' = 3 (N = 96). | 'size_words' = 3 (N = 96).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_addComplCarry96M(aPtr, bPtr, carry, zPtr) softfloat_addComplCarryM(3, aPtr, bPtr, carry, zPtr) #define softfloat_addComplCarry96M( aPtr, bPtr, carry, zPtr ) softfloat_addComplCarryM( 3, aPtr, bPtr, carry, zPtr )
#endif #endif
#ifndef softfloat_negXM #ifndef softfloat_negXM
@ -867,7 +981,7 @@ uint_fast8_t softfloat_addComplCarryM(uint_fast8_t size_words, const uint32_t* a
| points to a 'size_words'-long array of 32-bit elements that concatenate in | points to a 'size_words'-long array of 32-bit elements that concatenate in
| the platform's normal endian order to form an N-bit integer. | the platform's normal endian order to form an N-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_negXM(uint_fast8_t size_words, uint32_t* zPtr); void softfloat_negXM( uint_fast8_t size_words, uint32_t *zPtr );
#endif #endif
#ifndef softfloat_negX96M #ifndef softfloat_negX96M
@ -875,7 +989,7 @@ void softfloat_negXM(uint_fast8_t size_words, uint32_t* zPtr);
| This function or macro is the same as 'softfloat_negXM' with 'size_words' | This function or macro is the same as 'softfloat_negXM' with 'size_words'
| = 3 (N = 96). | = 3 (N = 96).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_negX96M(zPtr) softfloat_negXM(3, zPtr) #define softfloat_negX96M( zPtr ) softfloat_negXM( 3, zPtr )
#endif #endif
#ifndef softfloat_negX128M #ifndef softfloat_negX128M
@ -883,7 +997,7 @@ void softfloat_negXM(uint_fast8_t size_words, uint32_t* zPtr);
| This function or macro is the same as 'softfloat_negXM' with 'size_words' | This function or macro is the same as 'softfloat_negXM' with 'size_words'
| = 4 (N = 128). | = 4 (N = 128).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_negX128M(zPtr) softfloat_negXM(4, zPtr) #define softfloat_negX128M( zPtr ) softfloat_negXM( 4, zPtr )
#endif #endif
#ifndef softfloat_negX160M #ifndef softfloat_negX160M
@ -891,7 +1005,7 @@ void softfloat_negXM(uint_fast8_t size_words, uint32_t* zPtr);
| This function or macro is the same as 'softfloat_negXM' with 'size_words' | This function or macro is the same as 'softfloat_negXM' with 'size_words'
| = 5 (N = 160). | = 5 (N = 160).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_negX160M(zPtr) softfloat_negXM(5, zPtr) #define softfloat_negX160M( zPtr ) softfloat_negXM( 5, zPtr )
#endif #endif
#ifndef softfloat_negX256M #ifndef softfloat_negX256M
@ -899,7 +1013,7 @@ void softfloat_negXM(uint_fast8_t size_words, uint32_t* zPtr);
| This function or macro is the same as 'softfloat_negXM' with 'size_words' | This function or macro is the same as 'softfloat_negXM' with 'size_words'
| = 8 (N = 256). | = 8 (N = 256).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_negX256M(zPtr) softfloat_negXM(8, zPtr) #define softfloat_negX256M( zPtr ) softfloat_negXM( 8, zPtr )
#endif #endif
#ifndef softfloat_sub1XM #ifndef softfloat_sub1XM
@ -910,7 +1024,7 @@ void softfloat_negXM(uint_fast8_t size_words, uint32_t* zPtr);
| elements that concatenate in the platform's normal endian order to form an | elements that concatenate in the platform's normal endian order to form an
| N-bit integer. | N-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_sub1XM(uint_fast8_t size_words, uint32_t* zPtr); void softfloat_sub1XM( uint_fast8_t size_words, uint32_t *zPtr );
#endif #endif
#ifndef softfloat_sub1X96M #ifndef softfloat_sub1X96M
@ -918,7 +1032,7 @@ void softfloat_sub1XM(uint_fast8_t size_words, uint32_t* zPtr);
| This function or macro is the same as 'softfloat_sub1XM' with 'size_words' | This function or macro is the same as 'softfloat_sub1XM' with 'size_words'
| = 3 (N = 96). | = 3 (N = 96).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_sub1X96M(zPtr) softfloat_sub1XM(3, zPtr) #define softfloat_sub1X96M( zPtr ) softfloat_sub1XM( 3, zPtr )
#endif #endif
#ifndef softfloat_sub1X160M #ifndef softfloat_sub1X160M
@ -926,7 +1040,7 @@ void softfloat_sub1XM(uint_fast8_t size_words, uint32_t* zPtr);
| This function or macro is the same as 'softfloat_sub1XM' with 'size_words' | This function or macro is the same as 'softfloat_sub1XM' with 'size_words'
| = 5 (N = 160). | = 5 (N = 160).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_sub1X160M(zPtr) softfloat_sub1XM(5, zPtr) #define softfloat_sub1X160M( zPtr ) softfloat_sub1XM( 5, zPtr )
#endif #endif
#ifndef softfloat_subM #ifndef softfloat_subM
@ -938,7 +1052,13 @@ void softfloat_sub1XM(uint_fast8_t size_words, uint32_t* zPtr);
| array of 32-bit elements that concatenate in the platform's normal endian | array of 32-bit elements that concatenate in the platform's normal endian
| order to form an N-bit integer. | order to form an N-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_subM(uint_fast8_t size_words, const uint32_t* aPtr, const uint32_t* bPtr, uint32_t* zPtr); void
softfloat_subM(
uint_fast8_t size_words,
const uint32_t *aPtr,
const uint32_t *bPtr,
uint32_t *zPtr
);
#endif #endif
#ifndef softfloat_sub96M #ifndef softfloat_sub96M
@ -946,7 +1066,7 @@ void softfloat_subM(uint_fast8_t size_words, const uint32_t* aPtr, const uint32_
| This function or macro is the same as 'softfloat_subM' with 'size_words' | This function or macro is the same as 'softfloat_subM' with 'size_words'
| = 3 (N = 96). | = 3 (N = 96).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_sub96M(aPtr, bPtr, zPtr) softfloat_subM(3, aPtr, bPtr, zPtr) #define softfloat_sub96M( aPtr, bPtr, zPtr ) softfloat_subM( 3, aPtr, bPtr, zPtr )
#endif #endif
#ifndef softfloat_sub128M #ifndef softfloat_sub128M
@ -954,7 +1074,7 @@ void softfloat_subM(uint_fast8_t size_words, const uint32_t* aPtr, const uint32_
| This function or macro is the same as 'softfloat_subM' with 'size_words' | This function or macro is the same as 'softfloat_subM' with 'size_words'
| = 4 (N = 128). | = 4 (N = 128).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_sub128M(aPtr, bPtr, zPtr) softfloat_subM(4, aPtr, bPtr, zPtr) #define softfloat_sub128M( aPtr, bPtr, zPtr ) softfloat_subM( 4, aPtr, bPtr, zPtr )
#endif #endif
#ifndef softfloat_sub160M #ifndef softfloat_sub160M
@ -962,7 +1082,7 @@ void softfloat_subM(uint_fast8_t size_words, const uint32_t* aPtr, const uint32_
| This function or macro is the same as 'softfloat_subM' with 'size_words' | This function or macro is the same as 'softfloat_subM' with 'size_words'
| = 5 (N = 160). | = 5 (N = 160).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_sub160M(aPtr, bPtr, zPtr) softfloat_subM(5, aPtr, bPtr, zPtr) #define softfloat_sub160M( aPtr, bPtr, zPtr ) softfloat_subM( 5, aPtr, bPtr, zPtr )
#endif #endif
#ifndef softfloat_mul64To128M #ifndef softfloat_mul64To128M
@ -972,7 +1092,7 @@ void softfloat_subM(uint_fast8_t size_words, const uint32_t* aPtr, const uint32_
| elements that concatenate in the platform's normal endian order to form a | elements that concatenate in the platform's normal endian order to form a
| 128-bit integer. | 128-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_mul64To128M(uint64_t a, uint64_t b, uint32_t* zPtr); void softfloat_mul64To128M( uint64_t a, uint64_t b, uint32_t *zPtr );
#endif #endif
#ifndef softfloat_mul128MTo256M #ifndef softfloat_mul128MTo256M
@ -984,7 +1104,9 @@ void softfloat_mul64To128M(uint64_t a, uint64_t b, uint32_t* zPtr);
| Argument 'zPtr' points to an array of eight 32-bit elements that concatenate | Argument 'zPtr' points to an array of eight 32-bit elements that concatenate
| to form a 256-bit integer. | to form a 256-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_mul128MTo256M(const uint32_t* aPtr, const uint32_t* bPtr, uint32_t* zPtr); void
softfloat_mul128MTo256M(
const uint32_t *aPtr, const uint32_t *bPtr, uint32_t *zPtr );
#endif #endif
#ifndef softfloat_remStepMBy32 #ifndef softfloat_remStepMBy32
@ -997,8 +1119,15 @@ void softfloat_mul128MTo256M(const uint32_t* aPtr, const uint32_t* bPtr, uint32_
| to a 'size_words'-long array of 32-bit elements that concatenate in the | to a 'size_words'-long array of 32-bit elements that concatenate in the
| platform's normal endian order to form an N-bit integer. | platform's normal endian order to form an N-bit integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_remStepMBy32(uint_fast8_t size_words, const uint32_t* remPtr, uint_fast8_t dist, const uint32_t* bPtr, uint32_t q, void
uint32_t* zPtr); softfloat_remStepMBy32(
uint_fast8_t size_words,
const uint32_t *remPtr,
uint_fast8_t dist,
const uint32_t *bPtr,
uint32_t q,
uint32_t *zPtr
);
#endif #endif
#ifndef softfloat_remStep96MBy32 #ifndef softfloat_remStep96MBy32
@ -1006,7 +1135,7 @@ void softfloat_remStepMBy32(uint_fast8_t size_words, const uint32_t* remPtr, uin
| This function or macro is the same as 'softfloat_remStepMBy32' with | This function or macro is the same as 'softfloat_remStepMBy32' with
| 'size_words' = 3 (N = 96). | 'size_words' = 3 (N = 96).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_remStep96MBy32(remPtr, dist, bPtr, q, zPtr) softfloat_remStepMBy32(3, remPtr, dist, bPtr, q, zPtr) #define softfloat_remStep96MBy32( remPtr, dist, bPtr, q, zPtr ) softfloat_remStepMBy32( 3, remPtr, dist, bPtr, q, zPtr )
#endif #endif
#ifndef softfloat_remStep128MBy32 #ifndef softfloat_remStep128MBy32
@ -1014,7 +1143,7 @@ void softfloat_remStepMBy32(uint_fast8_t size_words, const uint32_t* remPtr, uin
| This function or macro is the same as 'softfloat_remStepMBy32' with | This function or macro is the same as 'softfloat_remStepMBy32' with
| 'size_words' = 4 (N = 128). | 'size_words' = 4 (N = 128).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_remStep128MBy32(remPtr, dist, bPtr, q, zPtr) softfloat_remStepMBy32(4, remPtr, dist, bPtr, q, zPtr) #define softfloat_remStep128MBy32( remPtr, dist, bPtr, q, zPtr ) softfloat_remStepMBy32( 4, remPtr, dist, bPtr, q, zPtr )
#endif #endif
#ifndef softfloat_remStep160MBy32 #ifndef softfloat_remStep160MBy32
@ -1022,9 +1151,10 @@ void softfloat_remStepMBy32(uint_fast8_t size_words, const uint32_t* remPtr, uin
| This function or macro is the same as 'softfloat_remStepMBy32' with | This function or macro is the same as 'softfloat_remStepMBy32' with
| 'size_words' = 5 (N = 160). | 'size_words' = 5 (N = 160).
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_remStep160MBy32(remPtr, dist, bPtr, q, zPtr) softfloat_remStepMBy32(5, remPtr, dist, bPtr, q, zPtr) #define softfloat_remStep160MBy32( remPtr, dist, bPtr, q, zPtr ) softfloat_remStepMBy32( 5, remPtr, dist, bPtr, q, zPtr )
#endif #endif
#endif #endif
#endif #endif

View File

@ -34,6 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/ =============================================================================*/
/*============================================================================ /*============================================================================
| Note: If SoftFloat is made available as a general library for programs to | Note: If SoftFloat is made available as a general library for programs to
| use, it is strongly recommended that a platform-specific version of this | use, it is strongly recommended that a platform-specific version of this
@ -41,12 +42,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
| eliminates all dependencies on compile-time macros. | eliminates all dependencies on compile-time macros.
*============================================================================*/ *============================================================================*/
#ifndef softfloat_h #ifndef softfloat_h
#define softfloat_h 1 #define softfloat_h 1
#include "softfloat_types.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "softfloat_types.h"
#ifndef THREAD_LOCAL #ifndef THREAD_LOCAL
#define THREAD_LOCAL #define THREAD_LOCAL
@ -56,7 +58,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
| Software floating-point underflow tininess-detection mode. | Software floating-point underflow tininess-detection mode.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
extern THREAD_LOCAL uint_fast8_t softfloat_detectTininess; extern THREAD_LOCAL uint_fast8_t softfloat_detectTininess;
enum { softfloat_tininess_beforeRounding = 0, softfloat_tininess_afterRounding = 1 }; enum {
softfloat_tininess_beforeRounding = 0,
softfloat_tininess_afterRounding = 1
};
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Software floating-point rounding mode. (Mode "odd" is supported only if | Software floating-point rounding mode. (Mode "odd" is supported only if
@ -64,12 +69,12 @@ enum { softfloat_tininess_beforeRounding = 0, softfloat_tininess_afterRounding =
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
extern THREAD_LOCAL uint_fast8_t softfloat_roundingMode; extern THREAD_LOCAL uint_fast8_t softfloat_roundingMode;
enum { enum {
softfloat_round_near_even = 0, softfloat_round_near_even = 0,
softfloat_round_minMag = 1, softfloat_round_minMag = 1,
softfloat_round_min = 2, softfloat_round_min = 2,
softfloat_round_max = 3, softfloat_round_max = 3,
softfloat_round_near_maxMag = 4, softfloat_round_near_maxMag = 4,
softfloat_round_odd = 6 softfloat_round_odd = 6
}; };
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -77,162 +82,162 @@ enum {
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
extern THREAD_LOCAL uint_fast8_t softfloat_exceptionFlags; extern THREAD_LOCAL uint_fast8_t softfloat_exceptionFlags;
enum { enum {
softfloat_flag_inexact = 1, softfloat_flag_inexact = 1,
softfloat_flag_underflow = 2, softfloat_flag_underflow = 2,
softfloat_flag_overflow = 4, softfloat_flag_overflow = 4,
softfloat_flag_infinite = 8, softfloat_flag_infinite = 8,
softfloat_flag_invalid = 16 softfloat_flag_invalid = 16
}; };
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Routine to raise any or all of the software floating-point exception flags. | Routine to raise any or all of the software floating-point exception flags.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void softfloat_raiseFlags(uint_fast8_t); void softfloat_raiseFlags( uint_fast8_t );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Integer-to-floating-point conversion routines. | Integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
float16_t ui32_to_f16(uint32_t); float16_t ui32_to_f16( uint32_t );
float32_t ui32_to_f32(uint32_t); float32_t ui32_to_f32( uint32_t );
float64_t ui32_to_f64(uint32_t); float64_t ui32_to_f64( uint32_t );
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
extFloat80_t ui32_to_extF80(uint32_t); extFloat80_t ui32_to_extF80( uint32_t );
float128_t ui32_to_f128(uint32_t); float128_t ui32_to_f128( uint32_t );
#endif #endif
void ui32_to_extF80M(uint32_t, extFloat80_t*); void ui32_to_extF80M( uint32_t, extFloat80_t * );
void ui32_to_f128M(uint32_t, float128_t*); void ui32_to_f128M( uint32_t, float128_t * );
float16_t ui64_to_f16(uint64_t); float16_t ui64_to_f16( uint64_t );
float32_t ui64_to_f32(uint64_t); float32_t ui64_to_f32( uint64_t );
float64_t ui64_to_f64(uint64_t); float64_t ui64_to_f64( uint64_t );
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
extFloat80_t ui64_to_extF80(uint64_t); extFloat80_t ui64_to_extF80( uint64_t );
float128_t ui64_to_f128(uint64_t); float128_t ui64_to_f128( uint64_t );
#endif #endif
void ui64_to_extF80M(uint64_t, extFloat80_t*); void ui64_to_extF80M( uint64_t, extFloat80_t * );
void ui64_to_f128M(uint64_t, float128_t*); void ui64_to_f128M( uint64_t, float128_t * );
float16_t i32_to_f16(int32_t); float16_t i32_to_f16( int32_t );
float32_t i32_to_f32(int32_t); float32_t i32_to_f32( int32_t );
float64_t i32_to_f64(int32_t); float64_t i32_to_f64( int32_t );
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
extFloat80_t i32_to_extF80(int32_t); extFloat80_t i32_to_extF80( int32_t );
float128_t i32_to_f128(int32_t); float128_t i32_to_f128( int32_t );
#endif #endif
void i32_to_extF80M(int32_t, extFloat80_t*); void i32_to_extF80M( int32_t, extFloat80_t * );
void i32_to_f128M(int32_t, float128_t*); void i32_to_f128M( int32_t, float128_t * );
float16_t i64_to_f16(int64_t); float16_t i64_to_f16( int64_t );
float32_t i64_to_f32(int64_t); float32_t i64_to_f32( int64_t );
float64_t i64_to_f64(int64_t); float64_t i64_to_f64( int64_t );
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
extFloat80_t i64_to_extF80(int64_t); extFloat80_t i64_to_extF80( int64_t );
float128_t i64_to_f128(int64_t); float128_t i64_to_f128( int64_t );
#endif #endif
void i64_to_extF80M(int64_t, extFloat80_t*); void i64_to_extF80M( int64_t, extFloat80_t * );
void i64_to_f128M(int64_t, float128_t*); void i64_to_f128M( int64_t, float128_t * );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| 16-bit (half-precision) floating-point operations. | 16-bit (half-precision) floating-point operations.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast32_t f16_to_ui32(float16_t, uint_fast8_t, bool); uint_fast32_t f16_to_ui32( float16_t, uint_fast8_t, bool );
uint_fast64_t f16_to_ui64(float16_t, uint_fast8_t, bool); uint_fast64_t f16_to_ui64( float16_t, uint_fast8_t, bool );
int_fast32_t f16_to_i32(float16_t, uint_fast8_t, bool); int_fast32_t f16_to_i32( float16_t, uint_fast8_t, bool );
int_fast64_t f16_to_i64(float16_t, uint_fast8_t, bool); int_fast64_t f16_to_i64( float16_t, uint_fast8_t, bool );
uint_fast32_t f16_to_ui32_r_minMag(float16_t, bool); uint_fast32_t f16_to_ui32_r_minMag( float16_t, bool );
uint_fast64_t f16_to_ui64_r_minMag(float16_t, bool); uint_fast64_t f16_to_ui64_r_minMag( float16_t, bool );
int_fast32_t f16_to_i32_r_minMag(float16_t, bool); int_fast32_t f16_to_i32_r_minMag( float16_t, bool );
int_fast64_t f16_to_i64_r_minMag(float16_t, bool); int_fast64_t f16_to_i64_r_minMag( float16_t, bool );
float32_t f16_to_f32(float16_t); float32_t f16_to_f32( float16_t );
float64_t f16_to_f64(float16_t); float64_t f16_to_f64( float16_t );
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
extFloat80_t f16_to_extF80(float16_t); extFloat80_t f16_to_extF80( float16_t );
float128_t f16_to_f128(float16_t); float128_t f16_to_f128( float16_t );
#endif #endif
void f16_to_extF80M(float16_t, extFloat80_t*); void f16_to_extF80M( float16_t, extFloat80_t * );
void f16_to_f128M(float16_t, float128_t*); void f16_to_f128M( float16_t, float128_t * );
float16_t f16_roundToInt(float16_t, uint_fast8_t, bool); float16_t f16_roundToInt( float16_t, uint_fast8_t, bool );
float16_t f16_add(float16_t, float16_t); float16_t f16_add( float16_t, float16_t );
float16_t f16_sub(float16_t, float16_t); float16_t f16_sub( float16_t, float16_t );
float16_t f16_mul(float16_t, float16_t); float16_t f16_mul( float16_t, float16_t );
float16_t f16_mulAdd(float16_t, float16_t, float16_t); float16_t f16_mulAdd( float16_t, float16_t, float16_t );
float16_t f16_div(float16_t, float16_t); float16_t f16_div( float16_t, float16_t );
float16_t f16_rem(float16_t, float16_t); float16_t f16_rem( float16_t, float16_t );
float16_t f16_sqrt(float16_t); float16_t f16_sqrt( float16_t );
bool f16_eq(float16_t, float16_t); bool f16_eq( float16_t, float16_t );
bool f16_le(float16_t, float16_t); bool f16_le( float16_t, float16_t );
bool f16_lt(float16_t, float16_t); bool f16_lt( float16_t, float16_t );
bool f16_eq_signaling(float16_t, float16_t); bool f16_eq_signaling( float16_t, float16_t );
bool f16_le_quiet(float16_t, float16_t); bool f16_le_quiet( float16_t, float16_t );
bool f16_lt_quiet(float16_t, float16_t); bool f16_lt_quiet( float16_t, float16_t );
bool f16_isSignalingNaN(float16_t); bool f16_isSignalingNaN( float16_t );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| 32-bit (single-precision) floating-point operations. | 32-bit (single-precision) floating-point operations.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast32_t f32_to_ui32(float32_t, uint_fast8_t, bool); uint_fast32_t f32_to_ui32( float32_t, uint_fast8_t, bool );
uint_fast64_t f32_to_ui64(float32_t, uint_fast8_t, bool); uint_fast64_t f32_to_ui64( float32_t, uint_fast8_t, bool );
int_fast32_t f32_to_i32(float32_t, uint_fast8_t, bool); int_fast32_t f32_to_i32( float32_t, uint_fast8_t, bool );
int_fast64_t f32_to_i64(float32_t, uint_fast8_t, bool); int_fast64_t f32_to_i64( float32_t, uint_fast8_t, bool );
uint_fast32_t f32_to_ui32_r_minMag(float32_t, bool); uint_fast32_t f32_to_ui32_r_minMag( float32_t, bool );
uint_fast64_t f32_to_ui64_r_minMag(float32_t, bool); uint_fast64_t f32_to_ui64_r_minMag( float32_t, bool );
int_fast32_t f32_to_i32_r_minMag(float32_t, bool); int_fast32_t f32_to_i32_r_minMag( float32_t, bool );
int_fast64_t f32_to_i64_r_minMag(float32_t, bool); int_fast64_t f32_to_i64_r_minMag( float32_t, bool );
float16_t f32_to_f16(float32_t); float16_t f32_to_f16( float32_t );
float64_t f32_to_f64(float32_t); float64_t f32_to_f64( float32_t );
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
extFloat80_t f32_to_extF80(float32_t); extFloat80_t f32_to_extF80( float32_t );
float128_t f32_to_f128(float32_t); float128_t f32_to_f128( float32_t );
#endif #endif
void f32_to_extF80M(float32_t, extFloat80_t*); void f32_to_extF80M( float32_t, extFloat80_t * );
void f32_to_f128M(float32_t, float128_t*); void f32_to_f128M( float32_t, float128_t * );
float32_t f32_roundToInt(float32_t, uint_fast8_t, bool); float32_t f32_roundToInt( float32_t, uint_fast8_t, bool );
float32_t f32_add(float32_t, float32_t); float32_t f32_add( float32_t, float32_t );
float32_t f32_sub(float32_t, float32_t); float32_t f32_sub( float32_t, float32_t );
float32_t f32_mul(float32_t, float32_t); float32_t f32_mul( float32_t, float32_t );
float32_t f32_mulAdd(float32_t, float32_t, float32_t); float32_t f32_mulAdd( float32_t, float32_t, float32_t );
float32_t f32_div(float32_t, float32_t); float32_t f32_div( float32_t, float32_t );
float32_t f32_rem(float32_t, float32_t); float32_t f32_rem( float32_t, float32_t );
float32_t f32_sqrt(float32_t); float32_t f32_sqrt( float32_t );
bool f32_eq(float32_t, float32_t); bool f32_eq( float32_t, float32_t );
bool f32_le(float32_t, float32_t); bool f32_le( float32_t, float32_t );
bool f32_lt(float32_t, float32_t); bool f32_lt( float32_t, float32_t );
bool f32_eq_signaling(float32_t, float32_t); bool f32_eq_signaling( float32_t, float32_t );
bool f32_le_quiet(float32_t, float32_t); bool f32_le_quiet( float32_t, float32_t );
bool f32_lt_quiet(float32_t, float32_t); bool f32_lt_quiet( float32_t, float32_t );
bool f32_isSignalingNaN(float32_t); bool f32_isSignalingNaN( float32_t );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| 64-bit (double-precision) floating-point operations. | 64-bit (double-precision) floating-point operations.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast32_t f64_to_ui32(float64_t, uint_fast8_t, bool); uint_fast32_t f64_to_ui32( float64_t, uint_fast8_t, bool );
uint_fast64_t f64_to_ui64(float64_t, uint_fast8_t, bool); uint_fast64_t f64_to_ui64( float64_t, uint_fast8_t, bool );
int_fast32_t f64_to_i32(float64_t, uint_fast8_t, bool); int_fast32_t f64_to_i32( float64_t, uint_fast8_t, bool );
int_fast64_t f64_to_i64(float64_t, uint_fast8_t, bool); int_fast64_t f64_to_i64( float64_t, uint_fast8_t, bool );
uint_fast32_t f64_to_ui32_r_minMag(float64_t, bool); uint_fast32_t f64_to_ui32_r_minMag( float64_t, bool );
uint_fast64_t f64_to_ui64_r_minMag(float64_t, bool); uint_fast64_t f64_to_ui64_r_minMag( float64_t, bool );
int_fast32_t f64_to_i32_r_minMag(float64_t, bool); int_fast32_t f64_to_i32_r_minMag( float64_t, bool );
int_fast64_t f64_to_i64_r_minMag(float64_t, bool); int_fast64_t f64_to_i64_r_minMag( float64_t, bool );
float16_t f64_to_f16(float64_t); float16_t f64_to_f16( float64_t );
float32_t f64_to_f32(float64_t); float32_t f64_to_f32( float64_t );
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
extFloat80_t f64_to_extF80(float64_t); extFloat80_t f64_to_extF80( float64_t );
float128_t f64_to_f128(float64_t); float128_t f64_to_f128( float64_t );
#endif #endif
void f64_to_extF80M(float64_t, extFloat80_t*); void f64_to_extF80M( float64_t, extFloat80_t * );
void f64_to_f128M(float64_t, float128_t*); void f64_to_f128M( float64_t, float128_t * );
float64_t f64_roundToInt(float64_t, uint_fast8_t, bool); float64_t f64_roundToInt( float64_t, uint_fast8_t, bool );
float64_t f64_add(float64_t, float64_t); float64_t f64_add( float64_t, float64_t );
float64_t f64_sub(float64_t, float64_t); float64_t f64_sub( float64_t, float64_t );
float64_t f64_mul(float64_t, float64_t); float64_t f64_mul( float64_t, float64_t );
float64_t f64_mulAdd(float64_t, float64_t, float64_t); float64_t f64_mulAdd( float64_t, float64_t, float64_t );
float64_t f64_div(float64_t, float64_t); float64_t f64_div( float64_t, float64_t );
float64_t f64_rem(float64_t, float64_t); float64_t f64_rem( float64_t, float64_t );
float64_t f64_sqrt(float64_t); float64_t f64_sqrt( float64_t );
bool f64_eq(float64_t, float64_t); bool f64_eq( float64_t, float64_t );
bool f64_le(float64_t, float64_t); bool f64_le( float64_t, float64_t );
bool f64_lt(float64_t, float64_t); bool f64_lt( float64_t, float64_t );
bool f64_eq_signaling(float64_t, float64_t); bool f64_eq_signaling( float64_t, float64_t );
bool f64_le_quiet(float64_t, float64_t); bool f64_le_quiet( float64_t, float64_t );
bool f64_lt_quiet(float64_t, float64_t); bool f64_lt_quiet( float64_t, float64_t );
bool f64_isSignalingNaN(float64_t); bool f64_isSignalingNaN( float64_t );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Rounding precision for 80-bit extended double-precision floating-point. | Rounding precision for 80-bit extended double-precision floating-point.
@ -244,118 +249,124 @@ extern THREAD_LOCAL uint_fast8_t extF80_roundingPrecision;
| 80-bit extended double-precision floating-point operations. | 80-bit extended double-precision floating-point operations.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
uint_fast32_t extF80_to_ui32(extFloat80_t, uint_fast8_t, bool); uint_fast32_t extF80_to_ui32( extFloat80_t, uint_fast8_t, bool );
uint_fast64_t extF80_to_ui64(extFloat80_t, uint_fast8_t, bool); uint_fast64_t extF80_to_ui64( extFloat80_t, uint_fast8_t, bool );
int_fast32_t extF80_to_i32(extFloat80_t, uint_fast8_t, bool); int_fast32_t extF80_to_i32( extFloat80_t, uint_fast8_t, bool );
int_fast64_t extF80_to_i64(extFloat80_t, uint_fast8_t, bool); int_fast64_t extF80_to_i64( extFloat80_t, uint_fast8_t, bool );
uint_fast32_t extF80_to_ui32_r_minMag(extFloat80_t, bool); uint_fast32_t extF80_to_ui32_r_minMag( extFloat80_t, bool );
uint_fast64_t extF80_to_ui64_r_minMag(extFloat80_t, bool); uint_fast64_t extF80_to_ui64_r_minMag( extFloat80_t, bool );
int_fast32_t extF80_to_i32_r_minMag(extFloat80_t, bool); int_fast32_t extF80_to_i32_r_minMag( extFloat80_t, bool );
int_fast64_t extF80_to_i64_r_minMag(extFloat80_t, bool); int_fast64_t extF80_to_i64_r_minMag( extFloat80_t, bool );
float16_t extF80_to_f16(extFloat80_t); float16_t extF80_to_f16( extFloat80_t );
float32_t extF80_to_f32(extFloat80_t); float32_t extF80_to_f32( extFloat80_t );
float64_t extF80_to_f64(extFloat80_t); float64_t extF80_to_f64( extFloat80_t );
float128_t extF80_to_f128(extFloat80_t); float128_t extF80_to_f128( extFloat80_t );
extFloat80_t extF80_roundToInt(extFloat80_t, uint_fast8_t, bool); extFloat80_t extF80_roundToInt( extFloat80_t, uint_fast8_t, bool );
extFloat80_t extF80_add(extFloat80_t, extFloat80_t); extFloat80_t extF80_add( extFloat80_t, extFloat80_t );
extFloat80_t extF80_sub(extFloat80_t, extFloat80_t); extFloat80_t extF80_sub( extFloat80_t, extFloat80_t );
extFloat80_t extF80_mul(extFloat80_t, extFloat80_t); extFloat80_t extF80_mul( extFloat80_t, extFloat80_t );
extFloat80_t extF80_div(extFloat80_t, extFloat80_t); extFloat80_t extF80_div( extFloat80_t, extFloat80_t );
extFloat80_t extF80_rem(extFloat80_t, extFloat80_t); extFloat80_t extF80_rem( extFloat80_t, extFloat80_t );
extFloat80_t extF80_sqrt(extFloat80_t); extFloat80_t extF80_sqrt( extFloat80_t );
bool extF80_eq(extFloat80_t, extFloat80_t); bool extF80_eq( extFloat80_t, extFloat80_t );
bool extF80_le(extFloat80_t, extFloat80_t); bool extF80_le( extFloat80_t, extFloat80_t );
bool extF80_lt(extFloat80_t, extFloat80_t); bool extF80_lt( extFloat80_t, extFloat80_t );
bool extF80_eq_signaling(extFloat80_t, extFloat80_t); bool extF80_eq_signaling( extFloat80_t, extFloat80_t );
bool extF80_le_quiet(extFloat80_t, extFloat80_t); bool extF80_le_quiet( extFloat80_t, extFloat80_t );
bool extF80_lt_quiet(extFloat80_t, extFloat80_t); bool extF80_lt_quiet( extFloat80_t, extFloat80_t );
bool extF80_isSignalingNaN(extFloat80_t); bool extF80_isSignalingNaN( extFloat80_t );
#endif #endif
uint_fast32_t extF80M_to_ui32(const extFloat80_t*, uint_fast8_t, bool); uint_fast32_t extF80M_to_ui32( const extFloat80_t *, uint_fast8_t, bool );
uint_fast64_t extF80M_to_ui64(const extFloat80_t*, uint_fast8_t, bool); uint_fast64_t extF80M_to_ui64( const extFloat80_t *, uint_fast8_t, bool );
int_fast32_t extF80M_to_i32(const extFloat80_t*, uint_fast8_t, bool); int_fast32_t extF80M_to_i32( const extFloat80_t *, uint_fast8_t, bool );
int_fast64_t extF80M_to_i64(const extFloat80_t*, uint_fast8_t, bool); int_fast64_t extF80M_to_i64( const extFloat80_t *, uint_fast8_t, bool );
uint_fast32_t extF80M_to_ui32_r_minMag(const extFloat80_t*, bool); uint_fast32_t extF80M_to_ui32_r_minMag( const extFloat80_t *, bool );
uint_fast64_t extF80M_to_ui64_r_minMag(const extFloat80_t*, bool); uint_fast64_t extF80M_to_ui64_r_minMag( const extFloat80_t *, bool );
int_fast32_t extF80M_to_i32_r_minMag(const extFloat80_t*, bool); int_fast32_t extF80M_to_i32_r_minMag( const extFloat80_t *, bool );
int_fast64_t extF80M_to_i64_r_minMag(const extFloat80_t*, bool); int_fast64_t extF80M_to_i64_r_minMag( const extFloat80_t *, bool );
float16_t extF80M_to_f16(const extFloat80_t*); float16_t extF80M_to_f16( const extFloat80_t * );
float32_t extF80M_to_f32(const extFloat80_t*); float32_t extF80M_to_f32( const extFloat80_t * );
float64_t extF80M_to_f64(const extFloat80_t*); float64_t extF80M_to_f64( const extFloat80_t * );
void extF80M_to_f128M(const extFloat80_t*, float128_t*); void extF80M_to_f128M( const extFloat80_t *, float128_t * );
void extF80M_roundToInt(const extFloat80_t*, uint_fast8_t, bool, extFloat80_t*); void
void extF80M_add(const extFloat80_t*, const extFloat80_t*, extFloat80_t*); extF80M_roundToInt(
void extF80M_sub(const extFloat80_t*, const extFloat80_t*, extFloat80_t*); const extFloat80_t *, uint_fast8_t, bool, extFloat80_t * );
void extF80M_mul(const extFloat80_t*, const extFloat80_t*, extFloat80_t*); void extF80M_add( const extFloat80_t *, const extFloat80_t *, extFloat80_t * );
void extF80M_div(const extFloat80_t*, const extFloat80_t*, extFloat80_t*); void extF80M_sub( const extFloat80_t *, const extFloat80_t *, extFloat80_t * );
void extF80M_rem(const extFloat80_t*, const extFloat80_t*, extFloat80_t*); void extF80M_mul( const extFloat80_t *, const extFloat80_t *, extFloat80_t * );
void extF80M_sqrt(const extFloat80_t*, extFloat80_t*); void extF80M_div( const extFloat80_t *, const extFloat80_t *, extFloat80_t * );
bool extF80M_eq(const extFloat80_t*, const extFloat80_t*); void extF80M_rem( const extFloat80_t *, const extFloat80_t *, extFloat80_t * );
bool extF80M_le(const extFloat80_t*, const extFloat80_t*); void extF80M_sqrt( const extFloat80_t *, extFloat80_t * );
bool extF80M_lt(const extFloat80_t*, const extFloat80_t*); bool extF80M_eq( const extFloat80_t *, const extFloat80_t * );
bool extF80M_eq_signaling(const extFloat80_t*, const extFloat80_t*); bool extF80M_le( const extFloat80_t *, const extFloat80_t * );
bool extF80M_le_quiet(const extFloat80_t*, const extFloat80_t*); bool extF80M_lt( const extFloat80_t *, const extFloat80_t * );
bool extF80M_lt_quiet(const extFloat80_t*, const extFloat80_t*); bool extF80M_eq_signaling( const extFloat80_t *, const extFloat80_t * );
bool extF80M_isSignalingNaN(const extFloat80_t*); bool extF80M_le_quiet( const extFloat80_t *, const extFloat80_t * );
bool extF80M_lt_quiet( const extFloat80_t *, const extFloat80_t * );
bool extF80M_isSignalingNaN( const extFloat80_t * );
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| 128-bit (quadruple-precision) floating-point operations. | 128-bit (quadruple-precision) floating-point operations.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef SOFTFLOAT_FAST_INT64 #ifdef SOFTFLOAT_FAST_INT64
uint_fast32_t f128_to_ui32(float128_t, uint_fast8_t, bool); uint_fast32_t f128_to_ui32( float128_t, uint_fast8_t, bool );
uint_fast64_t f128_to_ui64(float128_t, uint_fast8_t, bool); uint_fast64_t f128_to_ui64( float128_t, uint_fast8_t, bool );
int_fast32_t f128_to_i32(float128_t, uint_fast8_t, bool); int_fast32_t f128_to_i32( float128_t, uint_fast8_t, bool );
int_fast64_t f128_to_i64(float128_t, uint_fast8_t, bool); int_fast64_t f128_to_i64( float128_t, uint_fast8_t, bool );
uint_fast32_t f128_to_ui32_r_minMag(float128_t, bool); uint_fast32_t f128_to_ui32_r_minMag( float128_t, bool );
uint_fast64_t f128_to_ui64_r_minMag(float128_t, bool); uint_fast64_t f128_to_ui64_r_minMag( float128_t, bool );
int_fast32_t f128_to_i32_r_minMag(float128_t, bool); int_fast32_t f128_to_i32_r_minMag( float128_t, bool );
int_fast64_t f128_to_i64_r_minMag(float128_t, bool); int_fast64_t f128_to_i64_r_minMag( float128_t, bool );
float16_t f128_to_f16(float128_t); float16_t f128_to_f16( float128_t );
float32_t f128_to_f32(float128_t); float32_t f128_to_f32( float128_t );
float64_t f128_to_f64(float128_t); float64_t f128_to_f64( float128_t );
extFloat80_t f128_to_extF80(float128_t); extFloat80_t f128_to_extF80( float128_t );
float128_t f128_roundToInt(float128_t, uint_fast8_t, bool); float128_t f128_roundToInt( float128_t, uint_fast8_t, bool );
float128_t f128_add(float128_t, float128_t); float128_t f128_add( float128_t, float128_t );
float128_t f128_sub(float128_t, float128_t); float128_t f128_sub( float128_t, float128_t );
float128_t f128_mul(float128_t, float128_t); float128_t f128_mul( float128_t, float128_t );
float128_t f128_mulAdd(float128_t, float128_t, float128_t); float128_t f128_mulAdd( float128_t, float128_t, float128_t );
float128_t f128_div(float128_t, float128_t); float128_t f128_div( float128_t, float128_t );
float128_t f128_rem(float128_t, float128_t); float128_t f128_rem( float128_t, float128_t );
float128_t f128_sqrt(float128_t); float128_t f128_sqrt( float128_t );
bool f128_eq(float128_t, float128_t); bool f128_eq( float128_t, float128_t );
bool f128_le(float128_t, float128_t); bool f128_le( float128_t, float128_t );
bool f128_lt(float128_t, float128_t); bool f128_lt( float128_t, float128_t );
bool f128_eq_signaling(float128_t, float128_t); bool f128_eq_signaling( float128_t, float128_t );
bool f128_le_quiet(float128_t, float128_t); bool f128_le_quiet( float128_t, float128_t );
bool f128_lt_quiet(float128_t, float128_t); bool f128_lt_quiet( float128_t, float128_t );
bool f128_isSignalingNaN(float128_t); bool f128_isSignalingNaN( float128_t );
#endif #endif
uint_fast32_t f128M_to_ui32(const float128_t*, uint_fast8_t, bool); uint_fast32_t f128M_to_ui32( const float128_t *, uint_fast8_t, bool );
uint_fast64_t f128M_to_ui64(const float128_t*, uint_fast8_t, bool); uint_fast64_t f128M_to_ui64( const float128_t *, uint_fast8_t, bool );
int_fast32_t f128M_to_i32(const float128_t*, uint_fast8_t, bool); int_fast32_t f128M_to_i32( const float128_t *, uint_fast8_t, bool );
int_fast64_t f128M_to_i64(const float128_t*, uint_fast8_t, bool); int_fast64_t f128M_to_i64( const float128_t *, uint_fast8_t, bool );
uint_fast32_t f128M_to_ui32_r_minMag(const float128_t*, bool); uint_fast32_t f128M_to_ui32_r_minMag( const float128_t *, bool );
uint_fast64_t f128M_to_ui64_r_minMag(const float128_t*, bool); uint_fast64_t f128M_to_ui64_r_minMag( const float128_t *, bool );
int_fast32_t f128M_to_i32_r_minMag(const float128_t*, bool); int_fast32_t f128M_to_i32_r_minMag( const float128_t *, bool );
int_fast64_t f128M_to_i64_r_minMag(const float128_t*, bool); int_fast64_t f128M_to_i64_r_minMag( const float128_t *, bool );
float16_t f128M_to_f16(const float128_t*); float16_t f128M_to_f16( const float128_t * );
float32_t f128M_to_f32(const float128_t*); float32_t f128M_to_f32( const float128_t * );
float64_t f128M_to_f64(const float128_t*); float64_t f128M_to_f64( const float128_t * );
void f128M_to_extF80M(const float128_t*, extFloat80_t*); void f128M_to_extF80M( const float128_t *, extFloat80_t * );
void f128M_roundToInt(const float128_t*, uint_fast8_t, bool, float128_t*); void f128M_roundToInt( const float128_t *, uint_fast8_t, bool, float128_t * );
void f128M_add(const float128_t*, const float128_t*, float128_t*); void f128M_add( const float128_t *, const float128_t *, float128_t * );
void f128M_sub(const float128_t*, const float128_t*, float128_t*); void f128M_sub( const float128_t *, const float128_t *, float128_t * );
void f128M_mul(const float128_t*, const float128_t*, float128_t*); void f128M_mul( const float128_t *, const float128_t *, float128_t * );
void f128M_mulAdd(const float128_t*, const float128_t*, const float128_t*, float128_t*); void
void f128M_div(const float128_t*, const float128_t*, float128_t*); f128M_mulAdd(
void f128M_rem(const float128_t*, const float128_t*, float128_t*); const float128_t *, const float128_t *, const float128_t *, float128_t *
void f128M_sqrt(const float128_t*, float128_t*); );
bool f128M_eq(const float128_t*, const float128_t*); void f128M_div( const float128_t *, const float128_t *, float128_t * );
bool f128M_le(const float128_t*, const float128_t*); void f128M_rem( const float128_t *, const float128_t *, float128_t * );
bool f128M_lt(const float128_t*, const float128_t*); void f128M_sqrt( const float128_t *, float128_t * );
bool f128M_eq_signaling(const float128_t*, const float128_t*); bool f128M_eq( const float128_t *, const float128_t * );
bool f128M_le_quiet(const float128_t*, const float128_t*); bool f128M_le( const float128_t *, const float128_t * );
bool f128M_lt_quiet(const float128_t*, const float128_t*); bool f128M_lt( const float128_t *, const float128_t * );
bool f128M_isSignalingNaN(const float128_t*); bool f128M_eq_signaling( const float128_t *, const float128_t * );
bool f128M_le_quiet( const float128_t *, const float128_t * );
bool f128M_lt_quiet( const float128_t *, const float128_t * );
bool f128M_isSignalingNaN( const float128_t * );
#endif #endif

View File

@ -47,18 +47,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
| the types below may, if desired, be defined as aliases for the native types | the types below may, if desired, be defined as aliases for the native types
| (typically 'float' and 'double', and possibly 'long double'). | (typically 'float' and 'double', and possibly 'long double').
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
typedef struct { typedef struct { uint16_t v; } float16_t;
uint16_t v; typedef struct { uint32_t v; } float32_t;
} float16_t; typedef struct { uint64_t v; } float64_t;
typedef struct { typedef struct { uint64_t v[2]; } float128_t;
uint32_t v;
} float32_t;
typedef struct {
uint64_t v;
} float64_t;
typedef struct {
uint64_t v[2];
} float128_t;
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The format of an 80-bit extended floating-point number in memory. This | The format of an 80-bit extended floating-point number in memory. This
@ -66,15 +58,9 @@ typedef struct {
| named 'signif'. | named 'signif'.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef LITTLEENDIAN #ifdef LITTLEENDIAN
struct extFloat80M { struct extFloat80M { uint64_t signif; uint16_t signExp; };
uint64_t signif;
uint16_t signExp;
};
#else #else
struct extFloat80M { struct extFloat80M { uint16_t signExp; uint64_t signif; };
uint16_t signExp;
uint64_t signif;
};
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -92,3 +78,4 @@ struct extFloat80M {
typedef struct extFloat80M extFloat80_t; typedef struct extFloat80M extFloat80_t;
#endif #endif

3
src-gen/.gitignore vendored
View File

@ -1,3 +0,0 @@
/iss
/vm
/sysc

View File

@ -1,122 +0,0 @@
/*******************************************************************************
* Copyright (C) 2022 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
* eyck@minres.com - initial implementation
******************************************************************************/
#ifndef _RISCV_HART_M_P_HWL_H
#define _RISCV_HART_M_P_HWL_H
#include "riscv_hart_common.h"
#include <iss/vm_types.h>
namespace iss {
namespace arch {
template <typename BASE> class hwl : public BASE {
public:
using base_class = BASE;
using this_class = hwl<BASE>;
using reg_t = typename BASE::reg_t;
hwl(feature_config cfg = feature_config{});
virtual ~hwl() = default;
protected:
iss::status read_custom_csr_reg(unsigned addr, reg_t& val) override;
iss::status write_custom_csr_reg(unsigned addr, reg_t val) override;
};
template <typename BASE>
inline hwl<BASE>::hwl(feature_config cfg)
: BASE(cfg) {
for(unsigned addr = 0x800; addr < 0x803; ++addr) {
this->register_custom_csr_rd(addr);
this->register_custom_csr_wr(addr);
}
for(unsigned addr = 0x804; addr < 0x807; ++addr) {
this->register_custom_csr_rd(addr);
this->register_custom_csr_wr(addr);
}
}
template <typename BASE> inline iss::status iss::arch::hwl<BASE>::read_custom_csr_reg(unsigned addr, reg_t& val) {
switch(addr) {
case 0x800:
val = this->reg.lpstart0;
break;
case 0x801:
val = this->reg.lpend0;
break;
case 0x802:
val = this->reg.lpcount0;
break;
case 0x804:
val = this->reg.lpstart1;
break;
case 0x805:
val = this->reg.lpend1;
break;
case 0x806:
val = this->reg.lpcount1;
break;
}
return iss::Ok;
}
template <typename BASE> inline iss::status iss::arch::hwl<BASE>::write_custom_csr_reg(unsigned addr, reg_t val) {
switch(addr) {
case 0x800:
this->reg.lpstart0 = val;
break;
case 0x801:
this->reg.lpend0 = val;
break;
case 0x802:
this->reg.lpcount0 = val;
break;
case 0x804:
this->reg.lpstart1 = val;
break;
case 0x805:
this->reg.lpend1 = val;
break;
case 0x806:
this->reg.lpcount1 = val;
break;
}
return iss::Ok;
}
} // namespace arch
} // namespace iss
#endif /* _RISCV_HART_M_P_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,57 +0,0 @@
#ifndef _ISS_ARCH_TGC_MAPPER_H
#define _ISS_ARCH_TGC_MAPPER_H
#include "riscv_hart_m_p.h"
#include "tgc5c.h"
using tgc5c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc5c>;
#ifdef CORE_TGC5A
#include "riscv_hart_m_p.h"
#include <iss/arch/tgc5a.h>
using tgc5a_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc5a>;
#endif
#ifdef CORE_TGC5B
#include "riscv_hart_m_p.h"
#include <iss/arch/tgc5b.h>
using tgc5b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc5b>;
#endif
#ifdef CORE_TGC5C_XRB_NN
#include "hwl.h"
#include "riscv_hart_m_p.h"
#include <iss/arch/tgc5c_xrb_nn.h>
using tgc5c_xrb_nn_plat_type = iss::arch::hwl<iss::arch::riscv_hart_m_p<iss::arch::tgc5c_xrb_nn>>;
#endif
#ifdef CORE_TGC5D
#include "riscv_hart_mu_p.h"
#include <iss/arch/tgc5d.h>
using tgc5d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc5d, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC |
iss::arch::FEAT_EXT_N)>;
#endif
#ifdef CORE_TGC5D_XRB_MAC
#include "riscv_hart_mu_p.h"
#include <iss/arch/tgc5d_xrb_mac.h>
using tgc5d_xrb_mac_plat_type =
iss::arch::riscv_hart_mu_p<iss::arch::tgc5d_xrb_mac,
(iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
#endif
#ifdef CORE_TGC5D_XRB_NN
#include "hwl.h"
#include "riscv_hart_mu_p.h"
#include <iss/arch/tgc5d_xrb_nn.h>
using tgc5d_xrb_nn_plat_type =
iss::arch::hwl<iss::arch::riscv_hart_mu_p<iss::arch::tgc5d_xrb_nn,
(iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>>;
#endif
#ifdef CORE_TGC5E
#include "riscv_hart_mu_p.h"
#include <iss/arch/tgc5e.h>
using tgc5e_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc5e, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC |
iss::arch::FEAT_EXT_N)>;
#endif
#ifdef CORE_TGC5X
#include "riscv_hart_mu_p.h"
#include <iss/arch/tgc5x.h>
using tgc5x_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc5x, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC |
iss::arch::FEAT_EXT_N | iss::arch::FEAT_TCM)>;
#endif
#endif

View File

@ -1,171 +0,0 @@
/*******************************************************************************
* Copyright (C) 2023 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
* eyck@minres.com - initial implementation
******************************************************************************/
#ifndef _RISCV_HART_M_P_WT_CACHE_H
#define _RISCV_HART_M_P_WT_CACHE_H
#include <iss/vm_types.h>
#include <map>
#include <memory>
#include <util/ities.h>
#include <vector>
namespace iss {
namespace arch {
namespace cache {
enum class state { INVALID, VALID };
struct line {
uint64_t tag_addr{0};
state st{state::INVALID};
std::vector<uint8_t> data;
line(unsigned line_sz)
: data(line_sz) {}
};
struct set {
std::vector<line> ways;
set(unsigned ways_count, line const& l)
: ways(ways_count, l) {}
};
struct cache {
std::vector<set> sets;
cache(unsigned size, unsigned line_sz, unsigned ways) {
line const ref_line{line_sz};
set const ref_set{ways, ref_line};
sets.resize(size / (ways * line_sz), ref_set);
}
};
struct wt_policy {
bool is_cacheline_hit(cache& c);
};
} // namespace cache
// write thru, allocate on read, direct mapped or set-associative with round-robin replacement policy
template <typename BASE> class wt_cache : public BASE {
public:
using base_class = BASE;
using this_class = wt_cache<BASE>;
using reg_t = typename BASE::reg_t;
using mem_read_f = typename BASE::mem_read_f;
using mem_write_f = typename BASE::mem_write_f;
using phys_addr_t = typename BASE::phys_addr_t;
wt_cache(feature_config cfg = feature_config{});
virtual ~wt_cache() = default;
unsigned size{4096};
unsigned line_sz{32};
unsigned ways{1};
uint64_t io_address{0xf0000000};
uint64_t io_addr_mask{0xf0000000};
protected:
iss::status read_cache(phys_addr_t addr, unsigned, uint8_t* const);
iss::status write_cache(phys_addr_t addr, unsigned, uint8_t const* const);
std::function<mem_read_f> cache_mem_rd_delegate;
std::function<mem_write_f> cache_mem_wr_delegate;
std::unique_ptr<cache::cache> dcache_ptr;
std::unique_ptr<cache::cache> icache_ptr;
size_t get_way_select() { return 0; }
};
template <typename BASE>
inline wt_cache<BASE>::wt_cache(feature_config cfg)
: BASE(cfg)
, io_address{cfg.io_address}
, io_addr_mask{cfg.io_addr_mask} {
auto cb = base_class::replace_mem_access(
[this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status { return read_cache(a, l, d); },
[this](phys_addr_t a, unsigned l, uint8_t const* const d) -> iss::status { return write_cache(a, l, d); });
cache_mem_rd_delegate = cb.first;
cache_mem_wr_delegate = cb.second;
}
template <typename BASE> iss::status iss::arch::wt_cache<BASE>::read_cache(phys_addr_t a, unsigned l, uint8_t* const d) {
if(!icache_ptr) {
icache_ptr.reset(new cache::cache(size, line_sz, ways));
dcache_ptr.reset(new cache::cache(size, line_sz, ways));
}
if((a.val & io_addr_mask) != io_address) {
auto set_addr = (a.val & (size - 1)) >> util::ilog2(line_sz * ways);
auto tag_addr = a.val >> util::ilog2(line_sz);
auto& set = (is_fetch(a.access) ? icache_ptr : dcache_ptr)->sets[set_addr];
for(auto& cl : set.ways) {
if(cl.st == cache::state::VALID && cl.tag_addr == tag_addr) {
auto start_addr = a.val & (line_sz - 1);
for(auto i = 0U; i < l; ++i)
d[i] = cl.data[start_addr + i];
return iss::Ok;
}
}
auto& cl = set.ways[get_way_select()];
phys_addr_t cl_addr{a};
cl_addr.val = tag_addr << util::ilog2(line_sz);
cache_mem_rd_delegate(cl_addr, line_sz, cl.data.data());
cl.tag_addr = tag_addr;
cl.st = cache::state::VALID;
auto start_addr = a.val & (line_sz - 1);
for(auto i = 0U; i < l; ++i)
d[i] = cl.data[start_addr + i];
return iss::Ok;
} else
return cache_mem_rd_delegate(a, l, d);
}
template <typename BASE> iss::status iss::arch::wt_cache<BASE>::write_cache(phys_addr_t a, unsigned l, const uint8_t* const d) {
if(!dcache_ptr)
dcache_ptr.reset(new cache::cache(size, line_sz, ways));
auto res = cache_mem_wr_delegate(a, l, d);
if(res == iss::Ok && ((a.val & io_addr_mask) != io_address)) {
auto set_addr = (a.val & (size - 1)) >> util::ilog2(line_sz * ways);
auto tag_addr = a.val >> util::ilog2(line_sz);
auto& set = dcache_ptr->sets[set_addr];
for(auto& cl : set.ways) {
if(cl.st == cache::state::VALID && cl.tag_addr == tag_addr) {
auto start_addr = a.val & (line_sz - 1);
for(auto i = 0U; i < l; ++i)
cl.data[start_addr + i] = d[i];
break;
}
}
}
return res;
}
} // namespace arch
} // namespace iss
#endif /* _RISCV_HART_M_P_H */

View File

@ -1,8 +0,0 @@
# pctrace
Trace functionality to allow visualizing coverage in lcov and cachegrind tools. Use environment variables NOCOMPRES and REGDUMP to toggle functionality.
- NOCOMPRES: any value turns off the LZ4 compression
- REGDUMP: any value switches to tracing the registers instead. Also turns off compression.
Known Bugs:
- currently does not work correctly with jit backends, the plugin cant tell if instructions are compressed. Additionaly the cost of instrs that raise a trap is not known. It takes the cost of the instrid -1 (0 at the moment).

View File

@ -1,114 +0,0 @@
/*******************************************************************************
* Copyright (C) 2017 - 2023, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/
#include "cycle_estimate.h"
#include <iss/plugin/calculator.h>
#include <yaml-cpp/yaml.h>
#include <fstream>
#include <iss/arch_if.h>
#include <util/logging.h>
using namespace std;
iss::plugin::cycle_estimate::cycle_estimate(string const& config_file_name)
: instr_if(nullptr)
, config_file_name(config_file_name) {}
iss::plugin::cycle_estimate::~cycle_estimate() = default;
bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if& vm) {
instr_if = vm.get_arch()->get_instrumentation_if();
assert(instr_if && "No instrumentation interface available but callback executed");
reg_base_ptr = reinterpret_cast<uint32_t*>(vm.get_arch()->get_regs_base_ptr());
if(!instr_if)
return false;
const string core_name = instr_if->core_type_name();
if(config_file_name.length() > 0) {
std::ifstream is(config_file_name);
if(is.is_open()) {
try {
auto root = YAML::LoadAll(is);
if(root.size() != 1) {
CPPLOG(ERR) << "Too many root nodes in YAML file " << config_file_name;
}
for(auto p : root[0]) {
auto isa_subset = p.first;
auto instructions = p.second;
for(auto const& instr : instructions) {
auto idx = instr.second["index"].as<unsigned>();
if(delays.size() <= idx)
delays.resize(idx + 1);
auto& res = delays[idx];
res.is_branch = instr.second["branch"].as<bool>();
auto delay = instr.second["delay"];
if(delay.IsSequence()) {
res.not_taken = delay[0].as<uint64_t>();
res.taken = delay[1].as<uint64_t>();
} else {
try {
res.not_taken = delay.as<uint64_t>();
res.taken = res.not_taken;
} catch(const YAML::BadConversion& e) {
res.f = iss::plugin::calculator(reg_base_ptr, delay.as<std::string>());
}
}
}
}
} catch(YAML::ParserException& e) {
CPPLOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
return false;
}
} else {
CPPLOG(ERR) << "Could not open input file " << config_file_name;
return false;
}
}
return true;
}
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info) {
size_t instr_id = instr_info.instr_id;
auto& entry = instr_id < delays.size() ? delays[instr_id] : illegal_desc;
if(instr_info.phase_id == PRE_SYNC) {
if(entry.f)
current_delay = entry.f(instr_if->get_instr_word());
} else {
if(!entry.f)
current_delay = instr_if->is_branch_taken() ? entry.taken : entry.not_taken;
if(current_delay > 1)
instr_if->update_last_instr_cycles(current_delay);
current_delay = 1;
}
}

View File

@ -1,297 +0,0 @@
#include "semihosting.h"
#include <chrono>
#include <cstdint>
#include <iss/vm_types.h>
#include <map>
#include <stdexcept>
// explanation of syscalls can be found at https://github.com/SpinalHDL/openocd_riscv/blob/riscv_spinal/src/target/semihosting_common.h
const char* SYS_OPEN_MODES_STRS[] = {"r", "rb", "r+", "r+b", "w", "wb", "w+", "w+b", "a", "ab", "a+", "a+b"};
template <typename T> T sh_read_field(iss::arch_if* arch_if_ptr, T addr, int len = 4) {
uint8_t bytes[4];
auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, addr, 4, &bytes[0]);
// auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character);
if(res != iss::Ok) {
return 0; // TODO THROW ERROR
} else
return static_cast<T>(bytes[0]) | (static_cast<T>(bytes[1]) << 8) | (static_cast<T>(bytes[2]) << 16) |
(static_cast<T>(bytes[3]) << 24);
}
template <typename T> std::string sh_read_string(iss::arch_if* arch_if_ptr, T addr, T str_len) {
std::vector<uint8_t> buffer(str_len);
for(int i = 0; i < str_len; i++) {
buffer[i] = sh_read_field(arch_if_ptr, addr + i, 1);
}
std::string str(buffer.begin(), buffer.end());
return str;
}
template <typename T> void semihosting_callback<T>::operator()(iss::arch_if* arch_if_ptr, T* call_number, T* parameter) {
static std::map<T, FILE*> openFiles;
static T file_count = 3;
static T semihostingErrno;
switch(static_cast<semihosting_syscalls>(*call_number)) {
case semihosting_syscalls::SYS_CLOCK: {
auto end = std::chrono::high_resolution_clock::now(); // end measurement
auto elapsed = end - timeVar;
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
*call_number = millis; // TODO get time now
break;
}
case semihosting_syscalls::SYS_CLOSE: {
T file_handle = *parameter;
if(openFiles.size() <= file_handle && file_handle < 0) {
semihostingErrno = EBADF;
return;
}
auto file = openFiles[file_handle];
openFiles.erase(file_handle);
if(!(file == stdin || file == stdout || file == stderr)) {
int i = fclose(file);
*call_number = i;
} else {
*call_number = -1;
semihostingErrno = EINTR;
}
break;
}
case semihosting_syscalls::SYS_ELAPSED: {
throw std::runtime_error("Semihosting Call not Implemented");
break;
}
case semihosting_syscalls::SYS_ERRNO: {
*call_number = semihostingErrno;
break;
}
case semihosting_syscalls::SYS_EXIT: {
throw std::runtime_error("ISS terminated by Semihost: SYS_EXIT");
break;
}
case semihosting_syscalls::SYS_EXIT_EXTENDED: {
throw std::runtime_error("ISS terminated by Semihost: SYS_EXIT_EXTENDED");
break;
}
case semihosting_syscalls::SYS_FLEN: {
T file_handle = *parameter;
auto file = openFiles[file_handle];
size_t currentPos = ftell(file);
if(currentPos < 0)
throw std::runtime_error("SYS_FLEN negative value");
fseek(file, 0, SEEK_END);
size_t length = ftell(file);
fseek(file, currentPos, SEEK_SET);
*call_number = (T)length;
break;
}
case semihosting_syscalls::SYS_GET_CMDLINE: {
throw std::runtime_error("Semihosting Call not Implemented");
break;
}
case semihosting_syscalls::SYS_HEAPINFO: {
throw std::runtime_error("Semihosting Call not Implemented");
break;
}
case semihosting_syscalls::SYS_ISERROR: {
T value = *parameter;
*call_number = (value != 0);
break;
}
case semihosting_syscalls::SYS_ISTTY: {
T file_handle = *parameter;
*call_number = (file_handle == 0 || file_handle == 1 || file_handle == 2);
break;
}
case semihosting_syscalls::SYS_OPEN: {
T path_str_addr = sh_read_field<T>(arch_if_ptr, *parameter);
T mode = sh_read_field<T>(arch_if_ptr, 4 + (*parameter));
T path_len = sh_read_field<T>(arch_if_ptr, 8 + (*parameter));
std::string path_str = sh_read_string<T>(arch_if_ptr, path_str_addr, path_len);
// TODO LOG INFO
if(mode >= 12) {
// TODO throw ERROR
return;
}
FILE* file = nullptr;
if(path_str == ":tt") {
if(mode < 4)
file = stdin;
else if(mode < 8)
file = stdout;
else
file = stderr;
} else {
file = fopen(path_str.c_str(), SYS_OPEN_MODES_STRS[mode]);
if(file == nullptr) {
// TODO throw error
return;
}
}
T file_handle = file_count++;
openFiles[file_handle] = file;
*call_number = file_handle;
break;
}
case semihosting_syscalls::SYS_READ: {
T file_handle = sh_read_field<T>(arch_if_ptr, (*parameter) + 4);
T addr = sh_read_field<T>(arch_if_ptr, *parameter);
T count = sh_read_field<T>(arch_if_ptr, (*parameter) + 8);
auto file = openFiles[file_handle];
std::vector<uint8_t> buffer(count);
size_t num_read = 0;
if(file == stdin) {
// when reading from stdin: mimic behaviour from read syscall
// and return on newline.
while(num_read < count) {
char c = fgetc(file);
buffer[num_read] = c;
num_read++;
if(c == '\n')
break;
}
} else {
num_read = fread(buffer.data(), 1, count, file);
}
buffer.resize(num_read);
for(int i = 0; i < num_read; i++) {
auto res = arch_if_ptr->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, addr + i, 1, &buffer[i]);
if(res != iss::Ok)
return;
}
*call_number = count - num_read;
break;
}
case semihosting_syscalls::SYS_READC: {
uint8_t character = getchar();
// character = getchar();
/*if(character != iss::Ok)
std::cout << "Not OK";
return;*/
*call_number = character;
break;
}
case semihosting_syscalls::SYS_REMOVE: {
T path_str_addr = sh_read_field<T>(arch_if_ptr, *parameter);
T path_len = sh_read_field<T>(arch_if_ptr, (*parameter) + 4);
std::string path_str = sh_read_string<T>(arch_if_ptr, path_str_addr, path_len);
if(remove(path_str.c_str()) < 0)
*call_number = -1;
break;
}
case semihosting_syscalls::SYS_RENAME: {
T path_str_addr_old = sh_read_field<T>(arch_if_ptr, *parameter);
T path_len_old = sh_read_field<T>(arch_if_ptr, (*parameter) + 4);
T path_str_addr_new = sh_read_field<T>(arch_if_ptr, (*parameter) + 8);
T path_len_new = sh_read_field<T>(arch_if_ptr, (*parameter) + 12);
std::string path_str_old = sh_read_string<T>(arch_if_ptr, path_str_addr_old, path_len_old);
std::string path_str_new = sh_read_string<T>(arch_if_ptr, path_str_addr_new, path_len_new);
rename(path_str_old.c_str(), path_str_new.c_str());
break;
}
case semihosting_syscalls::SYS_SEEK: {
T file_handle = sh_read_field<T>(arch_if_ptr, *parameter);
T pos = sh_read_field<T>(arch_if_ptr, (*parameter) + 1);
auto file = openFiles[file_handle];
int retval = fseek(file, pos, SEEK_SET);
if(retval < 0)
throw std::runtime_error("SYS_SEEK negative return value");
break;
}
case semihosting_syscalls::SYS_SYSTEM: {
T cmd_addr = sh_read_field<T>(arch_if_ptr, *parameter);
T cmd_len = sh_read_field<T>(arch_if_ptr, (*parameter) + 1);
std::string cmd = sh_read_string<T>(arch_if_ptr, cmd_addr, cmd_len);
system(cmd.c_str());
break;
}
case semihosting_syscalls::SYS_TICKFREQ: {
throw std::runtime_error("Semihosting Call not Implemented");
break;
}
case semihosting_syscalls::SYS_TIME: {
// returns time in seconds scince 01.01.1970 00:00
*call_number = time(NULL);
break;
}
case semihosting_syscalls::SYS_TMPNAM: {
T buffer_addr = sh_read_field<T>(arch_if_ptr, *parameter);
T identifier = sh_read_field<T>(arch_if_ptr, (*parameter) + 1);
T buffer_len = sh_read_field<T>(arch_if_ptr, (*parameter) + 2);
if(identifier > 255) {
*call_number = -1;
return;
}
std::stringstream ss;
ss << "tmp/file-" << std::setfill('0') << std::setw(3) << identifier;
std::string filename = ss.str();
for(int i = 0; i < buffer_len; i++) {
uint8_t character = filename[i];
auto res = arch_if_ptr->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, (*parameter) + i, 1, &character);
if(res != iss::Ok)
return;
}
break;
}
case semihosting_syscalls::SYS_WRITE: {
T file_handle = sh_read_field<T>(arch_if_ptr, (*parameter) + 4);
T addr = sh_read_field<T>(arch_if_ptr, *parameter);
T count = sh_read_field<T>(arch_if_ptr, (*parameter) + 8);
auto file = openFiles[file_handle];
std::string str = sh_read_string<T>(arch_if_ptr, addr, count);
fwrite(&str[0], 1, count, file);
break;
}
case semihosting_syscalls::SYS_WRITEC: {
uint8_t character;
auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character);
if(res != iss::Ok)
return;
putchar(character);
break;
}
case semihosting_syscalls::SYS_WRITE0: {
uint8_t character;
while(1) {
auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character);
if(res != iss::Ok)
return;
if(character == 0)
break;
putchar(character);
(*parameter)++;
}
break;
}
case semihosting_syscalls::USER_CMD_0x100: {
throw std::runtime_error("Semihosting Call not Implemented");
break;
}
case semihosting_syscalls::USER_CMD_0x1FF: {
throw std::runtime_error("Semihosting Call not Implemented");
break;
}
default:
throw std::runtime_error("Semihosting Call not Implemented");
break;
}
}
template class semihosting_callback<uint32_t>;
template class semihosting_callback<uint64_t>;

View File

@ -1,61 +0,0 @@
#ifndef _SEMIHOSTING_H_
#define _SEMIHOSTING_H_
#include <chrono>
#include <functional>
#include <iss/arch_if.h>
/*
* According to:
* "Semihosting for AArch32 and AArch64, Release 2.0"
* https://static.docs.arm.com/100863/0200/semihosting.pdf
* from ARM Ltd.
*
* The available semihosting operation numbers passed in A0 are allocated
* as follows:
* - 0x00-0x31 Used by ARM.
* - 0x32-0xFF Reserved for future use by ARM.
* - 0x100-0x1FF Reserved for user applications. These are not used by ARM.
* However, if you are writing your own SVC operations, you are advised
* to use a different SVC number rather than using the semihosted
* SVC number and these operation type numbers.
* - 0x200-0xFFFFFFFF Undefined and currently unused. It is recommended
* that you do not use these.
*/
enum class semihosting_syscalls {
SYS_OPEN = 0x01,
SYS_CLOSE = 0x02,
SYS_WRITEC = 0x03,
SYS_WRITE0 = 0x04,
SYS_WRITE = 0x05,
SYS_READ = 0x06,
SYS_READC = 0x07,
SYS_ISERROR = 0x08,
SYS_ISTTY = 0x09,
SYS_SEEK = 0x0A,
SYS_FLEN = 0x0C,
SYS_TMPNAM = 0x0D,
SYS_REMOVE = 0x0E,
SYS_RENAME = 0x0F,
SYS_CLOCK = 0x10,
SYS_TIME = 0x11,
SYS_SYSTEM = 0x12,
SYS_ERRNO = 0x13,
SYS_GET_CMDLINE = 0x15,
SYS_HEAPINFO = 0x16,
SYS_EXIT = 0x18,
SYS_EXIT_EXTENDED = 0x20,
SYS_ELAPSED = 0x30,
SYS_TICKFREQ = 0x31,
USER_CMD_0x100 = 0x100,
USER_CMD_0x1FF = 0x1FF,
};
template <typename T> struct semihosting_callback {
std::chrono::high_resolution_clock::time_point timeVar;
semihosting_callback()
: timeVar(std::chrono::high_resolution_clock::now()) {}
void operator()(iss::arch_if* arch_if_ptr, T* call_number, T* parameter);
};
template <typename T> using semihosting_cb_t = std::function<void(iss::arch_if*, T*, T*)>;
#endif

View File

@ -30,29 +30,28 @@
* *
*******************************************************************************/ *******************************************************************************/
// clang-format off
#include "tgc5c.h"
#include "util/ities.h" #include "util/ities.h"
#include <util/logging.h> #include <util/logging.h>
#include <iss/arch/tgc_c.h>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <fstream> #include <fstream>
using namespace iss::arch; using namespace iss::arch;
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc5c>::reg_names; constexpr std::array<const char*, 35> iss::arch::traits<iss::arch::tgc_c>::reg_names;
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc5c>::reg_aliases; constexpr std::array<const char*, 35> iss::arch::traits<iss::arch::tgc_c>::reg_aliases;
constexpr std::array<const uint32_t, 43> iss::arch::traits<iss::arch::tgc5c>::reg_bit_widths; constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
constexpr std::array<const uint32_t, 43> iss::arch::traits<iss::arch::tgc5c>::reg_byte_offsets; constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
tgc5c::tgc5c() = default; tgc_c::tgc_c() {
reg.icount = 0;
}
tgc5c::~tgc5c() = default; tgc_c::~tgc_c() = default;
void tgc5c::reset(uint64_t address) { void tgc_c::reset(uint64_t address) {
auto base_ptr = reinterpret_cast<traits<tgc5c>::reg_t*>(get_regs_base_ptr()); for(size_t i=0; i<traits<tgc_c>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<tgc_c>::reg_t),0));
for(size_t i=0; i<traits<tgc5c>::NUM_REGS; ++i)
*(base_ptr+i)=0;
reg.PC=address; reg.PC=address;
reg.NEXT_PC=reg.PC; reg.NEXT_PC=reg.PC;
reg.PRIV=0x3; reg.PRIV=0x3;
@ -60,11 +59,11 @@ void tgc5c::reset(uint64_t address) {
reg.icount=0; reg.icount=0;
} }
uint8_t *tgc5c::get_regs_base_ptr() { uint8_t *tgc_c::get_regs_base_ptr() {
return reinterpret_cast<uint8_t*>(&reg); return reinterpret_cast<uint8_t*>(&reg);
} }
tgc5c::phys_addr_t tgc5c::virt2phys(const iss::addr_t &addr) { tgc_c::phys_addr_t tgc_c::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<tgc5c>::addr_mask); return phys_addr_t(pc); // change logical address to physical address
} }
// clang-format on

View File

@ -30,33 +30,35 @@
* *
*******************************************************************************/ *******************************************************************************/
#include <array>
#include <cstdint>
#include <iostream> #include <iostream>
#include <iss/factory.h> #include <iss/factory.h>
#include <iss/semihosting/semihosting.h>
#include <string>
#include <unordered_map>
#include <vector>
#include "iss/arch/tgc_mapper.h"
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <iss/arch/riscv_hart_m_p.h>
#include "iss/arch/riscv_hart_m_p.h"
#include "iss/arch/tgc_c.h"
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
#ifdef CORE_TGC_B
#include "iss/arch/riscv_hart_m_p.h"
#include "iss/arch/tgc_b.h"
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
#endif
#ifdef CORE_TGC_D
#include "iss/arch/riscv_hart_mu_p.h"
#include "iss/arch/tgc_d.h"
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
#endif
#ifdef WITH_LLVM #ifdef WITH_LLVM
#include <iss/llvm/jit_init.h> #include <iss/llvm/jit_helper.h>
#endif #endif
#include "iss/plugin/cycle_estimate.h"
#include "iss/plugin/instruction_count.h"
#include <iss/log_categories.h> #include <iss/log_categories.h>
#ifndef WIN32 #include <iss/plugin/cycle_estimate.h>
#include <iss/plugin/loader.h> #include <iss/plugin/instruction_count.h>
#endif
#if defined(HAS_LUA)
#include <iss/plugin/lua.h>
#endif
namespace po = boost::program_options; namespace po = boost::program_options;
int main(int argc, char* argv[]) {
int main(int argc, char *argv[]) {
/* /*
* Define and parse the program options * Define and parse the program options
*/ */
@ -65,29 +67,29 @@ int main(int argc, char* argv[]) {
// clang-format off // clang-format off
desc.add_options() desc.add_options()
("help,h", "Print help message") ("help,h", "Print help message")
("verbose,v", po::value<int>()->default_value(4), "Sets logging verbosity") ("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity")
("logfile,l", po::value<std::string>(), "Sets default log file.") ("logfile,f", po::value<std::string>(), "Sets default log file.")
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly") ("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use") ("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
("instructions,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate") ("instructions,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate")
("reset,r", po::value<std::string>(), "reset address") ("reset,r", po::value<std::string>(), "reset address")
("dump-ir", "dump the intermediate representation") ("dump-ir", "dump the intermediate representation")
("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load") ("elf", po::value<std::vector<std::string>>(), "ELF file(s) to load")
("mem,m", po::value<std::string>(), "the memory input file") ("mem,m", po::value<std::string>(), "the memory input file")
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate") ("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
("backend", po::value<std::string>()->default_value("interp"), "the ISS backend to use, options are: interp, llvm, tcc, asmjit") ("backend", po::value<std::string>()->default_value("interp"), "the memory input file")
("isa", po::value<std::string>()->default_value("tgc5c"), "core or isa name to use for simulation, use '?' to get list"); ("isa", po::value<std::string>()->default_value("tgc_c"), "isa to use for simulation");
// clang-format on // clang-format on
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(); auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
try { try {
po::store(parsed, clim); // can throw po::store(parsed, clim); // can throw
// --help option // --help option
if(clim.count("help")) { if (clim.count("help")) {
std::cout << "DBT-RISE-TGC simulator for TGC RISC-V cores" << std::endl << desc << std::endl; std::cout << "DBT-RISE-RiscV simulator for RISC-V" << std::endl << desc << std::endl;
return 0; return 0;
} }
po::notify(clim); // throws on error, so do after help in case po::notify(clim); // throws on error, so do after help in case
} catch(po::error& e) { } catch (po::error &e) {
// there are problems // there are problems
std::cerr << "ERROR: " << e.what() << std::endl << std::endl; std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
std::cerr << desc << std::endl; std::cerr << desc << std::endl;
@ -97,17 +99,19 @@ int main(int argc, char* argv[]) {
LOGGER(DEFAULT)::print_time() = false; LOGGER(DEFAULT)::print_time() = false;
LOGGER(connection)::print_time() = false; LOGGER(connection)::print_time() = false;
auto l = logging::as_log_level(clim["verbose"].as<int>()); if (clim.count("verbose")) {
LOGGER(DEFAULT)::reporting_level() = l; auto l = logging::as_log_level(clim["verbose"].as<int>());
LOGGER(connection)::reporting_level() = l; LOGGER(DEFAULT)::reporting_level() = l;
if(clim.count("logfile")) { LOGGER(connection)::reporting_level() = l;
}
if (clim.count("logfile")) {
// configure the connection logger // configure the connection logger
auto f = fopen(clim["logfile"].as<std::string>().c_str(), "w"); auto f = fopen(clim["logfile"].as<std::string>().c_str(), "w");
LOG_OUTPUT(DEFAULT)::stream() = f; LOG_OUTPUT(DEFAULT)::stream() = f;
LOG_OUTPUT(connection)::stream() = f; LOG_OUTPUT(connection)::stream() = f;
} }
std::vector<iss::vm_plugin*> plugin_list; std::vector<iss::vm_plugin *> plugin_list;
auto res = 0; auto res = 0;
try { try {
#ifdef WITH_LLVM #ifdef WITH_LLVM
@ -115,145 +119,89 @@ int main(int argc, char* argv[]) {
iss::init_jit_debug(argc, argv); iss::init_jit_debug(argc, argv);
#endif #endif
bool dump = clim.count("dump-ir"); bool dump = clim.count("dump-ir");
auto& f = iss::core_factory::instance();
// instantiate the simulator // instantiate the simulator
iss::vm_ptr vm{nullptr}; iss::vm_ptr vm{nullptr};
iss::cpu_ptr cpu{nullptr}; iss::cpu_ptr cpu{nullptr};
semihosting_callback<uint32_t> cb{};
semihosting_cb_t<uint32_t> semihosting_cb = [&cb](iss::arch_if* i, uint32_t* a0, uint32_t* a1) { cb(i, a0, a1); };
std::string isa_opt(clim["isa"].as<std::string>()); std::string isa_opt(clim["isa"].as<std::string>());
if(isa_opt.size() == 0 || isa_opt == "?") { if (isa_opt == "tgc_c") {
auto list = f.get_names();
std::sort(std::begin(list), std::end(list));
std::cout << "Available implementations (core|platform|backend):\n - " << util::join(list, "\n - ") << std::endl;
return 0;
} else if(isa_opt.find('|') != std::string::npos) {
std::tie(cpu, vm) = std::tie(cpu, vm) =
f.create(isa_opt + "|" + clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>(), &semihosting_cb); iss::create_cpu<tgc_c_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else { } else
auto base_isa = isa_opt.substr(0, 5); #ifdef CORE_TGC_B
if(base_isa == "tgc5d" || base_isa == "tgc5e") { if (isa_opt == "tgc_b") {
isa_opt += "|mu_p_clic_pmp|" + clim["backend"].as<std::string>(); std::tie(cpu, vm) =
} else { iss::create_cpu<tgc_b_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
isa_opt += "|m_p|" + clim["backend"].as<std::string>(); } else
} #endif
std::tie(cpu, vm) = f.create(isa_opt, clim["gdb-port"].as<unsigned>(), &semihosting_cb); #ifdef CORE_TGC_D
} if (isa_opt == "tgc_d") {
if(!cpu) { std::tie(cpu, vm) =
CPPLOG(ERR) << "Could not create cpu for isa " << isa_opt << " and backend " << clim["backend"].as<std::string>() << std::endl; iss::create_cpu<tgc_d_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
{
LOG(ERR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
return 127; return 127;
} }
if(!vm) { if (clim.count("plugin")) {
CPPLOG(ERR) << "Could not create vm for isa " << isa_opt << " and backend " << clim["backend"].as<std::string>() << std::endl; for (std::string const& opt_val : clim["plugin"].as<std::vector<std::string>>()) {
return 127; std::string plugin_name=opt_val;
} std::string filename{"cycles.txt"};
if(clim.count("plugin")) {
for(std::string const& opt_val : clim["plugin"].as<std::vector<std::string>>()) {
std::string plugin_name = opt_val;
std::string arg{""};
std::size_t found = opt_val.find('='); std::size_t found = opt_val.find('=');
if(found != std::string::npos) { if (found != std::string::npos) {
plugin_name = opt_val.substr(0, found); plugin_name = opt_val.substr(0, found);
arg = opt_val.substr(found + 1, opt_val.size()); filename = opt_val.substr(found + 1, opt_val.size());
} }
#if defined(WITH_PLUGINS) if (plugin_name == "ic") {
if(plugin_name == "ic") { auto *ic_plugin = new iss::plugin::instruction_count(filename);
auto* ic_plugin = new iss::plugin::instruction_count(arg);
vm->register_plugin(*ic_plugin); vm->register_plugin(*ic_plugin);
plugin_list.push_back(ic_plugin); plugin_list.push_back(ic_plugin);
} else if(plugin_name == "ce") { } else if (plugin_name == "ce") {
auto* ce_plugin = new iss::plugin::cycle_estimate(arg); auto *ce_plugin = new iss::plugin::cycle_estimate(filename);
vm->register_plugin(*ce_plugin); vm->register_plugin(*ce_plugin);
plugin_list.push_back(ce_plugin); plugin_list.push_back(ce_plugin);
} else } else {
#endif LOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
{ return 127;
#if !defined(WIN32)
std::vector<char const*> a{};
if(arg.length())
a.push_back({arg.c_str()});
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
if(plugin) {
vm->register_plugin(*plugin);
plugin_list.push_back(plugin);
} else
#endif
{
CPPLOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
return 127;
}
} }
} }
} }
if(clim.count("disass")) { if (clim.count("disass")) {
vm->setDisassEnabled(true); vm->setDisassEnabled(true);
LOGGER(disass)::reporting_level() = logging::INFO; LOGGER(disass)::reporting_level() = logging::INFO;
LOGGER(disass)::print_time() = false; LOGGER(disass)::print_time() = false;
auto file_name = clim["disass"].as<std::string>(); auto file_name = clim["disass"].as<std::string>();
if(file_name.length() > 0) { if (file_name.length() > 0) {
LOG_OUTPUT(disass)::stream() = fopen(file_name.c_str(), "w"); LOG_OUTPUT(disass)::stream() = fopen(file_name.c_str(), "w");
LOGGER(disass)::print_severity() = false; LOGGER(disass)::print_severity() = false;
} }
} }
uint64_t start_address = 0; uint64_t start_address = 0;
if(clim.count("mem")) if (clim.count("mem"))
vm->get_arch()->load_file(clim["mem"].as<std::string>()); vm->get_arch()->load_file(clim["mem"].as<std::string>());
if(clim.count("elf")) if (clim.count("elf"))
for(std::string input : clim["elf"].as<std::vector<std::string>>()) { for (std::string input : clim["elf"].as<std::vector<std::string>>()) {
auto start_addr = vm->get_arch()->load_file(input); auto start_addr = vm->get_arch()->load_file(input);
if(start_addr.second) // FIXME: this always evaluates to true as load file always returns <sth, true> if (start_addr.second) start_address = start_addr.first;
start_address = start_addr.first;
} }
for(std::string input : args) { for (std::string input : args) {
auto start_addr = vm->get_arch()->load_file(input); // treat remaining arguments as elf files auto start_addr = vm->get_arch()->load_file(input); // treat remaining arguments as elf files
if(start_addr.second) // FIXME: this always evaluates to true as load file always returns <sth, true> if (start_addr.second) start_address = start_addr.first;
start_address = start_addr.first;
} }
if(clim.count("reset")) { if (clim.count("reset")) {
auto str = clim["reset"].as<std::string>(); auto str = clim["reset"].as<std::string>();
start_address = str.find("0x") == 0 ? std::stoull(str.substr(2), nullptr, 16) : std::stoull(str, nullptr, 10); start_address = str.find("0x") == 0 ? std::stoull(str.substr(2), nullptr, 16) : std::stoull(str, nullptr, 10);
} }
vm->reset(start_address); vm->reset(start_address);
auto cycles = clim["instructions"].as<uint64_t>(); auto cycles = clim["instructions"].as<uint64_t>();
res = vm->start(cycles, dump); res = vm->start(cycles, dump);
} catch (std::exception &e) {
auto instr_if = vm->get_arch()->get_instrumentation_if(); LOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit"
// this assumes a single input file << std::endl;
std::unordered_map<std::string, uint64_t> sym_table;
if(args.empty())
sym_table = instr_if->get_symbol_table(clim["elf"].as<std::vector<std::string>>()[0]);
else
sym_table = instr_if->get_symbol_table(args[0]);
if(sym_table.find("begin_signature") != std::end(sym_table) && sym_table.find("end_signature") != std::end(sym_table)) {
auto start_addr = sym_table["begin_signature"];
auto end_addr = sym_table["end_signature"];
std::array<uint8_t, 4> data;
std::ofstream file;
std::string filename = fmt::format("{}.signature", isa_opt);
std::replace(std::begin(filename), std::end(filename), '|', '_');
// default riscof requires this filename
filename = "DUT-tgc.signature";
file.open(filename, std::ios::out);
if(!file.is_open()) {
LOG(ERR) << "Error opening file " << filename << std::endl;
return 1;
}
for(auto addr = start_addr; addr < end_addr; addr += data.size()) {
vm->get_arch()->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0 /*MEM*/, addr, data.size(),
data.data()); // FIXME: get space from iss::arch::traits<ARCH>::mem_type_e::MEM
// TODO : obey Target endianess
uint32_t to_print = (data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
file << std::hex << fmt::format("{:08x}", to_print) << std::dec << std::endl;
}
}
} catch(std::exception& e) {
CPPLOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit" << std::endl;
res = 2; res = 2;
} }
// cleanup to let plugins report if needed // cleanup to let plugins report of needed
for(auto* p : plugin_list) { for (auto *p : plugin_list) {
delete p; delete p;
} }
return res; return res;

821
src/plugin/GCOV.cpp Normal file
View File

@ -0,0 +1,821 @@
//===- GCOV.cpp - LLVM coverage tool --------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// GCOV implements the interface to read and write coverage files that use
// 'gcov' format.
//
//===----------------------------------------------------------------------===//
#include "GCOV.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <system_error>
using namespace llvm;
//===----------------------------------------------------------------------===//
// GCOVFile implementation.
/// readGCNO - Read GCNO buffer.
bool GCOVFile::readGCNO(GCOVBuffer &Buffer) {
if (!Buffer.readGCNOFormat())
return false;
if (!Buffer.readGCOVVersion(Version))
return false;
if (!Buffer.readInt(Checksum))
return false;
while (true) {
if (!Buffer.readFunctionTag())
break;
auto GFun = make_unique<GCOVFunction>(*this);
if (!GFun->readGCNO(Buffer, Version))
return false;
Functions.push_back(std::move(GFun));
}
GCNOInitialized = true;
return true;
}
/// readGCDA - Read GCDA buffer. It is required that readGCDA() can only be
/// called after readGCNO().
bool GCOVFile::readGCDA(GCOVBuffer &Buffer) {
assert(GCNOInitialized && "readGCDA() can only be called after readGCNO()");
if (!Buffer.readGCDAFormat())
return false;
GCOV::GCOVVersion GCDAVersion;
if (!Buffer.readGCOVVersion(GCDAVersion))
return false;
if (Version != GCDAVersion) {
errs() << "GCOV versions do not match.\n";
return false;
}
uint32_t GCDAChecksum;
if (!Buffer.readInt(GCDAChecksum))
return false;
if (Checksum != GCDAChecksum) {
errs() << "File checksums do not match: " << Checksum
<< " != " << GCDAChecksum << ".\n";
return false;
}
for (size_t i = 0, e = Functions.size(); i < e; ++i) {
if (!Buffer.readFunctionTag()) {
errs() << "Unexpected number of functions.\n";
return false;
}
if (!Functions[i]->readGCDA(Buffer, Version))
return false;
}
if (Buffer.readObjectTag()) {
uint32_t Length;
uint32_t Dummy;
if (!Buffer.readInt(Length))
return false;
if (!Buffer.readInt(Dummy))
return false; // checksum
if (!Buffer.readInt(Dummy))
return false; // num
if (!Buffer.readInt(RunCount))
return false;
Buffer.advanceCursor(Length - 3);
}
while (Buffer.readProgramTag()) {
uint32_t Length;
if (!Buffer.readInt(Length))
return false;
Buffer.advanceCursor(Length);
++ProgramCount;
}
return true;
}
void GCOVFile::print(raw_ostream &OS) const {
for (const auto &FPtr : Functions)
FPtr->print(OS);
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// dump - Dump GCOVFile content to dbgs() for debugging purposes.
LLVM_DUMP_METHOD void GCOVFile::dump() const {
print(dbgs());
}
#endif
/// collectLineCounts - Collect line counts. This must be used after
/// reading .gcno and .gcda files.
void GCOVFile::collectLineCounts(FileInfo &FI) {
for (const auto &FPtr : Functions)
FPtr->collectLineCounts(FI);
FI.setRunCount(RunCount);
FI.setProgramCount(ProgramCount);
}
//===----------------------------------------------------------------------===//
// GCOVFunction implementation.
/// readGCNO - Read a function from the GCNO buffer. Return false if an error
/// occurs.
bool GCOVFunction::readGCNO(GCOVBuffer &Buff, GCOV::GCOVVersion Version) {
uint32_t Dummy;
if (!Buff.readInt(Dummy))
return false; // Function header length
if (!Buff.readInt(Ident))
return false;
if (!Buff.readInt(Checksum))
return false;
if (Version != GCOV::V402) {
uint32_t CfgChecksum;
if (!Buff.readInt(CfgChecksum))
return false;
if (Parent.getChecksum() != CfgChecksum) {
errs() << "File checksums do not match: " << Parent.getChecksum()
<< " != " << CfgChecksum << " in (" << Name << ").\n";
return false;
}
}
if (!Buff.readString(Name))
return false;
if (!Buff.readString(Filename))
return false;
if (!Buff.readInt(LineNumber))
return false;
// read blocks.
if (!Buff.readBlockTag()) {
errs() << "Block tag not found.\n";
return false;
}
uint32_t BlockCount;
if (!Buff.readInt(BlockCount))
return false;
for (uint32_t i = 0, e = BlockCount; i != e; ++i) {
if (!Buff.readInt(Dummy))
return false; // Block flags;
Blocks.push_back(make_unique<GCOVBlock>(*this, i));
}
// read edges.
while (Buff.readEdgeTag()) {
uint32_t EdgeCount;
if (!Buff.readInt(EdgeCount))
return false;
EdgeCount = (EdgeCount - 1) / 2;
uint32_t BlockNo;
if (!Buff.readInt(BlockNo))
return false;
if (BlockNo >= BlockCount) {
errs() << "Unexpected block number: " << BlockNo << " (in " << Name
<< ").\n";
return false;
}
for (uint32_t i = 0, e = EdgeCount; i != e; ++i) {
uint32_t Dst;
if (!Buff.readInt(Dst))
return false;
Edges.push_back(make_unique<GCOVEdge>(*Blocks[BlockNo], *Blocks[Dst]));
GCOVEdge *Edge = Edges.back().get();
Blocks[BlockNo]->addDstEdge(Edge);
Blocks[Dst]->addSrcEdge(Edge);
if (!Buff.readInt(Dummy))
return false; // Edge flag
}
}
// read line table.
while (Buff.readLineTag()) {
uint32_t LineTableLength;
// Read the length of this line table.
if (!Buff.readInt(LineTableLength))
return false;
uint32_t EndPos = Buff.getCursor() + LineTableLength * 4;
uint32_t BlockNo;
// Read the block number this table is associated with.
if (!Buff.readInt(BlockNo))
return false;
if (BlockNo >= BlockCount) {
errs() << "Unexpected block number: " << BlockNo << " (in " << Name
<< ").\n";
return false;
}
GCOVBlock &Block = *Blocks[BlockNo];
// Read the word that pads the beginning of the line table. This may be a
// flag of some sort, but seems to always be zero.
if (!Buff.readInt(Dummy))
return false;
// Line information starts here and continues up until the last word.
if (Buff.getCursor() != (EndPos - sizeof(uint32_t))) {
StringRef F;
// Read the source file name.
if (!Buff.readString(F))
return false;
if (Filename != F) {
errs() << "Multiple sources for a single basic block: " << Filename
<< " != " << F << " (in " << Name << ").\n";
return false;
}
// Read lines up to, but not including, the null terminator.
while (Buff.getCursor() < (EndPos - 2 * sizeof(uint32_t))) {
uint32_t Line;
if (!Buff.readInt(Line))
return false;
// Line 0 means this instruction was injected by the compiler. Skip it.
if (!Line)
continue;
Block.addLine(Line);
}
// Read the null terminator.
if (!Buff.readInt(Dummy))
return false;
}
// The last word is either a flag or padding, it isn't clear which. Skip
// over it.
if (!Buff.readInt(Dummy))
return false;
}
return true;
}
/// readGCDA - Read a function from the GCDA buffer. Return false if an error
/// occurs.
bool GCOVFunction::readGCDA(GCOVBuffer &Buff, GCOV::GCOVVersion Version) {
uint32_t HeaderLength;
if (!Buff.readInt(HeaderLength))
return false; // Function header length
uint64_t EndPos = Buff.getCursor() + HeaderLength * sizeof(uint32_t);
uint32_t GCDAIdent;
if (!Buff.readInt(GCDAIdent))
return false;
if (Ident != GCDAIdent) {
errs() << "Function identifiers do not match: " << Ident
<< " != " << GCDAIdent << " (in " << Name << ").\n";
return false;
}
uint32_t GCDAChecksum;
if (!Buff.readInt(GCDAChecksum))
return false;
if (Checksum != GCDAChecksum) {
errs() << "Function checksums do not match: " << Checksum
<< " != " << GCDAChecksum << " (in " << Name << ").\n";
return false;
}
uint32_t CfgChecksum;
if (Version != GCOV::V402) {
if (!Buff.readInt(CfgChecksum))
return false;
if (Parent.getChecksum() != CfgChecksum) {
errs() << "File checksums do not match: " << Parent.getChecksum()
<< " != " << CfgChecksum << " (in " << Name << ").\n";
return false;
}
}
if (Buff.getCursor() < EndPos) {
StringRef GCDAName;
if (!Buff.readString(GCDAName))
return false;
if (Name != GCDAName) {
errs() << "Function names do not match: " << Name << " != " << GCDAName
<< ".\n";
return false;
}
}
if (!Buff.readArcTag()) {
errs() << "Arc tag not found (in " << Name << ").\n";
return false;
}
uint32_t Count;
if (!Buff.readInt(Count))
return false;
Count /= 2;
// This for loop adds the counts for each block. A second nested loop is
// required to combine the edge counts that are contained in the GCDA file.
for (uint32_t BlockNo = 0; Count > 0; ++BlockNo) {
// The last block is always reserved for exit block
if (BlockNo >= Blocks.size()) {
errs() << "Unexpected number of edges (in " << Name << ").\n";
return false;
}
if (BlockNo == Blocks.size() - 1)
errs() << "(" << Name << ") has arcs from exit block.\n";
GCOVBlock &Block = *Blocks[BlockNo];
for (size_t EdgeNo = 0, End = Block.getNumDstEdges(); EdgeNo < End;
++EdgeNo) {
if (Count == 0) {
errs() << "Unexpected number of edges (in " << Name << ").\n";
return false;
}
uint64_t ArcCount;
if (!Buff.readInt64(ArcCount))
return false;
Block.addCount(EdgeNo, ArcCount);
--Count;
}
Block.sortDstEdges();
}
return true;
}
/// getEntryCount - Get the number of times the function was called by
/// retrieving the entry block's count.
uint64_t GCOVFunction::getEntryCount() const {
return Blocks.front()->getCount();
}
/// getExitCount - Get the number of times the function returned by retrieving
/// the exit block's count.
uint64_t GCOVFunction::getExitCount() const {
return Blocks.back()->getCount();
}
void GCOVFunction::print(raw_ostream &OS) const {
OS << "===== " << Name << " (" << Ident << ") @ " << Filename << ":"
<< LineNumber << "\n";
for (const auto &Block : Blocks)
Block->print(OS);
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// dump - Dump GCOVFunction content to dbgs() for debugging purposes.
LLVM_DUMP_METHOD void GCOVFunction::dump() const {
print(dbgs());
}
#endif
/// collectLineCounts - Collect line counts. This must be used after
/// reading .gcno and .gcda files.
void GCOVFunction::collectLineCounts(FileInfo &FI) {
// If the line number is zero, this is a function that doesn't actually appear
// in the source file, so there isn't anything we can do with it.
if (LineNumber == 0)
return;
for (const auto &Block : Blocks)
Block->collectLineCounts(FI);
FI.addFunctionLine(Filename, LineNumber, this);
}
//===----------------------------------------------------------------------===//
// GCOVBlock implementation.
/// ~GCOVBlock - Delete GCOVBlock and its content.
GCOVBlock::~GCOVBlock() {
SrcEdges.clear();
DstEdges.clear();
Lines.clear();
}
/// addCount - Add to block counter while storing the edge count. If the
/// destination has no outgoing edges, also update that block's count too.
void GCOVBlock::addCount(size_t DstEdgeNo, uint64_t N) {
assert(DstEdgeNo < DstEdges.size()); // up to caller to ensure EdgeNo is valid
DstEdges[DstEdgeNo]->Count = N;
Counter += N;
if (!DstEdges[DstEdgeNo]->Dst.getNumDstEdges())
DstEdges[DstEdgeNo]->Dst.Counter += N;
}
/// sortDstEdges - Sort destination edges by block number, nop if already
/// sorted. This is required for printing branch info in the correct order.
void GCOVBlock::sortDstEdges() {
if (!DstEdgesAreSorted) {
SortDstEdgesFunctor SortEdges;
std::stable_sort(DstEdges.begin(), DstEdges.end(), SortEdges);
}
}
/// collectLineCounts - Collect line counts. This must be used after
/// reading .gcno and .gcda files.
void GCOVBlock::collectLineCounts(FileInfo &FI) {
for (uint32_t N : Lines)
FI.addBlockLine(Parent.getFilename(), N, this);
}
void GCOVBlock::print(raw_ostream &OS) const {
OS << "Block : " << Number << " Counter : " << Counter << "\n";
if (!SrcEdges.empty()) {
OS << "\tSource Edges : ";
for (const GCOVEdge *Edge : SrcEdges)
OS << Edge->Src.Number << " (" << Edge->Count << "), ";
OS << "\n";
}
if (!DstEdges.empty()) {
OS << "\tDestination Edges : ";
for (const GCOVEdge *Edge : DstEdges)
OS << Edge->Dst.Number << " (" << Edge->Count << "), ";
OS << "\n";
}
if (!Lines.empty()) {
OS << "\tLines : ";
for (uint32_t N : Lines)
OS << (N) << ",";
OS << "\n";
}
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// dump - Dump GCOVBlock content to dbgs() for debugging purposes.
LLVM_DUMP_METHOD void GCOVBlock::dump() const {
print(dbgs());
}
#endif
//===----------------------------------------------------------------------===//
// FileInfo implementation.
// Safe integer division, returns 0 if numerator is 0.
static uint32_t safeDiv(uint64_t Numerator, uint64_t Divisor) {
if (!Numerator)
return 0;
return Numerator / Divisor;
}
// This custom division function mimics gcov's branch ouputs:
// - Round to closest whole number
// - Only output 0% or 100% if it's exactly that value
static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) {
if (!Numerator)
return 0;
if (Numerator == Divisor)
return 100;
uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor;
if (Res == 0)
return 1;
if (Res == 100)
return 99;
return Res;
}
namespace {
struct formatBranchInfo {
formatBranchInfo(const GCOV::Options &Options, uint64_t Count, uint64_t Total)
: Options(Options), Count(Count), Total(Total) {}
void print(raw_ostream &OS) const {
if (!Total)
OS << "never executed";
else if (Options.BranchCount)
OS << "taken " << Count;
else
OS << "taken " << branchDiv(Count, Total) << "%";
}
const GCOV::Options &Options;
uint64_t Count;
uint64_t Total;
};
static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) {
FBI.print(OS);
return OS;
}
class LineConsumer {
std::unique_ptr<MemoryBuffer> Buffer;
StringRef Remaining;
public:
LineConsumer(StringRef Filename) {
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
MemoryBuffer::getFileOrSTDIN(Filename);
if (std::error_code EC = BufferOrErr.getError()) {
errs() << Filename << ": " << EC.message() << "\n";
Remaining = "";
} else {
Buffer = std::move(BufferOrErr.get());
Remaining = Buffer->getBuffer();
}
}
bool empty() { return Remaining.empty(); }
void printNext(raw_ostream &OS, uint32_t LineNum) {
StringRef Line;
if (empty())
Line = "/*EOF*/";
else
std::tie(Line, Remaining) = Remaining.split("\n");
OS << format("%5u:", LineNum) << Line << "\n";
}
};
} // end anonymous namespace
/// Convert a path to a gcov filename. If PreservePaths is true, this
/// translates "/" to "#", ".." to "^", and drops ".", to match gcov.
static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) {
if (!PreservePaths)
return sys::path::filename(Filename).str();
// This behaviour is defined by gcov in terms of text replacements, so it's
// not likely to do anything useful on filesystems with different textual
// conventions.
llvm::SmallString<256> Result("");
StringRef::iterator I, S, E;
for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I) {
if (*I != '/')
continue;
if (I - S == 1 && *S == '.') {
// ".", the current directory, is skipped.
} else if (I - S == 2 && *S == '.' && *(S + 1) == '.') {
// "..", the parent directory, is replaced with "^".
Result.append("^#");
} else {
if (S < I)
// Leave other components intact,
Result.append(S, I);
// And separate with "#".
Result.push_back('#');
}
S = I + 1;
}
if (S < I)
Result.append(S, I);
return Result.str();
}
std::string FileInfo::getCoveragePath(StringRef Filename,
StringRef MainFilename) {
if (Options.NoOutput)
// This is probably a bug in gcov, but when -n is specified, paths aren't
// mangled at all, and the -l and -p options are ignored. Here, we do the
// same.
return Filename;
std::string CoveragePath;
if (Options.LongFileNames && !Filename.equals(MainFilename))
CoveragePath =
mangleCoveragePath(MainFilename, Options.PreservePaths) + "##";
CoveragePath += mangleCoveragePath(Filename, Options.PreservePaths) + ".gcov";
return CoveragePath;
}
std::unique_ptr<raw_ostream>
FileInfo::openCoveragePath(StringRef CoveragePath) {
if (Options.NoOutput)
return llvm::make_unique<raw_null_ostream>();
std::error_code EC;
auto OS = llvm::make_unique<raw_fd_ostream>(CoveragePath, EC,
sys::fs::F_Text);
if (EC) {
errs() << EC.message() << "\n";
return llvm::make_unique<raw_null_ostream>();
}
return std::move(OS);
}
/// print - Print source files with collected line count information.
void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
StringRef GCNOFile, StringRef GCDAFile) {
SmallVector<StringRef, 4> Filenames;
for (const auto &LI : LineInfo)
Filenames.push_back(LI.first());
std::sort(Filenames.begin(), Filenames.end());
for (StringRef Filename : Filenames) {
auto AllLines = LineConsumer(Filename);
std::string CoveragePath = getCoveragePath(Filename, MainFilename);
std::unique_ptr<raw_ostream> CovStream = openCoveragePath(CoveragePath);
raw_ostream &CovOS = *CovStream;
CovOS << " -: 0:Source:" << Filename << "\n";
CovOS << " -: 0:Graph:" << GCNOFile << "\n";
CovOS << " -: 0:Data:" << GCDAFile << "\n";
CovOS << " -: 0:Runs:" << RunCount << "\n";
CovOS << " -: 0:Programs:" << ProgramCount << "\n";
const LineData &Line = LineInfo[Filename];
GCOVCoverage FileCoverage(Filename);
for (uint32_t LineIndex = 0; LineIndex < Line.LastLine || !AllLines.empty();
++LineIndex) {
if (Options.BranchInfo) {
FunctionLines::const_iterator FuncsIt = Line.Functions.find(LineIndex);
if (FuncsIt != Line.Functions.end())
printFunctionSummary(CovOS, FuncsIt->second);
}
BlockLines::const_iterator BlocksIt = Line.Blocks.find(LineIndex);
if (BlocksIt == Line.Blocks.end()) {
// No basic blocks are on this line. Not an executable line of code.
CovOS << " -:";
AllLines.printNext(CovOS, LineIndex + 1);
} else {
const BlockVector &Blocks = BlocksIt->second;
// Add up the block counts to form line counts.
DenseMap<const GCOVFunction *, bool> LineExecs;
uint64_t LineCount = 0;
for (const GCOVBlock *Block : Blocks) {
if (Options.AllBlocks) {
// Only take the highest block count for that line.
uint64_t BlockCount = Block->getCount();
LineCount = LineCount > BlockCount ? LineCount : BlockCount;
} else {
// Sum up all of the block counts.
LineCount += Block->getCount();
}
if (Options.FuncCoverage) {
// This is a slightly convoluted way to most accurately gather line
// statistics for functions. Basically what is happening is that we
// don't want to count a single line with multiple blocks more than
// once. However, we also don't simply want to give the total line
// count to every function that starts on the line. Thus, what is
// happening here are two things:
// 1) Ensure that the number of logical lines is only incremented
// once per function.
// 2) If there are multiple blocks on the same line, ensure that the
// number of lines executed is incremented as long as at least
// one of the blocks are executed.
const GCOVFunction *Function = &Block->getParent();
if (FuncCoverages.find(Function) == FuncCoverages.end()) {
std::pair<const GCOVFunction *, GCOVCoverage> KeyValue(
Function, GCOVCoverage(Function->getName()));
FuncCoverages.insert(KeyValue);
}
GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second;
if (LineExecs.find(Function) == LineExecs.end()) {
if (Block->getCount()) {
++FuncCoverage.LinesExec;
LineExecs[Function] = true;
} else {
LineExecs[Function] = false;
}
++FuncCoverage.LogicalLines;
} else if (!LineExecs[Function] && Block->getCount()) {
++FuncCoverage.LinesExec;
LineExecs[Function] = true;
}
}
}
if (LineCount == 0)
CovOS << " #####:";
else {
CovOS << format("%9" PRIu64 ":", LineCount);
++FileCoverage.LinesExec;
}
++FileCoverage.LogicalLines;
AllLines.printNext(CovOS, LineIndex + 1);
uint32_t BlockNo = 0;
uint32_t EdgeNo = 0;
for (const GCOVBlock *Block : Blocks) {
// Only print block and branch information at the end of the block.
if (Block->getLastLine() != LineIndex + 1)
continue;
if (Options.AllBlocks)
printBlockInfo(CovOS, *Block, LineIndex, BlockNo);
if (Options.BranchInfo) {
size_t NumEdges = Block->getNumDstEdges();
if (NumEdges > 1)
printBranchInfo(CovOS, *Block, FileCoverage, EdgeNo);
else if (Options.UncondBranch && NumEdges == 1)
printUncondBranchInfo(CovOS, EdgeNo,
(*Block->dst_begin())->Count);
}
}
}
}
FileCoverages.push_back(std::make_pair(CoveragePath, FileCoverage));
}
// FIXME: There is no way to detect calls given current instrumentation.
if (Options.FuncCoverage)
printFuncCoverage(InfoOS);
printFileCoverage(InfoOS);
}
/// printFunctionSummary - Print function and block summary.
void FileInfo::printFunctionSummary(raw_ostream &OS,
const FunctionVector &Funcs) const {
for (const GCOVFunction *Func : Funcs) {
uint64_t EntryCount = Func->getEntryCount();
uint32_t BlocksExec = 0;
for (const GCOVBlock &Block : Func->blocks())
if (Block.getNumDstEdges() && Block.getCount())
++BlocksExec;
OS << "function " << Func->getName() << " called " << EntryCount
<< " returned " << safeDiv(Func->getExitCount() * 100, EntryCount)
<< "% blocks executed "
<< safeDiv(BlocksExec * 100, Func->getNumBlocks() - 1) << "%\n";
}
}
/// printBlockInfo - Output counts for each block.
void FileInfo::printBlockInfo(raw_ostream &OS, const GCOVBlock &Block,
uint32_t LineIndex, uint32_t &BlockNo) const {
if (Block.getCount() == 0)
OS << " $$$$$:";
else
OS << format("%9" PRIu64 ":", Block.getCount());
OS << format("%5u-block %2u\n", LineIndex + 1, BlockNo++);
}
/// printBranchInfo - Print conditional branch probabilities.
void FileInfo::printBranchInfo(raw_ostream &OS, const GCOVBlock &Block,
GCOVCoverage &Coverage, uint32_t &EdgeNo) {
SmallVector<uint64_t, 16> BranchCounts;
uint64_t TotalCounts = 0;
for (const GCOVEdge *Edge : Block.dsts()) {
BranchCounts.push_back(Edge->Count);
TotalCounts += Edge->Count;
if (Block.getCount())
++Coverage.BranchesExec;
if (Edge->Count)
++Coverage.BranchesTaken;
++Coverage.Branches;
if (Options.FuncCoverage) {
const GCOVFunction *Function = &Block.getParent();
GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second;
if (Block.getCount())
++FuncCoverage.BranchesExec;
if (Edge->Count)
++FuncCoverage.BranchesTaken;
++FuncCoverage.Branches;
}
}
for (uint64_t N : BranchCounts)
OS << format("branch %2u ", EdgeNo++)
<< formatBranchInfo(Options, N, TotalCounts) << "\n";
}
/// printUncondBranchInfo - Print unconditional branch probabilities.
void FileInfo::printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo,
uint64_t Count) const {
OS << format("unconditional %2u ", EdgeNo++)
<< formatBranchInfo(Options, Count, Count) << "\n";
}
// printCoverage - Print generic coverage info used by both printFuncCoverage
// and printFileCoverage.
void FileInfo::printCoverage(raw_ostream &OS,
const GCOVCoverage &Coverage) const {
OS << format("Lines executed:%.2f%% of %u\n",
double(Coverage.LinesExec) * 100 / Coverage.LogicalLines,
Coverage.LogicalLines);
if (Options.BranchInfo) {
if (Coverage.Branches) {
OS << format("Branches executed:%.2f%% of %u\n",
double(Coverage.BranchesExec) * 100 / Coverage.Branches,
Coverage.Branches);
OS << format("Taken at least once:%.2f%% of %u\n",
double(Coverage.BranchesTaken) * 100 / Coverage.Branches,
Coverage.Branches);
} else {
OS << "No branches\n";
}
OS << "No calls\n"; // to be consistent with gcov
}
}
// printFuncCoverage - Print per-function coverage info.
void FileInfo::printFuncCoverage(raw_ostream &OS) const {
for (const auto &FC : FuncCoverages) {
const GCOVCoverage &Coverage = FC.second;
OS << "Function '" << Coverage.Name << "'\n";
printCoverage(OS, Coverage);
OS << "\n";
}
}
// printFileCoverage - Print per-file coverage info.
void FileInfo::printFileCoverage(raw_ostream &OS) const {
for (const auto &FC : FileCoverages) {
const std::string &Filename = FC.first;
const GCOVCoverage &Coverage = FC.second;
OS << "File '" << Coverage.Name << "'\n";
printCoverage(OS, Coverage);
if (!Options.NoOutput)
OS << Coverage.Name << ":creating '" << Filename << "'\n";
OS << "\n";
}
}

460
src/plugin/GCOV.h Normal file
View File

@ -0,0 +1,460 @@
//===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This header provides the interface to read and write coverage files that
// use 'gcov' format.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_PROFILEDATA_GCOV_H
#define LLVM_PROFILEDATA_GCOV_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
namespace llvm {
class GCOVFunction;
class GCOVBlock;
class FileInfo;
namespace GCOV {
enum GCOVVersion { V402, V404, V704 };
/// \brief A struct for passing gcov options between functions.
struct Options {
Options(bool A, bool B, bool C, bool F, bool P, bool U, bool L, bool N)
: AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
PreservePaths(P), UncondBranch(U), LongFileNames(L), NoOutput(N) {}
bool AllBlocks;
bool BranchInfo;
bool BranchCount;
bool FuncCoverage;
bool PreservePaths;
bool UncondBranch;
bool LongFileNames;
bool NoOutput;
};
} // end namespace GCOV
/// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
/// read operations.
class GCOVBuffer {
public:
GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
/// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
bool readGCNOFormat() {
StringRef File = Buffer->getBuffer().slice(0, 4);
if (File != "oncg") {
errs() << "Unexpected file type: " << File << ".\n";
return false;
}
Cursor = 4;
return true;
}
/// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
bool readGCDAFormat() {
StringRef File = Buffer->getBuffer().slice(0, 4);
if (File != "adcg") {
errs() << "Unexpected file type: " << File << ".\n";
return false;
}
Cursor = 4;
return true;
}
/// readGCOVVersion - Read GCOV version.
bool readGCOVVersion(GCOV::GCOVVersion &Version) {
StringRef VersionStr = Buffer->getBuffer().slice(Cursor, Cursor + 4);
if (VersionStr == "*204") {
Cursor += 4;
Version = GCOV::V402;
return true;
}
if (VersionStr == "*404") {
Cursor += 4;
Version = GCOV::V404;
return true;
}
if (VersionStr == "*704") {
Cursor += 4;
Version = GCOV::V704;
return true;
}
errs() << "Unexpected version: " << VersionStr << ".\n";
return false;
}
/// readFunctionTag - If cursor points to a function tag then increment the
/// cursor and return true otherwise return false.
bool readFunctionTag() {
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
Tag[3] != '\1') {
return false;
}
Cursor += 4;
return true;
}
/// readBlockTag - If cursor points to a block tag then increment the
/// cursor and return true otherwise return false.
bool readBlockTag() {
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x41' ||
Tag[3] != '\x01') {
return false;
}
Cursor += 4;
return true;
}
/// readEdgeTag - If cursor points to an edge tag then increment the
/// cursor and return true otherwise return false.
bool readEdgeTag() {
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x43' ||
Tag[3] != '\x01') {
return false;
}
Cursor += 4;
return true;
}
/// readLineTag - If cursor points to a line tag then increment the
/// cursor and return true otherwise return false.
bool readLineTag() {
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x45' ||
Tag[3] != '\x01') {
return false;
}
Cursor += 4;
return true;
}
/// readArcTag - If cursor points to an gcda arc tag then increment the
/// cursor and return true otherwise return false.
bool readArcTag() {
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\xa1' ||
Tag[3] != '\1') {
return false;
}
Cursor += 4;
return true;
}
/// readObjectTag - If cursor points to an object summary tag then increment
/// the cursor and return true otherwise return false.
bool readObjectTag() {
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
Tag[3] != '\xa1') {
return false;
}
Cursor += 4;
return true;
}
/// readProgramTag - If cursor points to a program summary tag then increment
/// the cursor and return true otherwise return false.
bool readProgramTag() {
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
Tag[3] != '\xa3') {
return false;
}
Cursor += 4;
return true;
}
bool readInt(uint32_t &Val) {
if (Buffer->getBuffer().size() < Cursor + 4) {
errs() << "Unexpected end of memory buffer: " << Cursor + 4 << ".\n";
return false;
}
StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor + 4);
Cursor += 4;
Val = *(const uint32_t *)(Str.data());
return true;
}
bool readInt64(uint64_t &Val) {
uint32_t Lo, Hi;
if (!readInt(Lo) || !readInt(Hi))
return false;
Val = ((uint64_t)Hi << 32) | Lo;
return true;
}
bool readString(StringRef &Str) {
uint32_t Len = 0;
// Keep reading until we find a non-zero length. This emulates gcov's
// behaviour, which appears to do the same.
while (Len == 0)
if (!readInt(Len))
return false;
Len *= 4;
if (Buffer->getBuffer().size() < Cursor + Len) {
errs() << "Unexpected end of memory buffer: " << Cursor + Len << ".\n";
return false;
}
Str = Buffer->getBuffer().slice(Cursor, Cursor + Len).split('\0').first;
Cursor += Len;
return true;
}
uint64_t getCursor() const { return Cursor; }
void advanceCursor(uint32_t n) { Cursor += n * 4; }
private:
MemoryBuffer *Buffer;
uint64_t Cursor = 0;
};
/// GCOVFile - Collects coverage information for one pair of coverage file
/// (.gcno and .gcda).
class GCOVFile {
public:
GCOVFile() = default;
bool readGCNO(GCOVBuffer &Buffer);
bool readGCDA(GCOVBuffer &Buffer);
uint32_t getChecksum() const { return Checksum; }
void print(raw_ostream &OS) const;
void dump() const;
void collectLineCounts(FileInfo &FI);
private:
bool GCNOInitialized = false;
GCOV::GCOVVersion Version;
uint32_t Checksum = 0;
SmallVector<std::unique_ptr<GCOVFunction>, 16> Functions;
uint32_t RunCount = 0;
uint32_t ProgramCount = 0;
};
/// GCOVEdge - Collects edge information.
struct GCOVEdge {
GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D) {}
GCOVBlock &Src;
GCOVBlock &Dst;
uint64_t Count = 0;
};
/// GCOVFunction - Collects function information.
class GCOVFunction {
public:
using BlockIterator = pointee_iterator<SmallVectorImpl<
std::unique_ptr<GCOVBlock>>::const_iterator>;
GCOVFunction(GCOVFile &P) : Parent(P) {}
bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
StringRef getName() const { return Name; }
StringRef getFilename() const { return Filename; }
size_t getNumBlocks() const { return Blocks.size(); }
uint64_t getEntryCount() const;
uint64_t getExitCount() const;
BlockIterator block_begin() const { return Blocks.begin(); }
BlockIterator block_end() const { return Blocks.end(); }
iterator_range<BlockIterator> blocks() const {
return make_range(block_begin(), block_end());
}
void print(raw_ostream &OS) const;
void dump() const;
void collectLineCounts(FileInfo &FI);
private:
GCOVFile &Parent;
uint32_t Ident = 0;
uint32_t Checksum;
uint32_t LineNumber = 0;
StringRef Name;
StringRef Filename;
SmallVector<std::unique_ptr<GCOVBlock>, 16> Blocks;
SmallVector<std::unique_ptr<GCOVEdge>, 16> Edges;
};
/// GCOVBlock - Collects block information.
class GCOVBlock {
struct EdgeWeight {
EdgeWeight(GCOVBlock *D) : Dst(D) {}
GCOVBlock *Dst;
uint64_t Count = 0;
};
struct SortDstEdgesFunctor {
bool operator()(const GCOVEdge *E1, const GCOVEdge *E2) {
return E1->Dst.Number < E2->Dst.Number;
}
};
public:
using EdgeIterator = SmallVectorImpl<GCOVEdge *>::const_iterator;
GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N) {}
~GCOVBlock();
const GCOVFunction &getParent() const { return Parent; }
void addLine(uint32_t N) { Lines.push_back(N); }
uint32_t getLastLine() const { return Lines.back(); }
void addCount(size_t DstEdgeNo, uint64_t N);
uint64_t getCount() const { return Counter; }
void addSrcEdge(GCOVEdge *Edge) {
assert(&Edge->Dst == this); // up to caller to ensure edge is valid
SrcEdges.push_back(Edge);
}
void addDstEdge(GCOVEdge *Edge) {
assert(&Edge->Src == this); // up to caller to ensure edge is valid
// Check if adding this edge causes list to become unsorted.
if (DstEdges.size() && DstEdges.back()->Dst.Number > Edge->Dst.Number)
DstEdgesAreSorted = false;
DstEdges.push_back(Edge);
}
size_t getNumSrcEdges() const { return SrcEdges.size(); }
size_t getNumDstEdges() const { return DstEdges.size(); }
void sortDstEdges();
EdgeIterator src_begin() const { return SrcEdges.begin(); }
EdgeIterator src_end() const { return SrcEdges.end(); }
iterator_range<EdgeIterator> srcs() const {
return make_range(src_begin(), src_end());
}
EdgeIterator dst_begin() const { return DstEdges.begin(); }
EdgeIterator dst_end() const { return DstEdges.end(); }
iterator_range<EdgeIterator> dsts() const {
return make_range(dst_begin(), dst_end());
}
void print(raw_ostream &OS) const;
void dump() const;
void collectLineCounts(FileInfo &FI);
private:
GCOVFunction &Parent;
uint32_t Number;
uint64_t Counter = 0;
bool DstEdgesAreSorted = true;
SmallVector<GCOVEdge *, 16> SrcEdges;
SmallVector<GCOVEdge *, 16> DstEdges;
SmallVector<uint32_t, 16> Lines;
};
class FileInfo {
// It is unlikely--but possible--for multiple functions to be on the same
// line.
// Therefore this typedef allows LineData.Functions to store multiple
// functions
// per instance. This is rare, however, so optimize for the common case.
using FunctionVector = SmallVector<const GCOVFunction *, 1>;
using FunctionLines = DenseMap<uint32_t, FunctionVector>;
using BlockVector = SmallVector<const GCOVBlock *, 4>;
using BlockLines = DenseMap<uint32_t, BlockVector>;
struct LineData {
LineData() = default;
BlockLines Blocks;
FunctionLines Functions;
uint32_t LastLine = 0;
};
struct GCOVCoverage {
GCOVCoverage(StringRef Name) : Name(Name) {}
StringRef Name;
uint32_t LogicalLines = 0;
uint32_t LinesExec = 0;
uint32_t Branches = 0;
uint32_t BranchesExec = 0;
uint32_t BranchesTaken = 0;
};
public:
FileInfo(const GCOV::Options &Options) : Options(Options) {}
void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
if (Line > LineInfo[Filename].LastLine)
LineInfo[Filename].LastLine = Line;
LineInfo[Filename].Blocks[Line - 1].push_back(Block);
}
void addFunctionLine(StringRef Filename, uint32_t Line,
const GCOVFunction *Function) {
if (Line > LineInfo[Filename].LastLine)
LineInfo[Filename].LastLine = Line;
LineInfo[Filename].Functions[Line - 1].push_back(Function);
}
void setRunCount(uint32_t Runs) { RunCount = Runs; }
void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
void print(raw_ostream &OS, StringRef MainFilename, StringRef GCNOFile,
StringRef GCDAFile);
private:
std::string getCoveragePath(StringRef Filename, StringRef MainFilename);
std::unique_ptr<raw_ostream> openCoveragePath(StringRef CoveragePath);
void printFunctionSummary(raw_ostream &OS, const FunctionVector &Funcs) const;
void printBlockInfo(raw_ostream &OS, const GCOVBlock &Block,
uint32_t LineIndex, uint32_t &BlockNo) const;
void printBranchInfo(raw_ostream &OS, const GCOVBlock &Block,
GCOVCoverage &Coverage, uint32_t &EdgeNo);
void printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo,
uint64_t Count) const;
void printCoverage(raw_ostream &OS, const GCOVCoverage &Coverage) const;
void printFuncCoverage(raw_ostream &OS) const;
void printFileCoverage(raw_ostream &OS) const;
const GCOV::Options &Options;
StringMap<LineData> LineInfo;
uint32_t RunCount = 0;
uint32_t ProgramCount = 0;
using FileCoverageList = SmallVector<std::pair<std::string, GCOVCoverage>, 4>;
using FuncCoverageMap = MapVector<const GCOVFunction *, GCOVCoverage>;
FileCoverageList FileCoverages;
FuncCoverageMap FuncCoverages;
};
} // end namespace llvm
#endif // LLVM_SUPPORT_GCOV_H

View File

@ -0,0 +1,94 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/
#include "iss/plugin/cycle_estimate.h"
#include <iss/arch_if.h>
#include <util/logging.h>
#include <fstream>
iss::plugin::cycle_estimate::cycle_estimate(std::string config_file_name)
: arch_instr(nullptr)
{
if (config_file_name.length() > 0) {
std::ifstream is(config_file_name);
if (is.is_open()) {
try {
is >> root;
} catch (Json::RuntimeError &e) {
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
}
} else {
LOG(ERR) << "Could not open input file " << config_file_name;
}
}
}
iss::plugin::cycle_estimate::~cycle_estimate() {
}
bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if& vm) {
arch_instr = vm.get_arch()->get_instrumentation_if();
if(!arch_instr) return false;
const std::string core_name = arch_instr->core_type_name();
Json::Value &val = root[core_name];
if(!val.isNull() && val.isArray()){
delays.reserve(val.size());
for(auto it:val){
auto name = it["name"];
auto size = it["size"];
auto delay = it["delay"];
if(!name.isString() || !size.isUInt() || !(delay.isUInt() || delay.isArray())) throw std::runtime_error("JSON parse error");
if(delay.isUInt()){
delays.push_back(instr_desc{size.asUInt(), delay.asUInt(), 0});
} else {
delays.push_back(instr_desc{size.asUInt(), delay[0].asUInt(), delay[1].asUInt()});
}
}
} else {
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
}
return true;
}
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const&) {
assert(arch_instr && "No instrumentation interface available but callback executed");
auto entry = delays[instr_info.instr_id];
bool taken = (arch_instr->get_next_pc()-arch_instr->get_pc()) != (entry.size/8);
if (taken && entry.taken > 1)
arch_instr->set_curr_instr_cycles(entry.taken);
else if (entry.not_taken > 1)
arch_instr->set_curr_instr_cycles(entry.not_taken);
}

View File

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2017 - 2023 MINRES Technologies GmbH * Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -32,65 +32,64 @@
* eyck@minres.com - initial API and implementation * eyck@minres.com - initial API and implementation
******************************************************************************/ ******************************************************************************/
#include "instruction_count.h" #include "iss/plugin/instruction_count.h"
#include <iss/instrumentation_if.h> #include "iss/instrumentation_if.h"
#include <yaml-cpp/yaml.h>
#include <fstream>
#include <iss/arch_if.h> #include <iss/arch_if.h>
#include <util/logging.h> #include <util/logging.h>
#include <fstream>
iss::plugin::instruction_count::instruction_count(std::string config_file_name) { iss::plugin::instruction_count::instruction_count(std::string config_file_name) {
if(config_file_name.length() > 0) { if (config_file_name.length() > 0) {
std::ifstream is(config_file_name); std::ifstream is(config_file_name);
if(is.is_open()) { if (is.is_open()) {
try { try {
auto root = YAML::LoadAll(is); is >> root;
if(root.size() != 1) { } catch (Json::RuntimeError &e) {
CPPLOG(ERR) << "Too many rro nodes in YAML file " << config_file_name; LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
}
for(auto p : root[0]) {
auto isa_subset = p.first;
auto instructions = p.second;
for(auto const& instr : instructions) {
instr_delay res;
res.instr_name = instr.first.as<std::string>();
res.size = instr.second["encoding"].as<std::string>().size() - 2; // not counting 0b
auto delay = instr.second["delay"];
if(delay.IsSequence()) {
res.not_taken_delay = delay[0].as<uint64_t>();
res.taken_delay = delay[1].as<uint64_t>();
} else {
res.not_taken_delay = delay.as<uint64_t>();
res.taken_delay = res.not_taken_delay;
}
delays.push_back(std::move(res));
}
}
rep_counts.resize(delays.size());
} catch(YAML::ParserException& e) {
CPPLOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
} }
} else { } else {
CPPLOG(ERR) << "Could not open input file " << config_file_name; LOG(ERR) << "Could not open input file " << config_file_name;
} }
} }
} }
iss::plugin::instruction_count::~instruction_count() { iss::plugin::instruction_count::~instruction_count() {
size_t idx = 0; size_t idx=0;
for(auto it : delays) { for(auto it:delays){
if(rep_counts[idx] > 0 && it.instr_name.find("__" != 0)) if(rep_counts[idx]>0)
CPPLOG(INFO) << it.instr_name << ";" << rep_counts[idx]; LOG(INFO)<<it.instr_name<<";"<<rep_counts[idx];
idx++; idx++;
} }
} }
bool iss::plugin::instruction_count::registration(const char* const version, vm_if& vm) { bool iss::plugin::instruction_count::registration(const char* const version, vm_if& vm) {
auto instr_if = vm.get_arch()->get_instrumentation_if(); auto instr_if = vm.get_arch()->get_instrumentation_if();
if(!instr_if) if(!instr_if) return false;
return false; const std::string core_name = instr_if->core_type_name();
return true; Json::Value &val = root[core_name];
if(!val.isNull() && val.isArray()){
delays.reserve(val.size());
for(auto it:val){
auto name = it["name"];
auto size = it["size"];
auto delay = it["delay"];
if(!name.isString() || !size.isUInt() || !(delay.isUInt() || delay.isArray())) throw std::runtime_error("JSON parse error");
if(delay.isUInt()){
const instr_delay entry{name.asCString(), size.asUInt(), delay.asUInt(), 0};
delays.push_back(entry);
} else {
const instr_delay entry{name.asCString(), size.asUInt(), delay[0].asUInt(), delay[1].asUInt()};
delays.push_back(entry);
}
}
rep_counts.resize(delays.size());
} else {
LOG(ERR)<<"plugin instruction_count: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
}
return true;
} }
void iss::plugin::instruction_count::callback(instr_info_t instr_info) { rep_counts[instr_info.instr_id]++; } void iss::plugin::instruction_count::callback(instr_info_t instr_info, exec_info const&) {
rep_counts[instr_info.instr_id]++;
}

View File

@ -30,37 +30,38 @@
* *
*******************************************************************************/ *******************************************************************************/
// clang-format off // clang-format off
#include <iss/debugger/gdb_session.h> #include "iss/debugger/gdb_session.h"
#include <iss/debugger/encoderdecoder.h> #include "iss/debugger/encoderdecoder.h"
#include <iss/debugger/server.h> #include "iss/debugger/server.h"
#include <iss/debugger/target_adapter_if.h> #include "iss/debugger/target_adapter_if.h"
#include <iss/iss.h> #include "iss/iss.h"
#include <iss/vm_types.h> #include "iss/vm_types.h"
#include "iss_factory.h" #include "sysc/core_complex.h"
#ifndef WIN32 #ifdef CORE_TGC_B
#include <iss/plugin/loader.h> #include "iss/arch/riscv_hart_m_p.h"
#include "iss/arch/tgc_b.h"
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
#endif #endif
#include "sc_core_adapter_if.h" #include "iss/arch/riscv_hart_m_p.h"
#include <iss/arch/tgc_mapper.h> #include "iss/arch/tgc_c.h"
#include <scc/report.h> using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
#include <util/ities.h> #ifdef CORE_TGC_D
#include "iss/arch/riscv_hart_mu_p.h"
#include "iss/arch/tgc_d.h"
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, iss::arch::FEAT_PMP>;
#endif
#include "scc/report.h"
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <array> #include <array>
#include <numeric> // clang-format on
#include <iss/plugin/cycle_estimate.h>
#include <iss/plugin/instruction_count.h>
// clang-format on
#define STR(X) #X #define STR(X) #X
#define CREATE_CORE(CN) \ #define CREATE_CORE(CN) \
if(type == STR(CN)) { \ if (type == STR(CN)) { std::tie(cpu, vm) = create_core<CN ## _plat_type>(backend, gdb_port, hart_id); } else
std::tie(cpu, vm) = create_core<CN##_plat_type>(backend, gdb_port, hart_id); \
} else
#ifdef HAS_SCV #ifdef WITH_SCV
#include <scv.h> #include <scv.h>
#else #else
#include <scv-tr.h> #include <scv-tr.h>
@ -73,12 +74,12 @@ using namespace scv_tr;
#define GET_PROP_VALUE(P) P.getValue() #define GET_PROP_VALUE(P) P.getValue()
#endif #endif
#ifdef _MSC_VER #ifdef _MSC_VER
// not #if defined(_WIN32) || defined(_WIN64) because we have strncasecmp in mingw // not #if defined(_WIN32) || defined(_WIN64) because we have strncasecmp in mingw
#define strncasecmp _strnicmp #define strncasecmp _strnicmp
#define strcasecmp _stricmp #define strcasecmp _stricmp
#endif #endif
namespace sysc { namespace sysc {
namespace tgfs { namespace tgfs {
using namespace std; using namespace std;
@ -88,23 +89,149 @@ using namespace sc_core;
namespace { namespace {
iss::debugger::encoder_decoder encdec; iss::debugger::encoder_decoder encdec;
std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
} // namespace
int cmd_sysc(int argc, char* argv[], debugger::out_func of, debugger::data_func df, debugger::target_adapter_if* tgt_adapter) { std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
if(argc > 1) { }
if(strcasecmp(argv[1], "print_time") == 0) {
template<typename PLAT>
class core_wrapper_t : public PLAT {
public:
using reg_t = typename arch::traits<typename PLAT::core>::reg_t;
using phys_addr_t = typename arch::traits<typename PLAT::core>::phys_addr_t;
using heart_state_t = typename PLAT::hart_state_type;
core_wrapper_t(core_complex *owner)
: owner(owner) { }
uint32_t get_mode() { return this->reg.PRIV; }
inline void set_interrupt_execution(bool v) { this->interrupt_sim = v?1:0; }
inline bool get_interrupt_execution() { return this->interrupt_sim; }
heart_state_t &get_state() { return this->state; }
void notify_phase(iss::arch_if::exec_phase p) override {
if (p == iss::arch_if::ISTART) owner->sync(this->reg.icount);
}
sync_type needed_sync() const override { return PRE_SYNC; }
void disass_output(uint64_t pc, const std::string instr) override {
if (!owner->disass_output(pc, instr)) {
std::stringstream s;
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0')
<< std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:" << this->reg.icount << "]";
SCCDEBUG(owner->name())<<"disass: "
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
<< std::setfill(' ') << std::left << instr << s.str();
}
};
status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) override {
if (addr.access && access_type::DEBUG)
return owner->read_mem_dbg(addr.val, length, data) ? Ok : Err;
else {
return owner->read_mem(addr.val, length, data, addr.access && access_type::FETCH) ? Ok : Err;
}
}
status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data) override {
if (addr.access && access_type::DEBUG)
return owner->write_mem_dbg(addr.val, length, data) ? Ok : Err;
else {
auto res = owner->write_mem(addr.val, length, data) ? Ok : Err;
// clear MTIP on mtimecmp write
if (addr.val == 0x2004000) {
reg_t val;
this->read_csr(arch::mip, val);
if (val & (1ULL << 7)) this->write_csr(arch::mip, val & ~(1ULL << 7));
}
return res;
}
}
status read_csr(unsigned addr, reg_t &val) override {
#ifndef CWR_SYSTEMC
if((addr==arch::time || addr==arch::timeh) && owner->mtime_o.get_interface(0)){
uint64_t time_val;
bool ret = owner->mtime_o->nb_peek(time_val);
if (addr == iss::arch::time) {
val = static_cast<reg_t>(time_val);
} else if (addr == iss::arch::timeh) {
if (sizeof(reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(time_val >> 32);
}
return ret?Ok:Err;
#else
if((addr==arch::time || addr==arch::timeh)){
uint64_t time_val = owner->mtime_i.read();
if (addr == iss::arch::time) {
val = static_cast<reg_t>(time_val);
} else if (addr == iss::arch::timeh) {
if (sizeof(reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(time_val >> 32);
}
return Ok;
#endif
} else {
return PLAT::read_csr(addr, val);
}
}
void wait_until(uint64_t flags) override {
SCCDEBUG(owner->name()) << "Sleeping until interrupt";
do {
sc_core::wait(wfi_evt);
} while (this->reg.pending_trap == 0);
PLAT::wait_until(flags);
}
void local_irq(short id, bool value) {
reg_t mask = 0;
switch (id) {
case 16: // SW
mask = 1 << 3;
break;
case 17: // timer
mask = 1 << 7;
break;
case 18: // external
mask = 1 << 11;
break;
default:
/* do nothing*/
break;
}
if (value) {
this->csr[arch::mip] |= mask;
wfi_evt.notify();
} else
this->csr[arch::mip] &= ~mask;
this->check_interrupt();
if(value)
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
}
private:
core_complex *const owner;
sc_event wfi_evt;
};
int cmd_sysc(int argc, char *argv[], debugger::out_func of, debugger::data_func df,
debugger::target_adapter_if *tgt_adapter) {
if (argc > 1) {
if (strcasecmp(argv[1], "print_time") == 0) {
std::string t = sc_time_stamp().to_string(); std::string t = sc_time_stamp().to_string();
of(t.c_str()); of(t.c_str());
std::array<char, 64> buf; std::array<char, 64> buf;
encdec.enc_string(t.c_str(), buf.data(), 63); encdec.enc_string(t.c_str(), buf.data(), 63);
df(buf.data()); df(buf.data());
return Ok; return Ok;
} else if(strcasecmp(argv[1], "break") == 0) { } else if (strcasecmp(argv[1], "break") == 0) {
sc_time t; sc_time t;
if(argc == 4) { if (argc == 4) {
t = scc::parse_from_string(argv[2], argv[3]); t = scc::parse_from_string(argv[2], argv[3]);
} else if(argc == 3) { } else if (argc == 3) {
t = scc::parse_from_string(argv[2]); t = scc::parse_from_string(argv[2]);
} else } else
return Err; return Err;
@ -121,19 +248,15 @@ int cmd_sysc(int argc, char* argv[], debugger::out_func of, debugger::data_func
} }
using cpu_ptr = std::unique_ptr<iss::arch_if>; using cpu_ptr = std::unique_ptr<iss::arch_if>;
using vm_ptr = std::unique_ptr<iss::vm_if>; using vm_ptr= std::unique_ptr<iss::vm_if>;
class core_wrapper { class core_wrapper {
public: public:
core_wrapper(core_complex* owner) core_wrapper(core_complex *owner) : owner(owner) { }
: owner(owner) {}
void reset(uint64_t addr) { vm->reset(addr); } void reset(uint64_t addr){vm->reset(addr);}
inline void start(bool dump = false) { vm->start(std::numeric_limits<uint64_t>::max(), dump); } inline void start(){vm->start();}
inline std::pair<uint64_t, bool> load_file(std::string const& name) { inline std::pair<uint64_t, bool> load_file(std::string const& name){ return cpu->load_file(name);};
iss::arch_if* cc = cpu->get_arch_if();
return cc->load_file(name);
};
std::function<unsigned(void)> get_mode; std::function<unsigned(void)> get_mode;
std::function<uint64_t(void)> get_state; std::function<uint64_t(void)> get_state;
@ -141,88 +264,85 @@ public:
std::function<void(bool)> set_interrupt_execution; std::function<void(bool)> set_interrupt_execution;
std::function<void(short, bool)> local_irq; std::function<void(short, bool)> local_irq;
void create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id) { template<typename PLAT>
auto& f = sysc::iss_factory::instance(); std::tuple<cpu_ptr, vm_ptr> create_core(std::string const& backend, unsigned gdb_port, uint32_t hart_id){
if(type.size() == 0 || type == "?") { auto* lcpu = new core_wrapper_t<PLAT>(owner);
std::cout << "Available cores: " << util::join(f.get_names(), ", ") << std::endl; lcpu->set_mhartid(hart_id);
sc_core::sc_stop(); get_mode = [lcpu]() { return lcpu->get_mode(); };
} else if(type.find('|') != std::string::npos) { get_state = [lcpu]() { return lcpu->get_state().mstatus.backing.val; };
std::tie(cpu, vm) = f.create(type + "|" + backend); get_interrupt_execution = [lcpu]() { return lcpu->get_interrupt_execution(); };
} else { set_interrupt_execution = [lcpu](bool b) { return lcpu->set_interrupt_execution(b); };
auto base_isa = type.substr(0, 5); local_irq = [lcpu](short s, bool b) { return lcpu->local_irq(s, b); };
if(base_isa == "tgc5d" || base_isa == "tgc5e") { if(backend == "interp")
std::tie(cpu, vm) = f.create(type + "|mu_p_clic_pmp|" + backend, gdb_port, owner); return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(static_cast<typename PLAT::core*>(lcpu), gdb_port)}};
} else { #ifdef WITH_LLVM
std::tie(cpu, vm) = f.create(type + "|m_p|" + backend, gdb_port, owner); if(backend == "llvm")
} return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
} #endif
if(!cpu) { #ifdef WITH_TCC
SCCFATAL() << "Could not create cpu for isa " << type << " and backend " << backend; if(backend == "tcc")
} s return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
if(!vm) { #endif
SCCFATAL() << "Could not create vm for isa " << type << " and backend " << backend; return {nullptr, nullptr};
}
auto* sc_cpu_if = reinterpret_cast<sc_core_adapter_if*>(cpu.get());
sc_cpu_if->set_mhartid(hart_id);
get_mode = [sc_cpu_if]() { return sc_cpu_if->get_mode(); };
get_state = [sc_cpu_if]() { return sc_cpu_if->get_state(); };
get_interrupt_execution = [sc_cpu_if]() { return sc_cpu_if->get_interrupt_execution(); };
set_interrupt_execution = [sc_cpu_if](bool b) { return sc_cpu_if->set_interrupt_execution(b); };
local_irq = [sc_cpu_if](short s, bool b) { return sc_cpu_if->local_irq(s, b); };
auto* srv = debugger::server<debugger::gdb_session>::get();
if(srv)
tgt_adapter = srv->get_target();
if(tgt_adapter)
tgt_adapter->add_custom_command({"sysc",
[this](int argc, char* argv[], debugger::out_func of, debugger::data_func df) -> int {
return cmd_sysc(argc, argv, of, df, tgt_adapter);
},
"SystemC sub-commands: break <time>, print_time"});
} }
core_complex* const owner; void create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id){
CREATE_CORE(tgc_c)
#ifdef CORE_TGC_B
CREATE_CORE(tgc_b)
#endif
#ifdef CORE_TGC_D
CREATE_CORE(tgc_d)
#endif
{
LOG(ERR) << "Illegal argument value for core type: " << type << std::endl;
}
auto *srv = debugger::server<debugger::gdb_session>::get();
if (srv) tgt_adapter = srv->get_target();
if (tgt_adapter)
tgt_adapter->add_custom_command(
{"sysc", [this](int argc, char *argv[], debugger::out_func of,
debugger::data_func df) -> int { return cmd_sysc(argc, argv, of, df, tgt_adapter); },
"SystemC sub-commands: break <time>, print_time"});
}
core_complex * const owner;
vm_ptr vm{nullptr}; vm_ptr vm{nullptr};
sc_cpu_ptr cpu{nullptr}; cpu_ptr cpu{nullptr};
iss::debugger::target_adapter_if* tgt_adapter{nullptr}; iss::debugger::target_adapter_if *tgt_adapter{nullptr};
}; };
struct core_trace { struct core_trace {
//! transaction recording database //! transaction recording database
scv_tr_db* m_db{nullptr}; scv_tr_db *m_db{nullptr};
//! blocking transaction recording stream handle //! blocking transaction recording stream handle
scv_tr_stream* stream_handle{nullptr}; scv_tr_stream *stream_handle{nullptr};
//! transaction generator handle for blocking transactions //! transaction generator handle for blocking transactions
scv_tr_generator<_scv_tr_generator_default_data, _scv_tr_generator_default_data>* instr_tr_handle{nullptr}; scv_tr_generator<_scv_tr_generator_default_data, _scv_tr_generator_default_data> *instr_tr_handle{nullptr};
scv_tr_handle tr_handle; scv_tr_handle tr_handle;
}; };
SC_HAS_PROCESS(core_complex); // NOLINT SC_HAS_PROCESS(core_complex);// NOLINT
#ifndef CWR_SYSTEMC #ifndef CWR_SYSTEMC
core_complex::core_complex(sc_module_name const& name) core_complex::core_complex(sc_module_name const& name)
: sc_module(name) : sc_module(name)
, fetch_lut(tlm_dmi_ext())
, read_lut(tlm_dmi_ext()) , read_lut(tlm_dmi_ext())
, write_lut(tlm_dmi_ext()) { , write_lut(tlm_dmi_ext())
init(); {
init();
} }
#endif #endif
void core_complex::init() { void core_complex::init(){
trc = new core_trace(); trc=new core_trace();
ibus.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void { initiator.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void {
auto lut_entry = fetch_lut.getEntry(start);
if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) {
fetch_lut.removeEntry(lut_entry);
}
});
dbus.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void {
auto lut_entry = read_lut.getEntry(start); auto lut_entry = read_lut.getEntry(start);
if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) { if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) {
read_lut.removeEntry(lut_entry); read_lut.removeEntry(lut_entry);
} }
lut_entry = write_lut.getEntry(start); lut_entry = write_lut.getEntry(start);
if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) { if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) {
write_lut.removeEntry(lut_entry); write_lut.removeEntry(lut_entry);
} }
}); });
@ -234,91 +354,54 @@ void core_complex::init() {
sensitive << sw_irq_i; sensitive << sw_irq_i;
SC_METHOD(timer_irq_cb); SC_METHOD(timer_irq_cb);
sensitive << timer_irq_i; sensitive << timer_irq_i;
SC_METHOD(ext_irq_cb); SC_METHOD(global_irq_cb);
sensitive << ext_irq_i; sensitive << global_irq_i;
SC_METHOD(local_irq_cb); trc->m_db=scv_tr_db::get_default_db();
for(auto pin : local_irq_i)
sensitive << pin;
trc->m_db = scv_tr_db::get_default_db();
SC_METHOD(forward); SC_METHOD(forward);
#ifndef CWR_SYSTEMC #ifndef CWR_SYSTEMC
sensitive << clk_i; sensitive<<clk_i;
#else #else
sensitive << curr_clk; sensitive<<curr_clk;
t2t.reset(new scc::tick2time{"t2t"}); t2t.reset(new scc::tick2time{"t2t"});
t2t->clk_i(clk_i); t2t->clk_i(clk_i);
t2t->clk_o(curr_clk); t2t->clk_o(curr_clk);
#endif #endif
} }
core_complex::~core_complex() { core_complex::~core_complex(){
delete cpu; delete cpu;
delete trc; delete trc;
for(auto* p : plugin_list)
delete p;
} }
void core_complex::trace(sc_trace_file* trf) const {} void core_complex::trace(sc_trace_file *trf) const {}
void core_complex::before_end_of_elaboration() { void core_complex::before_end_of_elaboration() {
SCCDEBUG(SCMOD) << "instantiating iss::arch::tgf with " << GET_PROP_VALUE(backend) << " backend"; SCCDEBUG(SCMOD)<<"instantiating iss::arch::tgf with "<<GET_PROP_VALUE(backend)<<" backend";
// cpu = scc::make_unique<core_wrapper>(this); // cpu = scc::make_unique<core_wrapper>(this);
cpu = new core_wrapper(this); cpu = new core_wrapper(this);
cpu->create_cpu(GET_PROP_VALUE(core_type), GET_PROP_VALUE(backend), GET_PROP_VALUE(gdb_server_port), GET_PROP_VALUE(mhartid)); cpu->create_cpu(GET_PROP_VALUE(core_type), GET_PROP_VALUE(backend), GET_PROP_VALUE(gdb_server_port), GET_PROP_VALUE(mhartid));
sc_assert(cpu->vm != nullptr); sc_assert(cpu->vm!=nullptr);
cpu->vm->setDisassEnabled(GET_PROP_VALUE(enable_disass) || trc->m_db != nullptr); cpu->vm->setDisassEnabled(GET_PROP_VALUE(enable_disass) || trc->m_db != nullptr);
if(GET_PROP_VALUE(plugins).length()) {
auto p = util::split(GET_PROP_VALUE(plugins), ';');
for(std::string const& opt_val : p) {
std::string plugin_name = opt_val;
std::string filename{"cycles.txt"};
std::size_t found = opt_val.find('=');
if(found != std::string::npos) {
plugin_name = opt_val.substr(0, found);
filename = opt_val.substr(found + 1, opt_val.size());
}
if(plugin_name == "ic") {
auto* plugin = new iss::plugin::instruction_count(filename);
cpu->vm->register_plugin(*plugin);
plugin_list.push_back(plugin);
} else if(plugin_name == "ce") {
auto* plugin = new iss::plugin::cycle_estimate(filename);
cpu->vm->register_plugin(*plugin);
plugin_list.push_back(plugin);
} else {
#ifndef WIN32
std::array<char const*, 1> a{{filename.c_str()}};
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
if(plugin) {
cpu->vm->register_plugin(*plugin);
plugin_list.push_back(plugin);
} else
#endif
SCCERR(SCMOD) << "Unknown plugin '" << plugin_name << "' or plugin not found";
}
}
}
} }
void core_complex::start_of_simulation() { void core_complex::start_of_simulation() {
// quantum_keeper.reset(); quantum_keeper.reset();
if(GET_PROP_VALUE(elf_file).size() > 0) { if (GET_PROP_VALUE(elf_file).size() > 0) {
istringstream is(GET_PROP_VALUE(elf_file)); istringstream is(GET_PROP_VALUE(elf_file));
string s; string s;
while(getline(is, s, ',')) { while (getline(is, s, ',')) {
std::pair<uint64_t, bool> start_addr = cpu->load_file(s); std::pair<uint64_t, bool> start_addr = cpu->load_file(s);
#ifndef CWR_SYSTEMC #ifndef CWR_SYSTEMC
if(reset_address.is_default_value() && start_addr.second == true) if (reset_address.is_default_value() && start_addr.second == true)
reset_address.set_value(start_addr.first); reset_address.set_value(start_addr.first);
#else #else
if(start_addr.second == true) if (start_addr.second == true)
reset_address = start_addr.first; reset_address=start_addr.first;
#endif #endif
} }
} }
if(trc->m_db != nullptr && trc->stream_handle == nullptr) { if (trc->m_db != nullptr && trc->stream_handle == nullptr) {
string basename(this->name()); string basename(this->name());
trc->stream_handle = new scv_tr_stream((basename + ".instr").c_str(), "TRANSACTOR", trc->m_db); trc->stream_handle = new scv_tr_stream((basename + ".instr").c_str(), "TRANSACTOR", trc->m_db);
trc->instr_tr_handle = new scv_tr_generator<>("execute", *trc->stream_handle); trc->instr_tr_handle = new scv_tr_generator<>("execute", *trc->stream_handle);
@ -326,10 +409,8 @@ void core_complex::start_of_simulation() {
} }
bool core_complex::disass_output(uint64_t pc, const std::string instr_str) { bool core_complex::disass_output(uint64_t pc, const std::string instr_str) {
if(trc->m_db == nullptr) if (trc->m_db == nullptr) return false;
return false; if (trc->tr_handle.is_active()) trc->tr_handle.end_transaction();
if(trc->tr_handle.is_active())
trc->tr_handle.end_transaction();
trc->tr_handle = trc->instr_tr_handle->begin_transaction(); trc->tr_handle = trc->instr_tr_handle->begin_transaction();
trc->tr_handle.record_attribute("PC", pc); trc->tr_handle.record_attribute("PC", pc);
trc->tr_handle.record_attribute("INSTR", instr_str); trc->tr_handle.record_attribute("INSTR", instr_str);
@ -341,120 +422,96 @@ bool core_complex::disass_output(uint64_t pc, const std::string instr_str) {
void core_complex::forward() { void core_complex::forward() {
#ifndef CWR_SYSTEMC #ifndef CWR_SYSTEMC
set_clock_period(clk_i.read()); set_clock_period(clk_i.read());
#else #else
set_clock_period(curr_clk.read()); set_clock_period(curr_clk.read());
#endif #endif
} }
void core_complex::set_clock_period(sc_core::sc_time period) { void core_complex::set_clock_period(sc_core::sc_time period) {
curr_clk = period; curr_clk = period;
if(period == SC_ZERO_TIME) if (period == SC_ZERO_TIME) cpu->set_interrupt_execution(true);
cpu->set_interrupt_execution(true);
} }
void core_complex::rst_cb() { void core_complex::rst_cb() {
if(rst_i.read()) if (rst_i.read()) cpu->set_interrupt_execution(true);
cpu->set_interrupt_execution(true);
} }
void core_complex::sw_irq_cb() { cpu->local_irq(3, sw_irq_i.read()); } void core_complex::sw_irq_cb() { cpu->local_irq(16, sw_irq_i.read()); }
void core_complex::timer_irq_cb() { cpu->local_irq(7, timer_irq_i.read()); } void core_complex::timer_irq_cb() { cpu->local_irq(17, timer_irq_i.read()); }
void core_complex::ext_irq_cb() { cpu->local_irq(11, ext_irq_i.read()); } void core_complex::global_irq_cb() { cpu->local_irq(18, global_irq_i.read()); }
void core_complex::local_irq_cb() {
for(auto i = 0U; i < local_irq_i.size(); ++i) {
if(local_irq_i[i].event()) {
cpu->local_irq(16 + i, local_irq_i[i].read());
}
}
}
void core_complex::run() { void core_complex::run() {
wait(SC_ZERO_TIME); // separate from elaboration phase wait(SC_ZERO_TIME); // separate from elaboration phase
do { do {
wait(SC_ZERO_TIME); if (rst_i.read()) {
if(rst_i.read()) {
cpu->reset(GET_PROP_VALUE(reset_address)); cpu->reset(GET_PROP_VALUE(reset_address));
wait(rst_i.negedge_event()); wait(rst_i.negedge_event());
} }
while(curr_clk.read() == SC_ZERO_TIME) { while (curr_clk.read() == SC_ZERO_TIME) {
wait(curr_clk.value_changed_event()); wait(curr_clk.value_changed_event());
} }
quantum_keeper.reset();
cpu->set_interrupt_execution(false); cpu->set_interrupt_execution(false);
cpu->start(dump_ir); cpu->start();
} while(cpu->get_interrupt_execution()); } while (cpu->get_interrupt_execution());
sc_stop(); sc_stop();
} }
bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t* const data, bool is_fetch) { bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data, bool is_fetch) {
auto& dmi_lut = is_fetch ? fetch_lut : read_lut; auto lut_entry = read_lut.getEntry(addr);
auto lut_entry = dmi_lut.getEntry(addr); if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE &&
if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && addr + length <= lut_entry.get_end_address() + 1) { addr + length <= lut_entry.get_end_address() + 1) {
auto offset = addr - lut_entry.get_start_address(); auto offset = addr - lut_entry.get_start_address();
std::copy(lut_entry.get_dmi_ptr() + offset, lut_entry.get_dmi_ptr() + offset + length, data); std::copy(lut_entry.get_dmi_ptr() + offset, lut_entry.get_dmi_ptr() + offset + length, data);
if(is_fetch) quantum_keeper.inc(lut_entry.get_read_latency());
ibus_inc += lut_entry.get_read_latency() / curr_clk;
else
dbus_inc += lut_entry.get_read_latency() / curr_clk;
return true; return true;
} else { } else {
auto& sckt = is_fetch ? ibus : dbus;
tlm::tlm_generic_payload gp; tlm::tlm_generic_payload gp;
gp.set_command(tlm::TLM_READ_COMMAND); gp.set_command(tlm::TLM_READ_COMMAND);
gp.set_address(addr); gp.set_address(addr);
gp.set_data_ptr(data); gp.set_data_ptr(data);
gp.set_data_length(length); gp.set_data_length(length);
gp.set_streaming_width(length); gp.set_streaming_width(length);
sc_time delay = quantum_keeper.get_local_time(); sc_time delay=quantum_keeper.get_local_time();
if(trc->m_db != nullptr && trc->tr_handle.is_valid()) { if (trc->m_db != nullptr && trc->tr_handle.is_valid()) {
if(is_fetch && trc->tr_handle.is_active()) { if (is_fetch && trc->tr_handle.is_active()) {
trc->tr_handle.end_transaction(); trc->tr_handle.end_transaction();
} }
auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this); auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this);
gp.set_extension(preExt); gp.set_extension(preExt);
} }
auto pre_delay = delay; initiator->b_transport(gp, delay);
dbus->b_transport(gp, delay); SCCTRACE(this->name()) << "read_mem(0x" << std::hex << addr << ") : " << data;
if(pre_delay > delay) { if (gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
quantum_keeper.reset();
} else {
auto incr = (delay - quantum_keeper.get_local_time()) / curr_clk;
if(is_fetch)
ibus_inc += incr;
else
dbus_inc += incr;
}
SCCTRACE(this->name()) << "[local time: " << delay << "]: finish read_mem(0x" << std::hex << addr << ") : 0x"
<< (length == 4 ? *(uint32_t*)data
: length == 2 ? *(uint16_t*)data
: (unsigned)*data);
if(gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
return false; return false;
} }
if(gp.is_dmi_allowed() && !GET_PROP_VALUE(disable_dmi)) { if (gp.is_dmi_allowed()) {
gp.set_command(tlm::TLM_READ_COMMAND); gp.set_command(tlm::TLM_READ_COMMAND);
gp.set_address(addr); gp.set_address(addr);
tlm_dmi_ext dmi_data; tlm_dmi_ext dmi_data;
if(sckt->get_direct_mem_ptr(gp, dmi_data)) { if (initiator->get_direct_mem_ptr(gp, dmi_data)) {
if(dmi_data.is_read_allowed()) if (dmi_data.is_read_allowed())
dmi_lut.addEntry(dmi_data, dmi_data.get_start_address(), dmi_data.get_end_address() - dmi_data.get_start_address() + 1); read_lut.addEntry(dmi_data, dmi_data.get_start_address(),
dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
if (dmi_data.is_write_allowed())
write_lut.addEntry(dmi_data, dmi_data.get_start_address(),
dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
} }
} }
return true; return true;
} }
} }
bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t* const data) { bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t *const data) {
auto lut_entry = write_lut.getEntry(addr); auto lut_entry = write_lut.getEntry(addr);
if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && addr + length <= lut_entry.get_end_address() + 1) { if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE &&
addr + length <= lut_entry.get_end_address() + 1) {
auto offset = addr - lut_entry.get_start_address(); auto offset = addr - lut_entry.get_start_address();
std::copy(data, data + length, lut_entry.get_dmi_ptr() + offset); std::copy(data, data + length, lut_entry.get_dmi_ptr() + offset);
dbus_inc += lut_entry.get_write_latency() / curr_clk; quantum_keeper.inc(lut_entry.get_read_latency());
return true; return true;
} else { } else {
write_buf.resize(length); write_buf.resize(length);
@ -465,30 +522,26 @@ bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t* cons
gp.set_data_ptr(write_buf.data()); gp.set_data_ptr(write_buf.data());
gp.set_data_length(length); gp.set_data_length(length);
gp.set_streaming_width(length); gp.set_streaming_width(length);
sc_time delay = quantum_keeper.get_local_time(); sc_time delay=quantum_keeper.get_local_time();
if(trc->m_db != nullptr && trc->tr_handle.is_valid()) { if (trc->m_db != nullptr && trc->tr_handle.is_valid()) {
auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this); auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this);
gp.set_extension(preExt); gp.set_extension(preExt);
} }
auto pre_delay = delay; initiator->b_transport(gp, delay);
dbus->b_transport(gp, delay); quantum_keeper.set(delay);
if(pre_delay > delay) SCCTRACE() << "write_mem(0x" << std::hex << addr << ") : " << data;
quantum_keeper.reset(); if (gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
else
dbus_inc += (delay - quantum_keeper.get_local_time()) / curr_clk;
SCCTRACE() << "[local time: " << delay << "]: finish write_mem(0x" << std::hex << addr << ") : 0x"
<< (length == 4 ? *(uint32_t*)data
: length == 2 ? *(uint16_t*)data
: (unsigned)*data);
if(gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
return false; return false;
} }
if(gp.is_dmi_allowed() && !GET_PROP_VALUE(disable_dmi)) { if (gp.is_dmi_allowed()) {
gp.set_command(tlm::TLM_READ_COMMAND); gp.set_command(tlm::TLM_READ_COMMAND);
gp.set_address(addr); gp.set_address(addr);
tlm_dmi_ext dmi_data; tlm_dmi_ext dmi_data;
if(dbus->get_direct_mem_ptr(gp, dmi_data)) { if (initiator->get_direct_mem_ptr(gp, dmi_data)) {
if(dmi_data.is_write_allowed()) if (dmi_data.is_read_allowed())
read_lut.addEntry(dmi_data, dmi_data.get_start_address(),
dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
if (dmi_data.is_write_allowed())
write_lut.addEntry(dmi_data, dmi_data.get_start_address(), write_lut.addEntry(dmi_data, dmi_data.get_start_address(),
dmi_data.get_end_address() - dmi_data.get_start_address() + 1); dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
} }
@ -497,26 +550,44 @@ bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t* cons
} }
} }
bool core_complex::read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data) { bool core_complex::read_mem_dbg(uint64_t addr, unsigned length, uint8_t *const data) {
tlm::tlm_generic_payload gp; auto lut_entry = read_lut.getEntry(addr);
gp.set_command(tlm::TLM_READ_COMMAND); if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE &&
gp.set_address(addr); addr + length <= lut_entry.get_end_address() + 1) {
gp.set_data_ptr(data); auto offset = addr - lut_entry.get_start_address();
gp.set_data_length(length); std::copy(lut_entry.get_dmi_ptr() + offset, lut_entry.get_dmi_ptr() + offset + length, data);
gp.set_streaming_width(length); quantum_keeper.inc(lut_entry.get_read_latency());
return dbus->transport_dbg(gp) == length; return true;
} else {
tlm::tlm_generic_payload gp;
gp.set_command(tlm::TLM_READ_COMMAND);
gp.set_address(addr);
gp.set_data_ptr(data);
gp.set_data_length(length);
gp.set_streaming_width(length);
return initiator->transport_dbg(gp) == length;
}
} }
bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data) { bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t *const data) {
write_buf.resize(length); auto lut_entry = write_lut.getEntry(addr);
std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE &&
tlm::tlm_generic_payload gp; addr + length <= lut_entry.get_end_address() + 1) {
gp.set_command(tlm::TLM_WRITE_COMMAND); auto offset = addr - lut_entry.get_start_address();
gp.set_address(addr); std::copy(data, data + length, lut_entry.get_dmi_ptr() + offset);
gp.set_data_ptr(write_buf.data()); quantum_keeper.inc(lut_entry.get_read_latency());
gp.set_data_length(length); return true;
gp.set_streaming_width(length); } else {
return dbus->transport_dbg(gp) == length; write_buf.resize(length);
std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity
tlm::tlm_generic_payload gp;
gp.set_command(tlm::TLM_WRITE_COMMAND);
gp.set_address(addr);
gp.set_data_ptr(write_buf.data());
gp.set_data_length(length);
gp.set_streaming_width(length);
return initiator->transport_dbg(gp) == length;
}
} }
} /* namespace tgfs */ } /* namespace SiFive */
} /* namespace sysc */ } /* namespace sysc */

View File

@ -1,90 +0,0 @@
/*******************************************************************************
* Copyright (C) 2021 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
#ifndef _ISS_FACTORY_H_
#define _ISS_FACTORY_H_
#include "sc_core_adapter_if.h"
#include <algorithm>
#include <functional>
#include <iss/iss.h>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
namespace sysc {
using sc_cpu_ptr = std::unique_ptr<sc_core_adapter_if>;
using vm_ptr = std::unique_ptr<iss::vm_if>;
class iss_factory {
public:
using base_t = std::tuple<sc_cpu_ptr, vm_ptr>;
using create_fn = std::function<base_t(unsigned, void*)>;
using registry_t = std::unordered_map<std::string, create_fn>;
iss_factory() = default;
iss_factory(const iss_factory&) = delete;
iss_factory& operator=(const iss_factory&) = delete;
static iss_factory& instance() {
static iss_factory bf;
return bf;
}
bool register_creator(const std::string& className, create_fn const& fn) {
registry[className] = fn;
return true;
}
base_t create(std::string const& className, unsigned gdb_port = 0, void* init_data = nullptr) const {
registry_t::const_iterator regEntry = registry.find(className);
if(regEntry != registry.end())
return regEntry->second(gdb_port, init_data);
return {nullptr, nullptr};
}
std::vector<std::string> get_names() {
std::vector<std::string> keys{registry.size()};
std::transform(std::begin(registry), std::end(registry), std::begin(keys),
[](std::pair<std::string, create_fn> const& p) { return p.first; });
return keys;
}
private:
registry_t registry;
};
} // namespace sysc
#endif /* _ISS_FACTORY_H_ */

View File

@ -1,110 +0,0 @@
/*******************************************************************************
* Copyright (C) 2023 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
// clang-format off
#include "iss_factory.h"
#include <iss/arch/tgc5c.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h>
#include "sc_core_adapter.h"
#include "core_complex.h"
#include <array>
// clang-format on
namespace iss {
namespace interp {
using namespace sysc;
volatile std::array<bool, 2> tgc_init = {
iss_factory::instance().register_creator("tgc5c|m_p|interp",
[](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
}),
iss_factory::instance().register_creator("tgc5c|mu_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
})};
} // namespace interp
#if defined(WITH_LLVM)
namespace llvm {
using namespace sysc;
volatile std::array<bool, 2> tgc_init = {
iss_factory::instance().register_creator("tgc5c|m_p|llvm",
[](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
}),
iss_factory::instance().register_creator("tgc5c|mu_p|llvm", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
})};
} // namespace llvm
#endif
#if defined(WITH_TCC)
namespace tcc {
using namespace sysc;
volatile std::array<bool, 2> tgc_init = {
iss_factory::instance().register_creator("tgc5c|m_p|tcc",
[](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
}),
iss_factory::instance().register_creator("tgc5c|mu_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
})};
} // namespace tcc
#endif
#if defined(WITH_ASMJIT)
namespace asmjit {
using namespace sysc;
volatile std::array<bool, 2> tgc_init = {
iss_factory::instance().register_creator("tgc5c|m_p|asmjit",
[](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
}),
iss_factory::instance().register_creator("tgc5c|mu_p|asmjit", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc);
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
})};
} // namespace asmjit
#endif
} // namespace iss

View File

@ -1,187 +0,0 @@
/*
* sc_core_adapter.h
*
* Created on: Jul 5, 2023
* Author: eyck
*/
#ifndef _SYSC_SC_CORE_ADAPTER_H_
#define _SYSC_SC_CORE_ADAPTER_H_
#include "sc_core_adapter_if.h"
#include <iostream>
#include <iss/iss.h>
#include <iss/vm_types.h>
#include <scc/report.h>
#include <util/ities.h>
namespace sysc {
template <typename PLAT> class sc_core_adapter : public PLAT, public sc_core_adapter_if {
public:
using reg_t = typename iss::arch::traits<typename PLAT::core>::reg_t;
using phys_addr_t = typename iss::arch::traits<typename PLAT::core>::phys_addr_t;
using heart_state_t = typename PLAT::hart_state_type;
sc_core_adapter(sysc::tgfs::core_complex* owner)
: owner(owner) {}
iss::arch_if* get_arch_if() override { return this; }
void set_mhartid(unsigned id) override { PLAT::set_mhartid(id); }
uint32_t get_mode() override { return this->reg.PRIV; }
void set_interrupt_execution(bool v) override { this->interrupt_sim = v ? 1 : 0; }
bool get_interrupt_execution() override { return this->interrupt_sim; }
uint64_t get_state() override { return this->state.mstatus.backing.val; }
void notify_phase(iss::arch_if::exec_phase p) override {
if(p == iss::arch_if::ISTART && !first) {
auto cycle_incr = owner->get_last_bus_cycles();
if(cycle_incr > 1)
this->instr_if.update_last_instr_cycles(cycle_incr);
owner->sync(this->instr_if.get_total_cycles());
}
first = false;
}
iss::sync_type needed_sync() const override { return iss::PRE_SYNC; }
void disass_output(uint64_t pc, const std::string instr) override {
static constexpr std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
if(!owner->disass_output(pc, instr)) {
std::stringstream s;
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0') << std::setw(sizeof(reg_t) * 2)
<< (reg_t)this->state.mstatus << std::dec << ";c:" << this->reg.icount + this->cycle_offset << "]";
SCCDEBUG(owner->name()) << "disass: "
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
<< std::setfill(' ') << std::left << instr << s.str();
}
};
iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t* const data) override {
if(addr.access && iss::access_type::DEBUG)
return owner->read_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err;
else {
return owner->read_mem(addr.val, length, data, is_fetch(addr.access)) ? iss::Ok : iss::Err;
}
}
iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t* const data) override {
if(addr.access && iss::access_type::DEBUG)
return owner->write_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err;
else {
auto tohost_upper = (sizeof(reg_t) == 4 && addr.val == (this->tohost + 4)) || (sizeof(reg_t) == 8 && addr.val == this->tohost);
auto tohost_lower = (sizeof(reg_t) == 4 && addr.val == this->tohost) || (sizeof(reg_t) == 64 && addr.val == this->tohost);
if(tohost_lower || tohost_upper) {
if(tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
switch(hostvar >> 48) {
case 0:
if(hostvar != 0x1) {
SCCINFO(owner->name())
<< "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar << "), stopping simulation";
} else {
SCCINFO(owner->name())
<< "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar << "), stopping simulation";
}
this->reg.trap_state = std::numeric_limits<uint32_t>::max();
this->interrupt_sim = hostvar;
#ifndef WITH_TCC
throw(iss::simulation_stopped(hostvar));
#endif
break;
default:
break;
}
} else if(tohost_lower)
to_host_wr_cnt++;
return iss::Ok;
} else {
auto res = owner->write_mem(addr.val, length, data) ? iss::Ok : iss::Err;
// clear MTIP on mtimecmp write
if(addr.val == 0x2004000) {
reg_t val;
this->read_csr(iss::arch::mip, val);
if(val & (1ULL << 7))
this->write_csr(iss::arch::mip, val & ~(1ULL << 7));
}
return res;
}
}
}
iss::status read_csr(unsigned addr, reg_t& val) override {
#ifndef CWR_SYSTEMC
if((addr == iss::arch::time || addr == iss::arch::timeh) && owner->mtime_o.get_interface(0)) {
uint64_t time_val;
bool ret = owner->mtime_o->nb_peek(time_val);
if(addr == iss::arch::time) {
val = static_cast<reg_t>(time_val);
} else if(addr == iss::arch::timeh) {
if(sizeof(reg_t) != 4)
return iss::Err;
val = static_cast<reg_t>(time_val >> 32);
}
return ret ? iss::Ok : iss::Err;
#else
if((addr == iss::arch::time || addr == iss::arch::timeh)) {
uint64_t time_val = owner->mtime_i.read();
if(addr == iss::arch::time) {
val = static_cast<reg_t>(time_val);
} else if(addr == iss::arch::timeh) {
if(sizeof(reg_t) != 4)
return iss::Err;
val = static_cast<reg_t>(time_val >> 32);
}
return iss::Ok;
#endif
} else {
return PLAT::read_csr(addr, val);
}
}
void wait_until(uint64_t flags) override {
SCCDEBUG(owner->name()) << "Sleeping until interrupt";
while(this->reg.pending_trap == 0 && (this->csr[iss::arch::mip] & this->csr[iss::arch::mie]) == 0) {
sc_core::wait(wfi_evt);
}
PLAT::wait_until(flags);
}
void local_irq(short id, bool value) override {
reg_t mask = 0;
switch(id) {
case 3: // SW
mask = 1 << 3;
break;
case 7: // timer
mask = 1 << 7;
break;
case 11: // external
mask = 1 << 11;
break;
default:
if(id > 15)
mask = 1 << id;
break;
}
if(value) {
this->csr[iss::arch::mip] |= mask;
wfi_evt.notify();
} else
this->csr[iss::arch::mip] &= ~mask;
this->check_interrupt();
if(value)
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
}
private:
sysc::tgfs::core_complex* const owner;
sc_core::sc_event wfi_evt;
uint64_t hostvar{std::numeric_limits<uint64_t>::max()};
unsigned to_host_wr_cnt = 0;
bool first{true};
};
} // namespace sysc
#endif /* _SYSC_SC_CORE_ADAPTER_H_ */

View File

@ -1,30 +0,0 @@
/*
* sc_core_adapter.h
*
* Created on: Jul 5, 2023
* Author: eyck
*/
#ifndef _SYSC_SC_CORE_ADAPTER_IF_H_
#define _SYSC_SC_CORE_ADAPTER_IF_H_
#include "core_complex.h"
#include <iostream>
#include <iss/iss.h>
#include <iss/vm_types.h>
#include <scc/report.h>
#include <util/ities.h>
namespace sysc {
struct sc_core_adapter_if {
virtual iss::arch_if* get_arch_if() = 0;
virtual void set_mhartid(unsigned) = 0;
virtual uint32_t get_mode() = 0;
virtual uint64_t get_state() = 0;
virtual bool get_interrupt_execution() = 0;
virtual void set_interrupt_execution(bool v) = 0;
virtual void local_irq(short id, bool value) = 0;
virtual ~sc_core_adapter_if() = default;
};
} // namespace sysc
#endif /* _SYSC_SC_CORE_ADAPTER_IF_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -35,90 +35,97 @@
#include "fp_functions.h" #include "fp_functions.h"
extern "C" { extern "C" {
#include <softfloat.h>
#include "internals.h" #include "internals.h"
#include "specialize.h" #include "specialize.h"
#include <softfloat.h>
} }
#include <limits> #include <limits>
using this_t = uint8_t*; using this_t = uint8_t *;
const uint8_t rmm_map[] = { const uint8_t rmm_map[] = {
softfloat_round_near_even /*RNE*/, softfloat_round_minMag /*RTZ*/, softfloat_round_min /*RDN*/, softfloat_round_max /*RUP?*/, softfloat_round_near_even /*RNE*/,
softfloat_round_near_maxMag /*RMM*/, softfloat_round_max /*RTZ*/, softfloat_round_max /*RTZ*/, softfloat_round_max /*RTZ*/, softfloat_round_minMag/*RTZ*/,
softfloat_round_min/*RDN*/,
softfloat_round_max/*RUP?*/,
softfloat_round_near_maxMag /*RMM*/,
softfloat_round_max/*RTZ*/,
softfloat_round_max/*RTZ*/,
softfloat_round_max/*RTZ*/,
}; };
const uint32_t quiet_nan32 = 0x7fC00000; const uint32_t quiet_nan32=0x7fC00000;
extern "C" { extern "C" {
uint32_t fget_flags() { return softfloat_exceptionFlags & 0x1f; } uint32_t fget_flags(){
return softfloat_exceptionFlags&0x1f;
}
uint32_t fadd_s(uint32_t v1, uint32_t v2, uint8_t mode) { uint32_t fadd_s(uint32_t v1, uint32_t v2, uint8_t mode) {
float32_t v1f{v1}, v2f{v2}; float32_t v1f{v1},v2f{v2};
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float32_t r = f32_add(v1f, v2f); float32_t r =f32_add(v1f, v2f);
return r.v; return r.v;
} }
uint32_t fsub_s(uint32_t v1, uint32_t v2, uint8_t mode) { uint32_t fsub_s(uint32_t v1, uint32_t v2, uint8_t mode) {
float32_t v1f{v1}, v2f{v2}; float32_t v1f{v1},v2f{v2};
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float32_t r = f32_sub(v1f, v2f); float32_t r=f32_sub(v1f, v2f);
return r.v; return r.v;
} }
uint32_t fmul_s(uint32_t v1, uint32_t v2, uint8_t mode) { uint32_t fmul_s(uint32_t v1, uint32_t v2, uint8_t mode) {
float32_t v1f{v1}, v2f{v2}; float32_t v1f{v1},v2f{v2};
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float32_t r = f32_mul(v1f, v2f); float32_t r=f32_mul(v1f, v2f);
return r.v; return r.v;
} }
uint32_t fdiv_s(uint32_t v1, uint32_t v2, uint8_t mode) { uint32_t fdiv_s(uint32_t v1, uint32_t v2, uint8_t mode) {
float32_t v1f{v1}, v2f{v2}; float32_t v1f{v1},v2f{v2};
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float32_t r = f32_div(v1f, v2f); float32_t r=f32_div(v1f, v2f);
return r.v; return r.v;
} }
uint32_t fsqrt_s(uint32_t v1, uint8_t mode) { uint32_t fsqrt_s(uint32_t v1, uint8_t mode) {
float32_t v1f{v1}; float32_t v1f{v1};
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float32_t r = f32_sqrt(v1f); float32_t r=f32_sqrt(v1f);
return r.v; return r.v;
} }
uint32_t fcmp_s(uint32_t v1, uint32_t v2, uint32_t op) { uint32_t fcmp_s(uint32_t v1, uint32_t v2, uint32_t op) {
float32_t v1f{v1}, v2f{v2}; float32_t v1f{v1},v2f{v2};
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
bool nan = (v1 & defaultNaNF32UI) == quiet_nan32 || (v2 & defaultNaNF32UI) == quiet_nan32; bool nan = (v1&defaultNaNF32UI)==quiet_nan32 || (v2&defaultNaNF32UI)==quiet_nan32;
bool snan = softfloat_isSigNaNF32UI(v1) || softfloat_isSigNaNF32UI(v2); bool snan = softfloat_isSigNaNF32UI(v1) || softfloat_isSigNaNF32UI(v2);
switch(op) { switch(op){
case 0: case 0:
if(nan | snan) { if(nan | snan){
if(snan) if(snan) softfloat_raiseFlags(softfloat_flag_invalid);
softfloat_raiseFlags(softfloat_flag_invalid);
return 0; return 0;
} else } else
return f32_eq(v1f, v2f) ? 1 : 0; return f32_eq(v1f,v2f )?1:0;
case 1: case 1:
if(nan | snan) { if(nan | snan){
softfloat_raiseFlags(softfloat_flag_invalid); softfloat_raiseFlags(softfloat_flag_invalid);
return 0; return 0;
} else } else
return f32_le(v1f, v2f) ? 1 : 0; return f32_le(v1f,v2f )?1:0;
case 2: case 2:
if(nan | snan) { if(nan | snan){
softfloat_raiseFlags(softfloat_flag_invalid); softfloat_raiseFlags(softfloat_flag_invalid);
return 0; return 0;
} else } else
return f32_lt(v1f, v2f) ? 1 : 0; return f32_lt(v1f,v2f )?1:0;
default: default:
break; break;
} }
@ -127,22 +134,22 @@ uint32_t fcmp_s(uint32_t v1, uint32_t v2, uint32_t op) {
uint32_t fcvt_s(uint32_t v1, uint32_t op, uint8_t mode) { uint32_t fcvt_s(uint32_t v1, uint32_t op, uint8_t mode) {
float32_t v1f{v1}; float32_t v1f{v1};
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float32_t r; float32_t r;
switch(op) { switch(op){
case 0: { // w->s, fp to int32 case 0:{ //w->s, fp to int32
uint_fast32_t res = f32_to_i32(v1f, rmm_map[mode & 0x7], true); uint_fast32_t res = f32_to_i32(v1f,rmm_map[mode&0x7],true);
return (uint32_t)res; return (uint32_t)res;
} }
case 1: { // wu->s case 1:{ //wu->s
uint_fast32_t res = f32_to_ui32(v1f, rmm_map[mode & 0x7], true); uint_fast32_t res = f32_to_ui32(v1f,rmm_map[mode&0x7],true);
return (uint32_t)res; return (uint32_t)res;
} }
case 2: // s->w case 2: //s->w
r = i32_to_f32(v1); r=i32_to_f32(v1);
return r.v; return r.v;
case 3: // s->wu case 3: //s->wu
r = ui32_to_f32(v1); r=ui32_to_f32(v1);
return r.v; return r.v;
} }
return 0; return 0;
@ -150,11 +157,10 @@ uint32_t fcvt_s(uint32_t v1, uint32_t op, uint8_t mode) {
uint32_t fmadd_s(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t op, uint8_t mode) { uint32_t fmadd_s(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t op, uint8_t mode) {
// op should be {softfloat_mulAdd_subProd(2), softfloat_mulAdd_subC(1)} // op should be {softfloat_mulAdd_subProd(2), softfloat_mulAdd_subC(1)}
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float32_t res = softfloat_mulAddF32(v1, v2, v3, op & 0x1); float32_t res = softfloat_mulAddF32(v1, v2, v3, op&0x1);
if(op > 1) if(op>1) res.v ^= 1ULL<<31;
res.v ^= 1ULL << 31;
return res.v; return res.v;
} }
@ -164,23 +170,23 @@ uint32_t fsel_s(uint32_t v1, uint32_t v2, uint32_t op) {
bool v2_nan = (v2 & defaultNaNF32UI) == defaultNaNF32UI; bool v2_nan = (v2 & defaultNaNF32UI) == defaultNaNF32UI;
bool v1_snan = softfloat_isSigNaNF32UI(v1); bool v1_snan = softfloat_isSigNaNF32UI(v1);
bool v2_snan = softfloat_isSigNaNF32UI(v2); bool v2_snan = softfloat_isSigNaNF32UI(v2);
if(v1_snan || v2_snan) if (v1_snan || v2_snan) softfloat_raiseFlags(softfloat_flag_invalid);
softfloat_raiseFlags(softfloat_flag_invalid); if (v1_nan || v1_snan)
if(v1_nan || v1_snan)
return (v2_nan || v2_snan) ? defaultNaNF32UI : v2; return (v2_nan || v2_snan) ? defaultNaNF32UI : v2;
else if(v2_nan || v2_snan) else
return v1; if (v2_nan || v2_snan)
else { return v1;
if((v1 & 0x7fffffff) == 0 && (v2 & 0x7fffffff) == 0) { else {
return op == 0 ? ((v1 & 0x80000000) ? v1 : v2) : ((v1 & 0x80000000) ? v2 : v1); if ((v1 & 0x7fffffff) == 0 && (v2 & 0x7fffffff) == 0) {
} else { return op == 0 ? ((v1 & 0x80000000) ? v1 : v2) : ((v1 & 0x80000000) ? v2 : v1);
float32_t v1f{v1}, v2f{v2}; } else {
return op == 0 ? (f32_lt(v1f, v2f) ? v1 : v2) : (f32_lt(v1f, v2f) ? v2 : v1); float32_t v1f{ v1 }, v2f{ v2 };
return op == 0 ? (f32_lt(v1f, v2f) ? v1 : v2) : (f32_lt(v1f, v2f) ? v2 : v1);
}
} }
}
} }
uint32_t fclass_s(uint32_t v1) { uint32_t fclass_s( uint32_t v1 ){
float32_t a{v1}; float32_t a{v1};
union ui32_f32 uA; union ui32_f32 uA;
@ -189,23 +195,30 @@ uint32_t fclass_s(uint32_t v1) {
uA.f = a; uA.f = a;
uiA = uA.ui; uiA = uA.ui;
uint_fast16_t infOrNaN = expF32UI(uiA) == 0xFF; uint_fast16_t infOrNaN = expF32UI( uiA ) == 0xFF;
uint_fast16_t subnormalOrZero = expF32UI(uiA) == 0; uint_fast16_t subnormalOrZero = expF32UI( uiA ) == 0;
bool sign = signF32UI(uiA); bool sign = signF32UI( uiA );
bool fracZero = fracF32UI(uiA) == 0; bool fracZero = fracF32UI( uiA ) == 0;
bool isNaN = isNaNF32UI(uiA); bool isNaN = isNaNF32UI( uiA );
bool isSNaN = softfloat_isSigNaNF32UI(uiA); bool isSNaN = softfloat_isSigNaNF32UI( uiA );
return (sign && infOrNaN && fracZero) << 0 | (sign && !infOrNaN && !subnormalOrZero) << 1 | return
(sign && subnormalOrZero && !fracZero) << 2 | (sign && subnormalOrZero && fracZero) << 3 | (!sign && infOrNaN && fracZero) << 7 | ( sign && infOrNaN && fracZero ) << 0 |
(!sign && !infOrNaN && !subnormalOrZero) << 6 | (!sign && subnormalOrZero && !fracZero) << 5 | ( sign && !infOrNaN && !subnormalOrZero ) << 1 |
(!sign && subnormalOrZero && fracZero) << 4 | (isNaN && isSNaN) << 8 | (isNaN && !isSNaN) << 9; ( sign && subnormalOrZero && !fracZero ) << 2 |
( sign && subnormalOrZero && fracZero ) << 3 |
( !sign && infOrNaN && fracZero ) << 7 |
( !sign && !infOrNaN && !subnormalOrZero ) << 6 |
( !sign && subnormalOrZero && !fracZero ) << 5 |
( !sign && subnormalOrZero && fracZero ) << 4 |
( isNaN && isSNaN ) << 8 |
( isNaN && !isSNaN ) << 9;
} }
uint32_t fconv_d2f(uint64_t v1, uint8_t mode) { uint32_t fconv_d2f(uint64_t v1, uint8_t mode){
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
bool nan = (v1 & defaultNaNF64UI) == defaultNaNF64UI; bool nan = (v1 & defaultNaNF64UI)==defaultNaNF64UI;
if(nan) { if(nan){
return defaultNaNF32UI; return defaultNaNF32UI;
} else { } else {
float32_t res = f64_to_f32(float64_t{v1}); float32_t res = f64_to_f32(float64_t{v1});
@ -213,84 +226,83 @@ uint32_t fconv_d2f(uint64_t v1, uint8_t mode) {
} }
} }
uint64_t fconv_f2d(uint32_t v1, uint8_t mode) { uint64_t fconv_f2d(uint32_t v1, uint8_t mode){
bool nan = (v1 & defaultNaNF32UI) == defaultNaNF32UI; bool nan = (v1 & defaultNaNF32UI)==defaultNaNF32UI;
if(nan) { if(nan){
return defaultNaNF64UI; return defaultNaNF64UI;
} else { } else {
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
float64_t res = f32_to_f64(float32_t{v1}); float64_t res = f32_to_f64(float32_t{v1});
return res.v; return res.v;
} }
} }
uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode) { uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode) {
bool nan = (v1 & defaultNaNF32UI) == quiet_nan32; bool nan = (v1&defaultNaNF32UI)==quiet_nan32;
bool snan = softfloat_isSigNaNF32UI(v1); bool snan = softfloat_isSigNaNF32UI(v1);
float64_t v1f{v1}, v2f{v2}; float64_t v1f{v1},v2f{v2};
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float64_t r = f64_add(v1f, v2f); float64_t r =f64_add(v1f, v2f);
return r.v; return r.v;
} }
uint64_t fsub_d(uint64_t v1, uint64_t v2, uint8_t mode) { uint64_t fsub_d(uint64_t v1, uint64_t v2, uint8_t mode) {
float64_t v1f{v1}, v2f{v2}; float64_t v1f{v1},v2f{v2};
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float64_t r = f64_sub(v1f, v2f); float64_t r=f64_sub(v1f, v2f);
return r.v; return r.v;
} }
uint64_t fmul_d(uint64_t v1, uint64_t v2, uint8_t mode) { uint64_t fmul_d(uint64_t v1, uint64_t v2, uint8_t mode) {
float64_t v1f{v1}, v2f{v2}; float64_t v1f{v1},v2f{v2};
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float64_t r = f64_mul(v1f, v2f); float64_t r=f64_mul(v1f, v2f);
return r.v; return r.v;
} }
uint64_t fdiv_d(uint64_t v1, uint64_t v2, uint8_t mode) { uint64_t fdiv_d(uint64_t v1, uint64_t v2, uint8_t mode) {
float64_t v1f{v1}, v2f{v2}; float64_t v1f{v1},v2f{v2};
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float64_t r = f64_div(v1f, v2f); float64_t r=f64_div(v1f, v2f);
return r.v; return r.v;
} }
uint64_t fsqrt_d(uint64_t v1, uint8_t mode) { uint64_t fsqrt_d(uint64_t v1, uint8_t mode) {
float64_t v1f{v1}; float64_t v1f{v1};
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float64_t r = f64_sqrt(v1f); float64_t r=f64_sqrt(v1f);
return r.v; return r.v;
} }
uint64_t fcmp_d(uint64_t v1, uint64_t v2, uint32_t op) { uint64_t fcmp_d(uint64_t v1, uint64_t v2, uint32_t op) {
float64_t v1f{v1}, v2f{v2}; float64_t v1f{v1},v2f{v2};
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
bool nan = (v1 & defaultNaNF64UI) == quiet_nan32 || (v2 & defaultNaNF64UI) == quiet_nan32; bool nan = (v1&defaultNaNF64UI)==quiet_nan32 || (v2&defaultNaNF64UI)==quiet_nan32;
bool snan = softfloat_isSigNaNF64UI(v1) || softfloat_isSigNaNF64UI(v2); bool snan = softfloat_isSigNaNF64UI(v1) || softfloat_isSigNaNF64UI(v2);
switch(op) { switch(op){
case 0: case 0:
if(nan | snan) { if(nan | snan){
if(snan) if(snan) softfloat_raiseFlags(softfloat_flag_invalid);
softfloat_raiseFlags(softfloat_flag_invalid);
return 0; return 0;
} else } else
return f64_eq(v1f, v2f) ? 1 : 0; return f64_eq(v1f,v2f )?1:0;
case 1: case 1:
if(nan | snan) { if(nan | snan){
softfloat_raiseFlags(softfloat_flag_invalid); softfloat_raiseFlags(softfloat_flag_invalid);
return 0; return 0;
} else } else
return f64_le(v1f, v2f) ? 1 : 0; return f64_le(v1f,v2f )?1:0;
case 2: case 2:
if(nan | snan) { if(nan | snan){
softfloat_raiseFlags(softfloat_flag_invalid); softfloat_raiseFlags(softfloat_flag_invalid);
return 0; return 0;
} else } else
return f64_lt(v1f, v2f) ? 1 : 0; return f64_lt(v1f,v2f )?1:0;
default: default:
break; break;
} }
@ -299,22 +311,22 @@ uint64_t fcmp_d(uint64_t v1, uint64_t v2, uint32_t op) {
uint64_t fcvt_d(uint64_t v1, uint32_t op, uint8_t mode) { uint64_t fcvt_d(uint64_t v1, uint32_t op, uint8_t mode) {
float64_t v1f{v1}; float64_t v1f{v1};
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float64_t r; float64_t r;
switch(op) { switch(op){
case 0: { // l->d, fp to int32 case 0:{ //l->d, fp to int32
int64_t res = f64_to_i64(v1f, rmm_map[mode & 0x7], true); int64_t res = f64_to_i64(v1f,rmm_map[mode&0x7],true);
return (uint64_t)res; return (uint64_t)res;
} }
case 1: { // lu->s case 1:{ //lu->s
uint64_t res = f64_to_ui64(v1f, rmm_map[mode & 0x7], true); uint64_t res = f64_to_ui64(v1f,rmm_map[mode&0x7],true);
return res; return res;
} }
case 2: // s->l case 2: //s->l
r = i64_to_f64(v1); r=i64_to_f64(v1);
return r.v; return r.v;
case 3: // s->lu case 3: //s->lu
r = ui64_to_f64(v1); r=ui64_to_f64(v1);
return r.v; return r.v;
} }
return 0; return 0;
@ -322,11 +334,10 @@ uint64_t fcvt_d(uint64_t v1, uint32_t op, uint8_t mode) {
uint64_t fmadd_d(uint64_t v1, uint64_t v2, uint64_t v3, uint32_t op, uint8_t mode) { uint64_t fmadd_d(uint64_t v1, uint64_t v2, uint64_t v3, uint32_t op, uint8_t mode) {
// op should be {softfloat_mulAdd_subProd(2), softfloat_mulAdd_subC(1)} // op should be {softfloat_mulAdd_subProd(2), softfloat_mulAdd_subC(1)}
softfloat_roundingMode = rmm_map[mode & 0x7]; softfloat_roundingMode=rmm_map[mode&0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float64_t res = softfloat_mulAddF64(v1, v2, v3, op & 0x1); float64_t res = softfloat_mulAddF64(v1, v2, v3, op&0x1);
if(op > 1) if(op>1) res.v ^= 1ULL<<63;
res.v ^= 1ULL << 63;
return res.v; return res.v;
} }
@ -336,24 +347,27 @@ uint64_t fsel_d(uint64_t v1, uint64_t v2, uint32_t op) {
bool v2_nan = (v2 & defaultNaNF64UI) == defaultNaNF64UI; bool v2_nan = (v2 & defaultNaNF64UI) == defaultNaNF64UI;
bool v1_snan = softfloat_isSigNaNF64UI(v1); bool v1_snan = softfloat_isSigNaNF64UI(v1);
bool v2_snan = softfloat_isSigNaNF64UI(v2); bool v2_snan = softfloat_isSigNaNF64UI(v2);
if(v1_snan || v2_snan) if (v1_snan || v2_snan) softfloat_raiseFlags(softfloat_flag_invalid);
softfloat_raiseFlags(softfloat_flag_invalid); if (v1_nan || v1_snan)
if(v1_nan || v1_snan)
return (v2_nan || v2_snan) ? defaultNaNF64UI : v2; return (v2_nan || v2_snan) ? defaultNaNF64UI : v2;
else if(v2_nan || v2_snan) else
return v1; if (v2_nan || v2_snan)
else { return v1;
if((v1 & std::numeric_limits<int64_t>::max()) == 0 && (v2 & std::numeric_limits<int64_t>::max()) == 0) { else {
return op == 0 ? ((v1 & std::numeric_limits<int64_t>::min()) ? v1 : v2) if ((v1 & std::numeric_limits<int64_t>::max()) == 0 && (v2 & std::numeric_limits<int64_t>::max()) == 0) {
: ((v1 & std::numeric_limits<int64_t>::min()) ? v2 : v1); return op == 0 ?
} else { ((v1 & std::numeric_limits<int64_t>::min()) ? v1 : v2) :
float64_t v1f{v1}, v2f{v2}; ((v1 & std::numeric_limits<int64_t>::min()) ? v2 : v1);
return op == 0 ? (f64_lt(v1f, v2f) ? v1 : v2) : (f64_lt(v1f, v2f) ? v2 : v1); } else {
float64_t v1f{ v1 }, v2f{ v2 };
return op == 0 ?
(f64_lt(v1f, v2f) ? v1 : v2) :
(f64_lt(v1f, v2f) ? v2 : v1);
}
} }
}
} }
uint64_t fclass_d(uint64_t v1) { uint64_t fclass_d(uint64_t v1 ){
float64_t a{v1}; float64_t a{v1};
union ui64_f64 uA; union ui64_f64 uA;
@ -362,61 +376,68 @@ uint64_t fclass_d(uint64_t v1) {
uA.f = a; uA.f = a;
uiA = uA.ui; uiA = uA.ui;
uint_fast16_t infOrNaN = expF64UI(uiA) == 0x7FF; uint_fast16_t infOrNaN = expF64UI( uiA ) == 0x7FF;
uint_fast16_t subnormalOrZero = expF64UI(uiA) == 0; uint_fast16_t subnormalOrZero = expF64UI( uiA ) == 0;
bool sign = signF64UI(uiA); bool sign = signF64UI( uiA );
bool fracZero = fracF64UI(uiA) == 0; bool fracZero = fracF64UI( uiA ) == 0;
bool isNaN = isNaNF64UI(uiA); bool isNaN = isNaNF64UI( uiA );
bool isSNaN = softfloat_isSigNaNF64UI(uiA); bool isSNaN = softfloat_isSigNaNF64UI( uiA );
return (sign && infOrNaN && fracZero) << 0 | (sign && !infOrNaN && !subnormalOrZero) << 1 | return
(sign && subnormalOrZero && !fracZero) << 2 | (sign && subnormalOrZero && fracZero) << 3 | (!sign && infOrNaN && fracZero) << 7 | ( sign && infOrNaN && fracZero ) << 0 |
(!sign && !infOrNaN && !subnormalOrZero) << 6 | (!sign && subnormalOrZero && !fracZero) << 5 | ( sign && !infOrNaN && !subnormalOrZero ) << 1 |
(!sign && subnormalOrZero && fracZero) << 4 | (isNaN && isSNaN) << 8 | (isNaN && !isSNaN) << 9; ( sign && subnormalOrZero && !fracZero ) << 2 |
( sign && subnormalOrZero && fracZero ) << 3 |
( !sign && infOrNaN && fracZero ) << 7 |
( !sign && !infOrNaN && !subnormalOrZero ) << 6 |
( !sign && subnormalOrZero && !fracZero ) << 5 |
( !sign && subnormalOrZero && fracZero ) << 4 |
( isNaN && isSNaN ) << 8 |
( isNaN && !isSNaN ) << 9;
} }
uint64_t fcvt_32_64(uint32_t v1, uint32_t op, uint8_t mode) { uint64_t fcvt_32_64(uint32_t v1, uint32_t op, uint8_t mode) {
float32_t v1f{v1}; float32_t v1f{v1};
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float64_t r; float64_t r;
switch(op) { switch(op){
case 0: // l->s, fp to int32 case 0: //l->s, fp to int32
return f32_to_i64(v1f, rmm_map[mode & 0x7], true); return f32_to_i64(v1f,rmm_map[mode&0x7],true);
case 1: // wu->s case 1: //wu->s
return f32_to_ui64(v1f, rmm_map[mode & 0x7], true); return f32_to_ui64(v1f,rmm_map[mode&0x7],true);
case 2: // s->w case 2: //s->w
r = i32_to_f64(v1); r=i32_to_f64(v1);
return r.v; return r.v;
case 3: // s->wu case 3: //s->wu
r = ui32_to_f64(v1); r=ui32_to_f64(v1);
return r.v; return r.v;
} }
return 0; return 0;
} }
uint32_t fcvt_64_32(uint64_t v1, uint32_t op, uint8_t mode) { uint32_t fcvt_64_32(uint64_t v1, uint32_t op, uint8_t mode) {
softfloat_exceptionFlags = 0; softfloat_exceptionFlags=0;
float32_t r; float32_t r;
switch(op) { switch(op){
case 0: { // wu->s case 0:{ //wu->s
int32_t r = f64_to_i32(float64_t{v1}, rmm_map[mode & 0x7], true); int32_t r=f64_to_i32(float64_t{v1}, rmm_map[mode&0x7],true);
return r; return r;
} }
case 1: { // wu->s case 1:{ //wu->s
uint32_t r = f64_to_ui32(float64_t{v1}, rmm_map[mode & 0x7], true); uint32_t r=f64_to_ui32(float64_t{v1}, rmm_map[mode&0x7],true);
return r; return r;
} }
case 2: // l->s, fp to int32 case 2: //l->s, fp to int32
r = i64_to_f32(v1); r=i64_to_f32(v1);
return r.v; return r.v;
case 3: // wu->s case 3: //wu->s
r = ui64_to_f32(v1); r=ui64_to_f32(v1);
return r.v; return r.v;
} }
return 0; return 0;
} }
uint32_t unbox_s(uint64_t v) { uint32_t unbox_s(uint64_t v){
constexpr uint64_t mask = std::numeric_limits<uint64_t>::max() & ~((uint64_t)std::numeric_limits<uint32_t>::max()); constexpr uint64_t mask = std::numeric_limits<uint64_t>::max() & ~((uint64_t)std::numeric_limits<uint32_t>::max());
if((v & mask) != mask) if((v & mask) != mask)
return 0x7fc00000; return 0x7fc00000;
@ -424,3 +445,4 @@ uint32_t unbox_s(uint64_t v) {
return v & std::numeric_limits<uint32_t>::max(); return v & std::numeric_limits<uint32_t>::max();
} }
} }

View File

@ -44,11 +44,11 @@ uint32_t fsub_s(uint32_t v1, uint32_t v2, uint8_t mode);
uint32_t fmul_s(uint32_t v1, uint32_t v2, uint8_t mode); uint32_t fmul_s(uint32_t v1, uint32_t v2, uint8_t mode);
uint32_t fdiv_s(uint32_t v1, uint32_t v2, uint8_t mode); uint32_t fdiv_s(uint32_t v1, uint32_t v2, uint8_t mode);
uint32_t fsqrt_s(uint32_t v1, uint8_t mode); uint32_t fsqrt_s(uint32_t v1, uint8_t mode);
uint32_t fcmp_s(uint32_t v1, uint32_t v2, uint32_t op); uint32_t fcmp_s(uint32_t v1, uint32_t v2, uint32_t op) ;
uint32_t fcvt_s(uint32_t v1, uint32_t op, uint8_t mode); uint32_t fcvt_s(uint32_t v1, uint32_t op, uint8_t mode);
uint32_t fmadd_s(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t op, uint8_t mode); uint32_t fmadd_s(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t op, uint8_t mode);
uint32_t fsel_s(uint32_t v1, uint32_t v2, uint32_t op); uint32_t fsel_s(uint32_t v1, uint32_t v2, uint32_t op);
uint32_t fclass_s(uint32_t v1); uint32_t fclass_s( uint32_t v1 );
uint32_t fconv_d2f(uint64_t v1, uint8_t mode); uint32_t fconv_d2f(uint64_t v1, uint8_t mode);
uint64_t fconv_f2d(uint32_t v1, uint8_t mode); uint64_t fconv_f2d(uint32_t v1, uint8_t mode);
uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode); uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode);
@ -59,8 +59,8 @@ uint64_t fsqrt_d(uint64_t v1, uint8_t mode);
uint64_t fcmp_d(uint64_t v1, uint64_t v2, uint32_t op); uint64_t fcmp_d(uint64_t v1, uint64_t v2, uint32_t op);
uint64_t fcvt_d(uint64_t v1, uint32_t op, uint8_t mode); uint64_t fcvt_d(uint64_t v1, uint32_t op, uint8_t mode);
uint64_t fmadd_d(uint64_t v1, uint64_t v2, uint64_t v3, uint32_t op, uint8_t mode); uint64_t fmadd_d(uint64_t v1, uint64_t v2, uint64_t v3, uint32_t op, uint8_t mode);
uint64_t fsel_d(uint64_t v1, uint64_t v2, uint32_t op); uint64_t fsel_d(uint64_t v1, uint64_t v2, uint32_t op) ;
uint64_t fclass_d(uint64_t v1); uint64_t fclass_d(uint64_t v1 );
uint64_t fcvt_32_64(uint32_t v1, uint32_t op, uint8_t mode); uint64_t fcvt_32_64(uint32_t v1, uint32_t op, uint8_t mode);
uint32_t fcvt_64_32(uint64_t v1, uint32_t op, uint8_t mode); uint32_t fcvt_64_32(uint64_t v1, uint32_t op, uint8_t mode);
uint32_t unbox_s(uint64_t v); uint32_t unbox_s(uint64_t v);

1
src/vm/interp/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/vm_tgc_*.cpp

File diff suppressed because it is too large Load Diff

4157
src/vm/interp/vm_tgc_c.cpp Normal file

File diff suppressed because it is too large Load Diff

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