Compare commits
74 Commits
feature/co
...
2bea95c1a7
Author | SHA1 | Date | |
---|---|---|---|
2bea95c1a7 | |||
7001b693ae | |||
e6f11081eb | |||
09db0cd35d | |||
980c8031c3 | |||
b86d7a517d | |||
b7478965ab | |||
bf4a6deb86 | |||
ffe730219d | |||
60c926c921 | |||
9371a09b71 | |||
4c3a7386b0 | |||
82c26acfc8 | |||
3a86f4f9de | |||
74ff1d455a | |||
aa12e93177 | |||
ae4322c1b9 | |||
9180ad1f9c | |||
ee6a068b06 | |||
b9b165465d | |||
b97853ff5a | |||
b7f023756e | |||
2095ac985b | |||
3fb8fe765a | |||
5fd226b670 | |||
417076f8e6 | |||
70839bbbf2 | |||
8db0cc5d05 | |||
212fb1c8ff | |||
f74f98f361 | |||
f074092a78 | |||
633c0d21a0 | |||
51f6fbe0dd | |||
de45d06878 | |||
c7038cafa5 | |||
40f50b0ec0 | |||
b360fc2c75 | |||
e21f8dc379 | |||
8ee3ac90f7 | |||
d5763d2f36 | |||
b5d915f389 | |||
813b40409d | |||
c8a4a4c736 | |||
18e08cfc50 | |||
20e920338c | |||
e151416f58 | |||
24de2bbdf5 | |||
e68f9c573f | |||
f38cc7d8b9 | |||
7af7e040da | |||
6e52af168b | |||
bd0d15f3a2 | |||
c78026b720 | |||
edba497fa1 | |||
94e46b9968 | |||
9459632f6c | |||
a0ca3cdfa5 | |||
720236ec3f | |||
957145ca84 | |||
0b719a4b57 | |||
57da07eb17 | |||
b4b03f7850 | |||
145a0cf68b | |||
1cef7de8c7 | |||
e95f422aab | |||
250ea3c980 | |||
7b31b8ca8e | |||
91a23a4a18 | |||
21d3250e1a | |||
2b094c3162 | |||
87b4082633 | |||
15cd36dcd4 | |||
2281ec4144 | |||
11c481cec2 |
1
.project
1
.project
@ -23,6 +23,5 @@
|
||||
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
<nature>org.eclipse.linuxtools.tmf.project.nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
|
@ -1,73 +0,0 @@
|
||||
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\\")"}
|
@ -1,13 +0,0 @@
|
||||
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
|
@ -1,37 +0,0 @@
|
||||
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
|
195
CMakeLists.txt
195
CMakeLists.txt
@ -1,114 +1,106 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
###############################################################################
|
||||
#
|
||||
###############################################################################
|
||||
project(dbt-rise-tgc VERSION 1.0.0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(flink)
|
||||
|
||||
find_package(elfio QUIET)
|
||||
find_package(Boost COMPONENTS coroutine)
|
||||
find_package(jsoncpp)
|
||||
|
||||
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)
|
||||
find_package(Boost COMPONENTS coroutine REQUIRED)
|
||||
|
||||
add_subdirectory(softfloat)
|
||||
|
||||
set(LIB_SOURCES
|
||||
src/iss/plugin/instruction_count.cpp
|
||||
src/iss/arch/tgc_c.cpp
|
||||
src/vm/interp/vm_tgc_c.cpp
|
||||
src/iss/arch/tgc5c.cpp
|
||||
src/vm/interp/vm_tgc5c.cpp
|
||||
src/vm/fp_functions.cpp
|
||||
)
|
||||
|
||||
if(WITH_TCC)
|
||||
list(APPEND LIB_SOURCES
|
||||
src/vm/tcc/vm_tgc5c.cpp
|
||||
)
|
||||
endif()
|
||||
if(WITH_LLVM)
|
||||
list(APPEND LIB_SOURCES
|
||||
src/vm/llvm/vm_tgc5c.cpp
|
||||
src/vm/llvm/fp_impl.cpp
|
||||
)
|
||||
endif()
|
||||
if(WITH_ASMJIT)
|
||||
list(APPEND LIB_SOURCES
|
||||
src/vm/asmjit/vm_tgc5c.cpp
|
||||
)
|
||||
endif()
|
||||
# library files
|
||||
if(TARGET ${CORE_NAME}_cpp)
|
||||
list(APPEND LIB_SOURCES ${${CORE_NAME}_OUTPUT_FILES})
|
||||
else()
|
||||
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)
|
||||
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("Defines are ${LIB_DEFINES}")
|
||||
endif()
|
||||
|
||||
if(TARGET RapidJSON OR TARGET RapidJSON::RapidJSON)
|
||||
list(APPEND LIB_SOURCES src/iss/plugin/cycle_estimate.cpp src/iss/plugin/pctrace.cpp)
|
||||
endif()
|
||||
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
|
||||
)
|
||||
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/vm/tcc/vm_*.cpp
|
||||
)
|
||||
FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/tcc/vm_*.cpp)
|
||||
list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
|
||||
endif()
|
||||
|
||||
# Define the library
|
||||
add_library(${PROJECT_NAME} ${LIB_SOURCES})
|
||||
# list code gen dependencies
|
||||
if(TARGET ${CORE_NAME}_cpp)
|
||||
add_dependencies(${PROJECT_NAME} ${CORE_NAME}_cpp)
|
||||
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()
|
||||
# Define the library
|
||||
add_library(${PROJECT_NAME} SHARED ${LIB_SOURCES})
|
||||
|
||||
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")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
|
||||
endif()
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC src)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC src-gen)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC softfloat scc-util Boost::coroutine)
|
||||
if(TARGET jsoncpp::jsoncpp)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp::jsoncpp)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp)
|
||||
endif()
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND BUILD_SHARED_LIBS)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-rise-core -Wl,--no-whole-archive)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-core)
|
||||
endif()
|
||||
if(TARGET elfio::elfio)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio)
|
||||
else()
|
||||
message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
|
||||
endif()
|
||||
if(TARGET lz4::lz4)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_LZ4)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC lz4::lz4)
|
||||
endif()
|
||||
if(TARGET RapidJSON::RapidJSON)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON::RapidJSON)
|
||||
elseif(TARGET RapidJSON)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON)
|
||||
|
||||
target_force_link_libraries(${PROJECT_NAME} PRIVATE dbt-rise-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()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio softfloat scc-util Boost::coroutine)
|
||||
if(TARGET yaml-cpp::yaml-cpp)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_PLUGINS)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC yaml-cpp::yaml-cpp)
|
||||
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()
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
@ -128,9 +120,11 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss COMPONENT ${PROJECT_NAME}
|
||||
FILES_MATCHING # install only matched 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)
|
||||
find_package(Boost COMPONENTS program_options thread REQUIRED)
|
||||
|
||||
@ -153,15 +147,16 @@ foreach(F IN LISTS TGC_SOURCES)
|
||||
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()
|
||||
# Links the target exe against the libraries
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc)
|
||||
#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)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options)
|
||||
else()
|
||||
@ -181,12 +176,36 @@ install(TARGETS tgc-sim
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} # headers for mac (note the different component -> different package)
|
||||
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)
|
||||
add_library(${PROJECT_NAME} src/sysc/core_complex.cpp)
|
||||
set(LIB_SOURCES
|
||||
src/sysc/core_complex.cpp
|
||||
src/sysc/register_tgc_c.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} PRIVATE CORE_${CORE_NAME})
|
||||
foreach(F IN LISTS TGC_SOURCES)
|
||||
@ -197,9 +216,9 @@ if(TARGET scc-sysc)
|
||||
endif()
|
||||
endforeach()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc)
|
||||
if(WITH_LLVM)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
||||
endif()
|
||||
# if(WITH_LLVM)
|
||||
# target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
||||
# endif()
|
||||
|
||||
set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
|
35
cmake/flink.cmake
Normal file
35
cmake/flink.cmake
Normal file
@ -0,0 +1,35 @@
|
||||
# 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()
|
1
contrib/instr/.gitignore
vendored
Normal file
1
contrib/instr/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/*.yaml
|
@ -1,307 +1,348 @@
|
||||
|
||||
RV32I:
|
||||
- LUI:
|
||||
LUI:
|
||||
index: 0
|
||||
encoding: 0b00000000000000000000000000110111
|
||||
mask: 0b00000000000000000000000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- AUIPC:
|
||||
AUIPC:
|
||||
index: 1
|
||||
encoding: 0b00000000000000000000000000010111
|
||||
mask: 0b00000000000000000000000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- JAL:
|
||||
JAL:
|
||||
index: 2
|
||||
encoding: 0b00000000000000000000000001101111
|
||||
mask: 0b00000000000000000000000001111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: 1
|
||||
- JALR:
|
||||
JALR:
|
||||
index: 3
|
||||
encoding: 0b00000000000000000000000001100111
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: 1
|
||||
- BEQ:
|
||||
delay: [1,2]
|
||||
BEQ:
|
||||
index: 4
|
||||
encoding: 0b00000000000000000000000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- BNE:
|
||||
delay: [1,2]
|
||||
BNE:
|
||||
index: 5
|
||||
encoding: 0b00000000000000000001000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- BLT:
|
||||
delay: [1,2]
|
||||
BLT:
|
||||
index: 6
|
||||
encoding: 0b00000000000000000100000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- BGE:
|
||||
delay: [1,2]
|
||||
BGE:
|
||||
index: 7
|
||||
encoding: 0b00000000000000000101000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- BLTU:
|
||||
delay: [1,2]
|
||||
BLTU:
|
||||
index: 8
|
||||
encoding: 0b00000000000000000110000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- BGEU:
|
||||
delay: [1,2]
|
||||
BGEU:
|
||||
index: 9
|
||||
encoding: 0b00000000000000000111000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- LB:
|
||||
delay: [1,2]
|
||||
LB:
|
||||
index: 10
|
||||
encoding: 0b00000000000000000000000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- LH:
|
||||
delay: 2
|
||||
LH:
|
||||
index: 11
|
||||
encoding: 0b00000000000000000001000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- LW:
|
||||
delay: 2
|
||||
LW:
|
||||
index: 12
|
||||
encoding: 0b00000000000000000010000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- LBU:
|
||||
delay: 2
|
||||
LBU:
|
||||
index: 13
|
||||
encoding: 0b00000000000000000100000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- LHU:
|
||||
delay: 2
|
||||
LHU:
|
||||
index: 14
|
||||
encoding: 0b00000000000000000101000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SB:
|
||||
delay: 2
|
||||
SB:
|
||||
index: 15
|
||||
encoding: 0b00000000000000000000000000100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SH:
|
||||
SH:
|
||||
index: 16
|
||||
encoding: 0b00000000000000000001000000100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SW:
|
||||
SW:
|
||||
index: 17
|
||||
encoding: 0b00000000000000000010000000100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- ADDI:
|
||||
ADDI:
|
||||
index: 18
|
||||
encoding: 0b00000000000000000000000000010011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SLTI:
|
||||
SLTI:
|
||||
index: 19
|
||||
encoding: 0b00000000000000000010000000010011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SLTIU:
|
||||
SLTIU:
|
||||
index: 20
|
||||
encoding: 0b00000000000000000011000000010011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- XORI:
|
||||
XORI:
|
||||
index: 21
|
||||
encoding: 0b00000000000000000100000000010011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- ORI:
|
||||
ORI:
|
||||
index: 22
|
||||
encoding: 0b00000000000000000110000000010011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- ANDI:
|
||||
ANDI:
|
||||
index: 23
|
||||
encoding: 0b00000000000000000111000000010011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SLLI:
|
||||
SLLI:
|
||||
index: 24
|
||||
encoding: 0b00000000000000000001000000010011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SRLI:
|
||||
SRLI:
|
||||
index: 25
|
||||
encoding: 0b00000000000000000101000000010011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SRAI:
|
||||
SRAI:
|
||||
index: 26
|
||||
encoding: 0b01000000000000000101000000010011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- ADD:
|
||||
ADD:
|
||||
index: 27
|
||||
encoding: 0b00000000000000000000000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SUB:
|
||||
SUB:
|
||||
index: 28
|
||||
encoding: 0b01000000000000000000000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SLL:
|
||||
SLL:
|
||||
index: 29
|
||||
encoding: 0b00000000000000000001000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SLT:
|
||||
SLT:
|
||||
index: 30
|
||||
encoding: 0b00000000000000000010000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SLTU:
|
||||
SLTU:
|
||||
index: 31
|
||||
encoding: 0b00000000000000000011000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- XOR:
|
||||
XOR:
|
||||
index: 32
|
||||
encoding: 0b00000000000000000100000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SRL:
|
||||
SRL:
|
||||
index: 33
|
||||
encoding: 0b00000000000000000101000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SRA:
|
||||
SRA:
|
||||
index: 34
|
||||
encoding: 0b01000000000000000101000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- OR:
|
||||
OR:
|
||||
index: 35
|
||||
encoding: 0b00000000000000000110000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- AND:
|
||||
AND:
|
||||
index: 36
|
||||
encoding: 0b00000000000000000111000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- FENCE:
|
||||
FENCE:
|
||||
index: 37
|
||||
encoding: 0b00000000000000000000000000001111
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- ECALL:
|
||||
ECALL:
|
||||
index: 38
|
||||
encoding: 0b00000000000000000000000001110011
|
||||
mask: 0b11111111111111111111111111111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- EBREAK:
|
||||
EBREAK:
|
||||
index: 39
|
||||
encoding: 0b00000000000100000000000001110011
|
||||
mask: 0b11111111111111111111111111111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- MRET:
|
||||
MRET:
|
||||
index: 40
|
||||
encoding: 0b00110000001000000000000001110011
|
||||
mask: 0b11111111111111111111111111111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- WFI:
|
||||
WFI:
|
||||
index: 41
|
||||
encoding: 0b00010000010100000000000001110011
|
||||
mask: 0b11111111111111111111111111111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
Zicsr:
|
||||
- CSRRW:
|
||||
CSRRW:
|
||||
index: 42
|
||||
encoding: 0b00000000000000000001000001110011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSRRS:
|
||||
CSRRS:
|
||||
index: 43
|
||||
encoding: 0b00000000000000000010000001110011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSRRC:
|
||||
CSRRC:
|
||||
index: 44
|
||||
encoding: 0b00000000000000000011000001110011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSRRWI:
|
||||
CSRRWI:
|
||||
index: 45
|
||||
encoding: 0b00000000000000000101000001110011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSRRSI:
|
||||
CSRRSI:
|
||||
index: 46
|
||||
encoding: 0b00000000000000000110000001110011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSRRCI:
|
||||
CSRRCI:
|
||||
index: 47
|
||||
encoding: 0b00000000000000000111000001110011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
Zifencei:
|
||||
- FENCE_I:
|
||||
FENCE_I:
|
||||
index: 48
|
||||
encoding: 0b00000000000000000001000000001111
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:flush]]
|
||||
@ -309,228 +350,274 @@ Zifencei:
|
||||
branch: false
|
||||
delay: 1
|
||||
RV32M:
|
||||
- MUL:
|
||||
MUL:
|
||||
index: 49
|
||||
encoding: 0b00000010000000000000000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- MULH:
|
||||
delay: 2
|
||||
MULH:
|
||||
index: 50
|
||||
encoding: 0b00000010000000000001000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- MULHSU:
|
||||
delay: 2
|
||||
MULHSU:
|
||||
index: 51
|
||||
encoding: 0b00000010000000000010000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- MULHU:
|
||||
delay: 2
|
||||
MULHU:
|
||||
index: 52
|
||||
encoding: 0b00000010000000000011000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- DIV:
|
||||
delay: 2
|
||||
DIV:
|
||||
index: 53
|
||||
encoding: 0b00000010000000000100000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- DIVU:
|
||||
delay: 17
|
||||
DIVU:
|
||||
index: 54
|
||||
encoding: 0b00000010000000000101000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- REM:
|
||||
delay: 17
|
||||
REM:
|
||||
index: 55
|
||||
encoding: 0b00000010000000000110000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- REMU:
|
||||
delay: 17
|
||||
REMU:
|
||||
index: 56
|
||||
encoding: 0b00000010000000000111000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
RV32IC:
|
||||
- CADDI4SPN:
|
||||
delay: 17
|
||||
Zca:
|
||||
C__ADDI4SPN:
|
||||
index: 57
|
||||
encoding: 0b0000000000000000
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CLW:
|
||||
C__LW:
|
||||
index: 58
|
||||
encoding: 0b0100000000000000
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSW:
|
||||
delay: 2
|
||||
C__SW:
|
||||
index: 59
|
||||
encoding: 0b1100000000000000
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CADDI:
|
||||
C__ADDI:
|
||||
index: 60
|
||||
encoding: 0b0000000000000001
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CNOP:
|
||||
C__NOP:
|
||||
index: 61
|
||||
encoding: 0b0000000000000001
|
||||
mask: 0b1110111110000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CJAL:
|
||||
C__JAL:
|
||||
index: 62
|
||||
encoding: 0b0010000000000001
|
||||
mask: 0b1110000000000011
|
||||
attributes: [[name:no_cont]]
|
||||
attributes: [[name:enable, value:1]]
|
||||
size: 16
|
||||
branch: true
|
||||
delay: 1
|
||||
- CLI:
|
||||
C__LI:
|
||||
index: 63
|
||||
encoding: 0b0100000000000001
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CLUI:
|
||||
C__LUI:
|
||||
index: 64
|
||||
encoding: 0b0110000000000001
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CADDI16SP:
|
||||
C__ADDI16SP:
|
||||
index: 65
|
||||
encoding: 0b0110000100000001
|
||||
mask: 0b1110111110000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSRLI:
|
||||
__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
|
||||
- CSRAI:
|
||||
C__SRAI:
|
||||
index: 68
|
||||
encoding: 0b1000010000000001
|
||||
mask: 0b1111110000000011
|
||||
attributes: [[name:enable, value:1]]
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CANDI:
|
||||
C__ANDI:
|
||||
index: 69
|
||||
encoding: 0b1000100000000001
|
||||
mask: 0b1110110000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSUB:
|
||||
C__SUB:
|
||||
index: 70
|
||||
encoding: 0b1000110000000001
|
||||
mask: 0b1111110001100011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CXOR:
|
||||
C__XOR:
|
||||
index: 71
|
||||
encoding: 0b1000110000100001
|
||||
mask: 0b1111110001100011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- COR:
|
||||
C__OR:
|
||||
index: 72
|
||||
encoding: 0b1000110001000001
|
||||
mask: 0b1111110001100011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CAND:
|
||||
C__AND:
|
||||
index: 73
|
||||
encoding: 0b1000110001100001
|
||||
mask: 0b1111110001100011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CJ:
|
||||
C__J:
|
||||
index: 74
|
||||
encoding: 0b1010000000000001
|
||||
mask: 0b1110000000000011
|
||||
attributes: [[name:no_cont]]
|
||||
size: 16
|
||||
branch: true
|
||||
delay: 1
|
||||
- CBEQZ:
|
||||
C__BEQZ:
|
||||
index: 75
|
||||
encoding: 0b1100000000000001
|
||||
mask: 0b1110000000000011
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 16
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- CBNEZ:
|
||||
delay: [1,2]
|
||||
C__BNEZ:
|
||||
index: 76
|
||||
encoding: 0b1110000000000001
|
||||
mask: 0b1110000000000011
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 16
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- CSLLI:
|
||||
delay: [1,2]
|
||||
C__SLLI:
|
||||
index: 77
|
||||
encoding: 0b0000000000000010
|
||||
mask: 0b1111000000000011
|
||||
attributes: [[name:enable, value:1]]
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CLWSP:
|
||||
C__LWSP:
|
||||
index: 78
|
||||
encoding: 0b0100000000000010
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CMV:
|
||||
delay: 2
|
||||
C__MV:
|
||||
index: 79
|
||||
encoding: 0b1000000000000010
|
||||
mask: 0b1111000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CJR:
|
||||
C__JR:
|
||||
index: 80
|
||||
encoding: 0b1000000000000010
|
||||
mask: 0b1111000001111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 16
|
||||
branch: true
|
||||
delay: 1
|
||||
- CADD:
|
||||
__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
|
||||
- CJALR:
|
||||
C__JALR:
|
||||
index: 83
|
||||
encoding: 0b1001000000000010
|
||||
mask: 0b1111000001111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 16
|
||||
branch: true
|
||||
delay: 1
|
||||
- CEBREAK:
|
||||
C__EBREAK:
|
||||
index: 84
|
||||
encoding: 0b1001000000000010
|
||||
mask: 0b1111111111111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSWSP:
|
||||
C__SWSP:
|
||||
index: 85
|
||||
encoding: 0b1100000000000010
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- DII:
|
||||
DII:
|
||||
index: 86
|
||||
encoding: 0b0000000000000000
|
||||
mask: 0b1111111111111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
624
contrib/instr/TGC5C_slow.yaml
Normal file
624
contrib/instr/TGC5C_slow.yaml
Normal file
@ -0,0 +1,624 @@
|
||||
|
||||
RV32I:
|
||||
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,2]
|
||||
BEQ:
|
||||
index: 4
|
||||
encoding: 0b00000000000000000000000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,2]
|
||||
BNE:
|
||||
index: 5
|
||||
encoding: 0b00000000000000000001000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,2]
|
||||
BLT:
|
||||
index: 6
|
||||
encoding: 0b00000000000000000100000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,2]
|
||||
BGE:
|
||||
index: 7
|
||||
encoding: 0b00000000000000000101000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,2]
|
||||
BLTU:
|
||||
index: 8
|
||||
encoding: 0b00000000000000000110000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,2]
|
||||
BGEU:
|
||||
index: 9
|
||||
encoding: 0b00000000000000000111000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,2]
|
||||
LB:
|
||||
index: 10
|
||||
encoding: 0b00000000000000000000000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 2
|
||||
LH:
|
||||
index: 11
|
||||
encoding: 0b00000000000000000001000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 2
|
||||
LW:
|
||||
index: 12
|
||||
encoding: 0b00000000000000000010000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 2
|
||||
LBU:
|
||||
index: 13
|
||||
encoding: 0b00000000000000000100000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 2
|
||||
LHU:
|
||||
index: 14
|
||||
encoding: 0b00000000000000000101000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 2
|
||||
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: "u_24:20"
|
||||
SRLI:
|
||||
index: 25
|
||||
encoding: 0b00000000000000000101000000010011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: "u_24:20"
|
||||
SRAI:
|
||||
index: 26
|
||||
encoding: 0b01000000000000000101000000010011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: "u_24:20"
|
||||
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: "X_24:20"
|
||||
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: "X_24:20"
|
||||
SRA:
|
||||
index: 34
|
||||
encoding: 0b01000000000000000101000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: "X_24:20"
|
||||
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
|
||||
RV32M:
|
||||
MUL:
|
||||
index: 49
|
||||
encoding: 0b00000010000000000000000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 32
|
||||
MULH:
|
||||
index: 50
|
||||
encoding: 0b00000010000000000001000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 32
|
||||
MULHSU:
|
||||
index: 51
|
||||
encoding: 0b00000010000000000010000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 32
|
||||
MULHU:
|
||||
index: 52
|
||||
encoding: 0b00000010000000000011000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 32
|
||||
DIV:
|
||||
index: 53
|
||||
encoding: 0b00000010000000000100000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 33
|
||||
DIVU:
|
||||
index: 54
|
||||
encoding: 0b00000010000000000101000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 33
|
||||
REM:
|
||||
index: 55
|
||||
encoding: 0b00000010000000000110000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 33
|
||||
REMU:
|
||||
index: 56
|
||||
encoding: 0b00000010000000000111000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 33
|
||||
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: 2
|
||||
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: "u_12:12*16+u_6:2"
|
||||
C__SRAI:
|
||||
index: 68
|
||||
encoding: 0b1000010000000001
|
||||
mask: 0b1111110000000011
|
||||
attributes: [[name:enable, value:1]]
|
||||
size: 16
|
||||
branch: false
|
||||
delay: "u_12:12*16+u_6:2"
|
||||
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,2]
|
||||
C__BNEZ:
|
||||
index: 76
|
||||
encoding: 0b1110000000000001
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: true
|
||||
delay: [1,2]
|
||||
C__SLLI:
|
||||
index: 77
|
||||
encoding: 0b0000000000000010
|
||||
mask: 0b1111000000000011
|
||||
attributes: [[name:enable, value:1]]
|
||||
size: 16
|
||||
branch: false
|
||||
delay: "u_12:12*16+u_6:2"
|
||||
C__LWSP:
|
||||
index: 78
|
||||
encoding: 0b0100000000000010
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 2
|
||||
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
|
||||
|
@ -19,7 +19,7 @@ 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
|
||||
cd dbt-rise-tgc/contrib/pa
|
||||
# import the TGC core itself
|
||||
pct tgc_import_tb.tcl
|
||||
```
|
||||
@ -37,7 +37,7 @@ 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
|
||||
cd dbt-rise-tgc/contrib/pa
|
||||
# import the TGC core itself
|
||||
pct tgc_import_tb.tcl
|
||||
```
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@ -1,8 +1,8 @@
|
||||
import "ISA/RV32I.core_desc"
|
||||
import "ISA/RVI.core_desc"
|
||||
import "ISA/RVM.core_desc"
|
||||
import "ISA/RVC.core_desc"
|
||||
|
||||
Core TGC_C provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
|
||||
Core TGC5C provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
|
||||
architectural_state {
|
||||
XLEN=32;
|
||||
// definitions for the architecture wrapper
|
@ -70,7 +70,7 @@ uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
|
||||
return reinterpret_cast<uint8_t*>(®);
|
||||
}
|
||||
|
||||
${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
|
||||
${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &addr) {
|
||||
return phys_addr_t(addr.access, addr.space, addr.val&traits<${coreDef.name.toLowerCase()}>::addr_mask);
|
||||
}
|
||||
|
||||
|
@ -30,8 +30,6 @@
|
||||
*
|
||||
*******************************************************************************/
|
||||
<%
|
||||
import com.minres.coredsl.util.BigIntegerWithRadix
|
||||
|
||||
def nativeTypeSize(int size){
|
||||
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
|
||||
}
|
||||
@ -57,10 +55,7 @@ def byteSize(int size){
|
||||
return 128;
|
||||
}
|
||||
def getCString(def val){
|
||||
if(val instanceof BigIntegerWithRadix)
|
||||
return ((BigIntegerWithRadix)val).toCString()
|
||||
else
|
||||
return val.toString()
|
||||
return val.toString()+'ULL'
|
||||
}
|
||||
%>
|
||||
#ifndef _${coreDef.name.toUpperCase()}_H_
|
||||
@ -81,10 +76,10 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
|
||||
constexpr static char const* const core_type = "${coreDef.name}";
|
||||
|
||||
static constexpr std::array<const char*, ${registers.size}> reg_names{
|
||||
{"${registers.collect{it.name}.join('", "')}"}};
|
||||
{"${registers.collect{it.name.toLowerCase()}.join('", "')}"}};
|
||||
|
||||
static constexpr std::array<const char*, ${registers.size}> reg_aliases{
|
||||
{"${registers.collect{it.alias}.join('", "')}"}};
|
||||
{"${registers.collect{it.alias.toLowerCase()}.join('", "')}"}};
|
||||
|
||||
enum constants {${constants.collect{c -> c.name+"="+getCString(c.value)}.join(', ')}};
|
||||
|
||||
@ -116,7 +111,7 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
|
||||
|
||||
enum mem_type_e { ${spaces.collect{it.name}.join(', ')} };
|
||||
|
||||
enum class opcode_e : unsigned short {<%instructions.eachWithIndex{instr, index -> %>
|
||||
enum class opcode_e {<%instructions.eachWithIndex{instr, index -> %>
|
||||
${instr.instruction.name} = ${index},<%}%>
|
||||
MAX_OPCODE
|
||||
};
|
||||
@ -142,14 +137,6 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
|
||||
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; }
|
||||
|
@ -1,86 +0,0 @@
|
||||
#include "${coreDef.name.toLowerCase()}.h"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
namespace {
|
||||
// according to
|
||||
// https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
|
||||
#ifdef __GCC__
|
||||
constexpr size_t bit_count(uint32_t u) { return __builtin_popcount(u); }
|
||||
#elif __cplusplus < 201402L
|
||||
constexpr size_t uCount(uint32_t u) { return u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); }
|
||||
constexpr size_t bit_count(uint32_t u) { return ((uCount(u) + (uCount(u) >> 3)) & 030707070707) % 63; }
|
||||
#else
|
||||
constexpr size_t bit_count(uint32_t u) {
|
||||
size_t uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
|
||||
return ((uCount + (uCount >> 3)) & 030707070707) % 63;
|
||||
}
|
||||
#endif
|
||||
|
||||
using opcode_e = traits<${coreDef.name.toLowerCase()}>::opcode_e;
|
||||
|
||||
/****************************************************************************
|
||||
* start opcode definitions
|
||||
****************************************************************************/
|
||||
struct instruction_desriptor {
|
||||
size_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
opcode_e op;
|
||||
};
|
||||
|
||||
const std::array<instruction_desriptor, ${instructions.size}> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, opcode_e::${instr.instruction.name}},<%}%>
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct instruction_decoder<${coreDef.name.toLowerCase()}> {
|
||||
using opcode_e = traits<${coreDef.name.toLowerCase()}>::opcode_e;
|
||||
using code_word_t=traits<${coreDef.name.toLowerCase()}>::code_word_t;
|
||||
|
||||
struct instruction_pattern {
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
opcode_e id;
|
||||
};
|
||||
|
||||
std::array<std::vector<instruction_pattern>, 4> qlut;
|
||||
|
||||
template<typename T>
|
||||
unsigned decode_instruction(T);
|
||||
|
||||
instruction_decoder() {
|
||||
for (auto instr : instr_descr) {
|
||||
auto quadrant = instr.value & 0x3;
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
unsigned instruction_decoder<${coreDef.name.toLowerCase()}>::decode_instruction<traits<${coreDef.name.toLowerCase()}>::code_word_t>(traits<${coreDef.name.toLowerCase()}>::code_word_t instr){
|
||||
auto res = std::find_if(std::begin(qlut[instr&0x3]), std::end(qlut[instr&0x3]), [instr](instruction_pattern const& e){
|
||||
return !((instr&e.mask) ^ e.value );
|
||||
});
|
||||
return static_cast<unsigned>(res!=std::end(qlut[instr&0x3])? res->id : opcode_e::MAX_OPCODE);
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<instruction_decoder<${coreDef.name.toLowerCase()}>> traits<${coreDef.name.toLowerCase()}>::get_decoder(){
|
||||
return std::make_unique<instruction_decoder<${coreDef.name.toLowerCase()}>>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -8,9 +8,10 @@
|
||||
instrGroups[groupName]+=it;
|
||||
}
|
||||
instrGroups
|
||||
}%><%getInstructionGroups().each{name, instrList -> %>
|
||||
${name}: <% instrList.findAll{!it.instruction.name.startsWith("__")}.each { %>
|
||||
- ${it.instruction.name}:
|
||||
}%><%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}<%}%>
|
||||
|
130
gen_input/templates/CORENAME_sysc.cpp.gtl
Normal file
130
gen_input/templates/CORENAME_sysc.cpp.gtl
Normal file
@ -0,0 +1,130 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#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
|
||||
}
|
280
gen_input/templates/asmjit/CORENAME.cpp.gtl
Normal file
280
gen_input/templates/asmjit/CORENAME.cpp.gtl
Normal file
@ -0,0 +1,280 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#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>
|
||||
#include <fp_functions.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 vm_base<ARCH>::get_reg_ptr;
|
||||
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;
|
||||
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
||||
|
||||
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);
|
||||
}
|
||||
#include "helper_func.h"
|
||||
|
||||
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 */
|
||||
}
|
||||
x86::Compiler& cc = jh.cc;
|
||||
//ideally only do this if necessary (someone / plugin needs it)
|
||||
cc.mov(jh.pc,PC);
|
||||
cc.comment(fmt::format("\\n${instr.name}_{:#x}:",pc.val).c_str());
|
||||
this->gen_sync(jh, PRE_SYNC, ${idx});
|
||||
pc=pc+ ${instr.length/8};
|
||||
|
||||
gen_instr_prologue(jh, pc.val);
|
||||
cc.comment("\\n//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 ) {
|
||||
|
||||
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) {
|
||||
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>
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // 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 asmjit
|
||||
} // namespace iss
|
||||
|
||||
#include <iss/factory.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/riscv_hart_mu_p.h>
|
||||
namespace iss {
|
||||
namespace {
|
||||
volatile std::array<bool, 2> dummy = {
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|asmjit", [](unsigned port, void*) -> 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);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
}),
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|asmjit", [](unsigned port, void*) -> 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);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
@ -30,22 +30,21 @@
|
||||
*
|
||||
*******************************************************************************/
|
||||
<%
|
||||
import com.minres.coredsl.util.BigIntegerWithRadix
|
||||
|
||||
def nativeTypeSize(int size){
|
||||
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
|
||||
}
|
||||
%>
|
||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||
#include <iss/debugger/gdb_session.h>
|
||||
#include <iss/debugger/server.h>
|
||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/iss.h>
|
||||
#include <iss/interp/vm_base.h>
|
||||
#include <util/logging.h>
|
||||
#include <sstream>
|
||||
#include <boost/coroutine2/all.hpp>
|
||||
#include <functional>
|
||||
#include <exception>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
#define FMT_HEADER_ONLY
|
||||
@ -62,6 +61,10 @@ using namespace iss::arch;
|
||||
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> {
|
||||
public:
|
||||
using traits = arch::traits<ARCH>;
|
||||
@ -94,30 +97,9 @@ protected:
|
||||
|
||||
inline const char *name(size_t index){return index<traits::reg_aliases.size()?traits::reg_aliases[index]:"illegal";}
|
||||
|
||||
typename arch::traits<ARCH>::opcode_e decode_inst_id(code_word_t instr);
|
||||
virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
|
||||
|
||||
// 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(static_cast<uint32_t>(EXTR_MASK32)),
|
||||
LUT_SIZE_C = 1 << util::bit_count(static_cast<uint32_t>(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;
|
||||
typename arch::traits<ARCH>::opcode_e id;
|
||||
};
|
||||
|
||||
std::array<std::vector<instruction_pattern>, 4> qlut;
|
||||
|
||||
inline void raise(uint16_t trap_id, uint16_t cause){
|
||||
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
|
||||
@ -161,30 +143,96 @@ private:
|
||||
/****************************************************************************
|
||||
* start opcode definitions
|
||||
****************************************************************************/
|
||||
struct InstructionDesriptor {
|
||||
struct instruction_descriptor {
|
||||
size_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
typename arch::traits<ARCH>::opcode_e 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){}
|
||||
};
|
||||
|
||||
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
||||
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 -> %>
|
||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%>
|
||||
}};
|
||||
|
||||
//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;
|
||||
//}
|
||||
if(this->core.has_mmu()) {
|
||||
auto phys_pc = this->core.virt2phys(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;
|
||||
// }
|
||||
} else {
|
||||
if (this->core.read(phys_addr_t(pc.access, pc.space, pc.val), 4, data) != iss::Ok)
|
||||
return iss::Err;
|
||||
|
||||
}
|
||||
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) {
|
||||
@ -211,16 +259,11 @@ constexpr size_t bit_count(uint32_t u) {
|
||||
template <typename ARCH>
|
||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
|
||||
: vm_base<ARCH>(core, core_id, cluster_id) {
|
||||
unsigned id=0;
|
||||
for (auto instr : instr_descr) {
|
||||
auto quadrant = instr.value & 0x3;
|
||||
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);
|
||||
});
|
||||
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);
|
||||
}
|
||||
|
||||
inline bool is_count_limit_enabled(finish_cond_e cond){
|
||||
@ -231,14 +274,6 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){
|
||||
return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF;
|
||||
}
|
||||
|
||||
template <typename ARCH>
|
||||
typename arch::traits<ARCH>::opcode_e vm_impl<ARCH>::decode_inst_id(code_word_t instr){
|
||||
for(auto& e: qlut[instr&0x3]){
|
||||
if(!((instr&e.mask) ^ e.value )) return e.id;
|
||||
}
|
||||
return arch::traits<ARCH>::opcode_e::MAX_OPCODE;
|
||||
}
|
||||
|
||||
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){
|
||||
auto pc=start;
|
||||
@ -260,32 +295,34 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
|
||||
} else {
|
||||
if (is_jump_to_self_enabled(cond) &&
|
||||
(instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
auto inst_id = decode_inst_id(instr);
|
||||
auto inst_id = decode_instr(root, instr);
|
||||
// pre execution stuff
|
||||
this->core.reg.last_branch = 0;
|
||||
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
|
||||
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{%>
|
||||
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);
|
||||
}
|
||||
// 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}<%}%>
|
||||
TRAP_${instr.name}: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));
|
||||
@ -307,7 +344,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
|
||||
return pc;
|
||||
}
|
||||
|
||||
}
|
||||
} // 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) {
|
||||
@ -317,3 +354,25 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
|
||||
}
|
||||
} // namespace interp
|
||||
} // namespace iss
|
||||
|
||||
#include <iss/factory.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/riscv_hart_mu_p.h>
|
||||
namespace iss {
|
||||
namespace {
|
||||
volatile std::array<bool, 2> dummy = {
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void*) -> 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);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
}),
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void*) -> 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);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -30,10 +30,9 @@
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||
#include <iss/debugger/gdb_session.h>
|
||||
#include <iss/debugger/server.h>
|
||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/iss.h>
|
||||
#include <iss/llvm/vm_base.h>
|
||||
#include <util/logging.h>
|
||||
@ -59,6 +58,7 @@ 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;
|
||||
@ -81,7 +81,7 @@ public:
|
||||
protected:
|
||||
using vm_base<ARCH>::get_reg_ptr;
|
||||
|
||||
inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}
|
||||
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()));
|
||||
@ -89,7 +89,7 @@ protected:
|
||||
|
||||
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);
|
||||
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) {
|
||||
@ -111,92 +111,74 @@ protected:
|
||||
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);
|
||||
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<ARCH>::XLEN, pc.val),
|
||||
this->get_type(traits<ARCH>::XLEN));
|
||||
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
|
||||
// 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;
|
||||
}
|
||||
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 InstructionDesriptor {
|
||||
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){}
|
||||
};
|
||||
|
||||
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
||||
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} */
|
||||
{${instr.length}, ${instr.value}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
||||
/* 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){<%instr.code.eachLine{%>
|
||||
${it}<%}%>
|
||||
std::tuple<continuation_e, BasicBlock*> __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){
|
||||
bb->setName(fmt::format("${instr.name}_0x{:X}",pc.val));
|
||||
this->gen_sync(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 = this->gen_const(32,pc.val);
|
||||
pc=pc+ ${instr.length/8};
|
||||
this->gen_set_pc(pc, traits::NEXT_PC);
|
||||
<%instr.behavior.eachLine{%>${it}
|
||||
<%}%>
|
||||
this->gen_trap_check(bb);
|
||||
this->gen_sync(POST_SYNC, ${idx});
|
||||
this->builder.CreateBr(bb);
|
||||
return returnValue;
|
||||
}
|
||||
<%}%>
|
||||
/****************************************************************************
|
||||
@ -204,23 +186,75 @@ private:
|
||||
****************************************************************************/
|
||||
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.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(get_reg_ptr(traits<ARCH>::ICOUNT), true),
|
||||
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<ARCH>::ICOUNT), true);
|
||||
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_trap_check(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 insn) {
|
||||
volatile CODE_WORD x = insn;
|
||||
insn = 2 * x;
|
||||
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()); }
|
||||
@ -228,14 +262,11 @@ 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);
|
||||
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>
|
||||
@ -243,49 +274,50 @@ 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;
|
||||
code_word_t instr = 0;
|
||||
// const typename traits::addr_t upper_bits = ~traits::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 *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 (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
// }
|
||||
if (instr == 0x0000006f || (instr&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];
|
||||
auto f = decode_instr(root, instr);
|
||||
if (f == nullptr) {
|
||||
f = &this_class::illegal_intruction;
|
||||
}
|
||||
return (this->*f)(pc, insn, this_block);
|
||||
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(get_reg_ptr(arch::traits<ARCH>::NEXT_PC), false));
|
||||
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<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);
|
||||
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<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);
|
||||
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) {
|
||||
@ -295,22 +327,25 @@ template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
|
||||
|
||||
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->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<ARCH>::LAST_BRANCH), false);
|
||||
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(get_reg_ptr(traits<ARCH>::PC), false))};
|
||||
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(get_reg_ptr(traits<ARCH>::NEXT_PC), false);
|
||||
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> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *bb) {
|
||||
auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::TRAP_STATE), true);
|
||||
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))),
|
||||
bb, this->trap_blk, 1);
|
||||
target_bb, this->trap_blk, 1);
|
||||
this->builder.SetInsertPoint(target_bb);
|
||||
}
|
||||
|
||||
} // namespace ${coreDef.name.toLowerCase()}
|
||||
@ -323,3 +358,25 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
|
||||
}
|
||||
} // namespace llvm
|
||||
} // namespace iss
|
||||
|
||||
#include <iss/factory.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/riscv_hart_mu_p.h>
|
||||
namespace iss {
|
||||
namespace {
|
||||
volatile std::array<bool, 2> dummy = {
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|llvm", [](unsigned port, void*) -> 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);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
}),
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|llvm", [](unsigned port, void*) -> 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);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"${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}
|
||||
}<%}%>
|
||||
]
|
||||
}
|
@ -1,223 +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.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
<%
|
||||
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_ */
|
@ -1,107 +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.
|
||||
*
|
||||
*******************************************************************************/
|
||||
<%
|
||||
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*>(®);
|
||||
}
|
||||
|
||||
${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
|
||||
}
|
||||
|
@ -31,7 +31,6 @@
|
||||
*******************************************************************************/
|
||||
|
||||
#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>
|
||||
@ -121,57 +120,7 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
// 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(static_cast<uint32_t>(EXTR_MASK32)), LUT_SIZE_C = 1 << util::bit_count(static_cast<uint32_t>(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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
|
||||
inline S sext(U from) {
|
||||
auto mask = (1ULL<<W) - 1;
|
||||
@ -183,14 +132,23 @@ private:
|
||||
/****************************************************************************
|
||||
* start opcode definitions
|
||||
****************************************************************************/
|
||||
struct InstructionDesriptor {
|
||||
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){}
|
||||
};
|
||||
|
||||
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
||||
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)}},<%}%>
|
||||
@ -201,19 +159,21 @@ private:
|
||||
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){
|
||||
tu("${instr.name}_{:#010x}:", pc.val);
|
||||
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+4;
|
||||
pc=pc+ ${instr.length/8};
|
||||
gen_set_pc(tu, pc, traits::NEXT_PC);
|
||||
tu.open_scope();<%instr.behavior.eachLine{%>
|
||||
${it}<%}%>
|
||||
tu.open_scope();
|
||||
<%instr.behavior.eachLine{%>${it}
|
||||
<%}%>
|
||||
tu.close_scope();
|
||||
gen_trap_check(tu);
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
|
||||
gen_trap_check(tu);
|
||||
return returnValue;
|
||||
}
|
||||
<%}%>
|
||||
@ -228,11 +188,64 @@ private:
|
||||
vm_impl::gen_trap_check(tu);
|
||||
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 insn) {
|
||||
volatile CODE_WORD x = insn;
|
||||
insn = 2 * x;
|
||||
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()); }
|
||||
@ -240,14 +253,11 @@ 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);
|
||||
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>
|
||||
@ -255,11 +265,11 @@ std::tuple<continuation_e>
|
||||
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
|
||||
enum {TRAP_ID=1<<16};
|
||||
code_word_t insn = 0;
|
||||
// const typename traits::addr_t upper_bits = ~traits::PGMASK;
|
||||
code_word_t instr = 0;
|
||||
phys_addr_t paddr(pc);
|
||||
auto *const data = (uint8_t *)&insn;
|
||||
paddr = this->core.v2p(pc);
|
||||
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);
|
||||
@ -267,18 +277,17 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
||||
// res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
|
||||
// }
|
||||
// } else {
|
||||
auto res = this->core.read(paddr, 4, data);
|
||||
auto res = this->core.read(paddr, 4, reinterpret_cast<uint8_t*>(&instr));
|
||||
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'
|
||||
if (instr == 0x0000006f || (instr&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];
|
||||
auto f = decode_instr(root, instr);
|
||||
if (f == nullptr) {
|
||||
f = &this_class::illegal_intruction;
|
||||
}
|
||||
return (this->*f)(pc, insn, tu);
|
||||
return (this->*f)(pc, instr, tu);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
|
||||
@ -297,12 +306,13 @@ 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) {
|
||||
tu("trap_entry:");
|
||||
this->gen_sync(tu, POST_SYNC, -1);
|
||||
tu("enter_trap(core_ptr, *trap_state, *pc, 0);");
|
||||
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(),32));
|
||||
tu("return *next_pc;");
|
||||
}
|
||||
|
||||
} // namespace mnrv32
|
||||
} // 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) {
|
||||
@ -310,5 +320,27 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
|
||||
return std::unique_ptr<vm_if>(ret);
|
||||
}
|
||||
}
|
||||
} // namesapce tcc
|
||||
} // namespace iss
|
||||
|
||||
#include <iss/factory.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/riscv_hart_mu_p.h>
|
||||
namespace iss {
|
||||
namespace {
|
||||
volatile std::array<bool, 2> dummy = {
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void*) -> 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);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
}),
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void*) -> 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);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
3
src-gen/.gitignore
vendored
3
src-gen/.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
/iss
|
||||
/vm
|
||||
/vm
|
||||
/sysc
|
@ -46,7 +46,7 @@ public:
|
||||
using this_class = hwl<BASE>;
|
||||
using reg_t = typename BASE::reg_t;
|
||||
|
||||
hwl();
|
||||
hwl(feature_config cfg = feature_config{});
|
||||
virtual ~hwl() = default;
|
||||
|
||||
protected:
|
||||
@ -56,7 +56,7 @@ protected:
|
||||
|
||||
|
||||
template<typename BASE>
|
||||
inline hwl<BASE>::hwl() {
|
||||
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);
|
||||
|
@ -226,6 +226,8 @@ struct feature_config {
|
||||
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 {
|
||||
|
@ -304,9 +304,9 @@ protected:
|
||||
*/
|
||||
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
||||
|
||||
uint64_t get_pc() override { return arch.reg.PC; };
|
||||
uint64_t get_pc() override { return arch.reg.PC; }
|
||||
|
||||
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
|
||||
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; }
|
||||
|
||||
uint64_t get_instr_word() override { return arch.reg.instruction; }
|
||||
|
||||
@ -316,9 +316,11 @@ protected:
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||
|
||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }
|
||||
|
||||
bool is_branch_taken() override { return arch.reg.last_branch; };
|
||||
bool is_branch_taken() override { return arch.reg.last_branch; }
|
||||
|
||||
unsigned get_reg_num() override {return traits<BASE>::NUM_REGS;}
|
||||
|
||||
riscv_hart_m_p<BASE, FEAT> &arch;
|
||||
};
|
||||
@ -619,9 +621,9 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
|
||||
}
|
||||
return std::make_pair(entry, true);
|
||||
}
|
||||
throw std::runtime_error("memory load file is not a valid elf file");
|
||||
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file",name));
|
||||
}
|
||||
throw std::runtime_error("memory load file not found");
|
||||
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
@ -666,7 +668,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
phys_addr_t phys_addr{access, space, addr};
|
||||
auto res = iss::Err;
|
||||
if(access != access_type::FETCH && memfn_range.size()){
|
||||
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||
@ -680,7 +682,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||
} else {
|
||||
res = hart_mem_rd_delegate( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)){
|
||||
if (unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)){
|
||||
this->reg.trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
fault_data=addr;
|
||||
}
|
||||
@ -759,7 +761,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
phys_addr_t phys_addr{access, space, addr};
|
||||
auto res = iss::Err;
|
||||
if(access != access_type::FETCH && memfn_range.size()){
|
||||
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||
@ -773,7 +775,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
} else {
|
||||
res = write_mem( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)) {
|
||||
if (unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) {
|
||||
this->reg.trap_state = (1UL << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
fault_data=addr;
|
||||
}
|
||||
@ -784,9 +786,8 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
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) {
|
||||
if ((addr + length) > mem.size()) return iss::Err;
|
||||
switch (addr) {
|
||||
case 0x10013000: // UART0 base, TXFIFO reg
|
||||
case 0x10023000: // UART1 base, TXFIFO reg
|
||||
uart_buf << (char)data[0];
|
||||
@ -798,16 +799,16 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
}
|
||||
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;
|
||||
auto &p = mem(addr / mem.page_size);
|
||||
auto offs = addr & 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;
|
||||
auto &p = mem(addr / mem.page_size);
|
||||
auto offs = addr & 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
|
||||
@ -1114,8 +1115,10 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
|
||||
}
|
||||
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim=hostvar;
|
||||
#ifndef WITH_TCC
|
||||
throw(iss::simulation_stopped(hostvar));
|
||||
#endif
|
||||
break;
|
||||
//throw(iss::simulation_stopped(hostvar));
|
||||
case 0x0101: {
|
||||
char c = static_cast<char>(hostvar & 0xff);
|
||||
if (c == '\n' || c == 0) {
|
||||
|
@ -286,7 +286,7 @@ public:
|
||||
return m[mode];
|
||||
}
|
||||
|
||||
riscv_hart_msu_vp();
|
||||
riscv_hart_msu_vp(feature_config cfg = feature_config{});
|
||||
virtual ~riscv_hart_msu_vp() = default;
|
||||
|
||||
void reset(uint64_t address) override;
|
||||
@ -331,9 +331,9 @@ protected:
|
||||
*/
|
||||
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
||||
|
||||
uint64_t get_pc() override { return arch.reg.PC; };
|
||||
uint64_t get_pc() override { return arch.reg.PC; }
|
||||
|
||||
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
|
||||
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; }
|
||||
|
||||
uint64_t get_instr_word() override { return arch.reg.instruction; }
|
||||
|
||||
@ -343,9 +343,11 @@ protected:
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||
|
||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }
|
||||
|
||||
bool is_branch_taken() override { return arch.reg.last_branch; };
|
||||
bool is_branch_taken() override { return arch.reg.last_branch; }
|
||||
|
||||
unsigned get_reg_num() override {return traits<BASE>::NUM_REGS; }
|
||||
|
||||
riscv_hart_msu_vp<BASE> &arch;
|
||||
};
|
||||
@ -430,6 +432,7 @@ template <typename BASE>
|
||||
riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
|
||||
: state()
|
||||
, instr_if(*this) {
|
||||
this->_has_mmu = true;
|
||||
// reset values
|
||||
csr[misa] = traits<BASE>::MISA_VAL;
|
||||
csr[mvendorid] = 0x669;
|
||||
@ -588,9 +591,9 @@ template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load
|
||||
}
|
||||
return std::make_pair(entry, true);
|
||||
}
|
||||
throw std::runtime_error("memory load file is not a valid elf file");
|
||||
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file",name));
|
||||
}
|
||||
throw std::runtime_error("memory load file not found");
|
||||
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
|
||||
}
|
||||
|
||||
template <typename BASE>
|
||||
@ -632,10 +635,8 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
||||
return res;
|
||||
}
|
||||
}
|
||||
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)){
|
||||
auto res = read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
||||
if (unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)){
|
||||
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
fault_data=addr;
|
||||
}
|
||||
@ -719,6 +720,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
try {
|
||||
if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary
|
||||
vm_info vm = hart_state_type::decode_vm_info(this->reg.PRIV, state.satp);
|
||||
@ -731,10 +733,8 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
return res;
|
||||
}
|
||||
}
|
||||
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)) {
|
||||
auto res = write_mem(paddr, length, data);
|
||||
if (unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) {
|
||||
this->reg.trap_state = (1UL << 31) | (7UL << 16); // issue trap 7 (Store/AMO access fault)
|
||||
fault_data=addr;
|
||||
}
|
||||
@ -745,7 +745,6 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
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
|
||||
|
@ -329,9 +329,9 @@ protected:
|
||||
*/
|
||||
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
||||
|
||||
uint64_t get_pc() override { return arch.reg.PC; };
|
||||
uint64_t get_pc() override { return arch.reg.PC; }
|
||||
|
||||
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
|
||||
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; }
|
||||
|
||||
uint64_t get_instr_word() override { return arch.reg.instruction; }
|
||||
|
||||
@ -341,9 +341,11 @@ protected:
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||
|
||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }
|
||||
|
||||
bool is_branch_taken() override { return arch.reg.last_branch; };
|
||||
bool is_branch_taken() override { return arch.reg.last_branch; }
|
||||
|
||||
unsigned get_reg_num() override {return traits<BASE>::NUM_REGS; }
|
||||
|
||||
riscv_hart_mu_p<BASE, FEAT> &arch;
|
||||
};
|
||||
@ -690,9 +692,9 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
|
||||
}
|
||||
return std::make_pair(entry, true);
|
||||
}
|
||||
throw std::runtime_error("memory load file is not a valid elf file");
|
||||
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file",name));
|
||||
}
|
||||
throw std::runtime_error("memory load file not found");
|
||||
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
@ -834,7 +836,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
phys_addr_t phys_addr{access, space, addr};
|
||||
auto res = iss::Err;
|
||||
if(!is_fetch(access) && memfn_range.size()){
|
||||
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||
@ -848,7 +850,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||
} else {
|
||||
res = hart_mem_rd_delegate( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)){
|
||||
if (unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)){
|
||||
this->reg.trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
fault_data=addr;
|
||||
}
|
||||
@ -935,7 +937,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
phys_addr_t phys_addr{access, space, addr};
|
||||
auto res = iss::Err;
|
||||
if(!is_fetch(access) && memfn_range.size()){
|
||||
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||
@ -949,7 +951,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||
} else {
|
||||
res = hart_mem_wr_delegate( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)) {
|
||||
if (unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) {
|
||||
this->reg.trap_state = (1UL << 31) | (7UL << 16); // issue trap 7 (Store/AMO access fault)
|
||||
fault_data=addr;
|
||||
}
|
||||
@ -960,30 +962,29 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||
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) {
|
||||
if ((addr + length) > mem.size()) return iss::Err;
|
||||
switch (addr) {
|
||||
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
|
||||
// LOG(INFO)<<"UART"<<((addr>>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;
|
||||
auto &p = mem(addr / mem.page_size);
|
||||
auto offs = addr & 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;
|
||||
auto &p = mem(addr / mem.page_size);
|
||||
auto offs = addr & 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
|
||||
|
@ -30,7 +30,7 @@
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include "tgc_c.h"
|
||||
#include "tgc5c.h"
|
||||
#include "util/ities.h"
|
||||
#include <util/logging.h>
|
||||
#include <cstdio>
|
||||
@ -39,18 +39,18 @@
|
||||
|
||||
using namespace iss::arch;
|
||||
|
||||
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_names;
|
||||
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, 43> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, 43> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
|
||||
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc5c>::reg_names;
|
||||
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc5c>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, 43> iss::arch::traits<iss::arch::tgc5c>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, 43> iss::arch::traits<iss::arch::tgc5c>::reg_byte_offsets;
|
||||
|
||||
tgc_c::tgc_c() = default;
|
||||
tgc5c::tgc5c() = default;
|
||||
|
||||
tgc_c::~tgc_c() = default;
|
||||
tgc5c::~tgc5c() = default;
|
||||
|
||||
void tgc_c::reset(uint64_t address) {
|
||||
auto base_ptr = reinterpret_cast<traits<tgc_c>::reg_t*>(get_regs_base_ptr());
|
||||
for(size_t i=0; i<traits<tgc_c>::NUM_REGS; ++i)
|
||||
void tgc5c::reset(uint64_t address) {
|
||||
auto base_ptr = reinterpret_cast<traits<tgc5c>::reg_t*>(get_regs_base_ptr());
|
||||
for(size_t i=0; i<traits<tgc5c>::NUM_REGS; ++i)
|
||||
*(base_ptr+i)=0;
|
||||
reg.PC=address;
|
||||
reg.NEXT_PC=reg.PC;
|
||||
@ -59,11 +59,11 @@ void tgc_c::reset(uint64_t address) {
|
||||
reg.icount=0;
|
||||
}
|
||||
|
||||
uint8_t *tgc_c::get_regs_base_ptr() {
|
||||
uint8_t *tgc5c::get_regs_base_ptr() {
|
||||
return reinterpret_cast<uint8_t*>(®);
|
||||
}
|
||||
|
||||
tgc_c::phys_addr_t tgc_c::virt2phys(const iss::addr_t &pc) {
|
||||
return phys_addr_t(pc); // change logical address to physical address
|
||||
tgc5c::phys_addr_t tgc5c::virt2phys(const iss::addr_t &addr) {
|
||||
return phys_addr_t(addr.access, addr.space, addr.val&traits<tgc5c>::addr_mask);
|
||||
}
|
||||
|
@ -30,8 +30,8 @@
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _TGC_C_H_
|
||||
#define _TGC_C_H_
|
||||
#ifndef _TGC5C_H_
|
||||
#define _TGC5C_H_
|
||||
|
||||
#include <array>
|
||||
#include <iss/arch/traits.h>
|
||||
@ -41,19 +41,19 @@
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
struct tgc_c;
|
||||
struct tgc5c;
|
||||
|
||||
template <> struct traits<tgc_c> {
|
||||
template <> struct traits<tgc5c> {
|
||||
|
||||
constexpr static char const* const core_type = "TGC_C";
|
||||
constexpr static char const* const core_type = "TGC5C";
|
||||
|
||||
static constexpr std::array<const char*, 36> 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", "dpc"}};
|
||||
|
||||
static constexpr std::array<const char*, 36> 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"}};
|
||||
{"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"}};
|
||||
|
||||
enum constants {MISA_VAL=0b01000000000000000001000100000100, MARCHID_VAL=0x80000003, XLEN=32, INSTR_ALIGNMENT=2, RFS=32, fence=0, fencei=1, fencevmal=2, fencevmau=3, CSR_SIZE=4096, MUL_LEN=64};
|
||||
enum constants {MISA_VAL=1073746180ULL, MARCHID_VAL=2147483651ULL, XLEN=32ULL, INSTR_ALIGNMENT=2ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevmal=2ULL, fencevmau=3ULL, CSR_SIZE=4096ULL, MUL_LEN=64ULL};
|
||||
|
||||
constexpr static unsigned FP_REGS_SIZE = 0;
|
||||
|
||||
@ -83,7 +83,7 @@ template <> struct traits<tgc_c> {
|
||||
|
||||
enum mem_type_e { MEM, FENCE, RES, CSR };
|
||||
|
||||
enum class opcode_e : unsigned short {
|
||||
enum class opcode_e {
|
||||
LUI = 0,
|
||||
AUIPC = 1,
|
||||
JAL = 2,
|
||||
@ -141,49 +141,49 @@ template <> struct traits<tgc_c> {
|
||||
DIVU = 54,
|
||||
REM = 55,
|
||||
REMU = 56,
|
||||
CADDI4SPN = 57,
|
||||
CLW = 58,
|
||||
CSW = 59,
|
||||
CADDI = 60,
|
||||
CNOP = 61,
|
||||
CJAL = 62,
|
||||
CLI = 63,
|
||||
CLUI = 64,
|
||||
CADDI16SP = 65,
|
||||
C__ADDI4SPN = 57,
|
||||
C__LW = 58,
|
||||
C__SW = 59,
|
||||
C__ADDI = 60,
|
||||
C__NOP = 61,
|
||||
C__JAL = 62,
|
||||
C__LI = 63,
|
||||
C__LUI = 64,
|
||||
C__ADDI16SP = 65,
|
||||
__reserved_clui = 66,
|
||||
CSRLI = 67,
|
||||
CSRAI = 68,
|
||||
CANDI = 69,
|
||||
CSUB = 70,
|
||||
CXOR = 71,
|
||||
COR = 72,
|
||||
CAND = 73,
|
||||
CJ = 74,
|
||||
CBEQZ = 75,
|
||||
CBNEZ = 76,
|
||||
CSLLI = 77,
|
||||
CLWSP = 78,
|
||||
CMV = 79,
|
||||
CJR = 80,
|
||||
C__SRLI = 67,
|
||||
C__SRAI = 68,
|
||||
C__ANDI = 69,
|
||||
C__SUB = 70,
|
||||
C__XOR = 71,
|
||||
C__OR = 72,
|
||||
C__AND = 73,
|
||||
C__J = 74,
|
||||
C__BEQZ = 75,
|
||||
C__BNEZ = 76,
|
||||
C__SLLI = 77,
|
||||
C__LWSP = 78,
|
||||
C__MV = 79,
|
||||
C__JR = 80,
|
||||
__reserved_cmv = 81,
|
||||
CADD = 82,
|
||||
CJALR = 83,
|
||||
CEBREAK = 84,
|
||||
CSWSP = 85,
|
||||
C__ADD = 82,
|
||||
C__JALR = 83,
|
||||
C__EBREAK = 84,
|
||||
C__SWSP = 85,
|
||||
DII = 86,
|
||||
MAX_OPCODE
|
||||
};
|
||||
};
|
||||
|
||||
struct tgc_c: public arch_if {
|
||||
struct tgc5c: public arch_if {
|
||||
|
||||
using virt_addr_t = typename traits<tgc_c>::virt_addr_t;
|
||||
using phys_addr_t = typename traits<tgc_c>::phys_addr_t;
|
||||
using reg_t = typename traits<tgc_c>::reg_t;
|
||||
using addr_t = typename traits<tgc_c>::addr_t;
|
||||
using virt_addr_t = typename traits<tgc5c>::virt_addr_t;
|
||||
using phys_addr_t = typename traits<tgc5c>::phys_addr_t;
|
||||
using reg_t = typename traits<tgc5c>::reg_t;
|
||||
using addr_t = typename traits<tgc5c>::addr_t;
|
||||
|
||||
tgc_c();
|
||||
~tgc_c();
|
||||
tgc5c();
|
||||
~tgc5c();
|
||||
|
||||
void reset(uint64_t address=0) override;
|
||||
|
||||
@ -195,14 +195,6 @@ struct tgc_c: public arch_if {
|
||||
|
||||
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 iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
||||
@ -211,7 +203,7 @@ struct tgc_c: public arch_if {
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct TGC_C_regs {
|
||||
struct TGC5C_regs {
|
||||
uint32_t X0 = 0;
|
||||
uint32_t X1 = 0;
|
||||
uint32_t X2 = 0;
|
||||
@ -267,4 +259,4 @@ struct tgc_c: public arch_if {
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* _TGC_C_H_ */
|
||||
#endif /* _TGC5C_H_ */
|
@ -1,175 +0,0 @@
|
||||
#include "tgc_c.h"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
namespace {
|
||||
// according to
|
||||
// https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
|
||||
#ifdef __GCC__
|
||||
constexpr size_t bit_count(uint32_t u) { return __builtin_popcount(u); }
|
||||
#elif __cplusplus < 201402L
|
||||
constexpr size_t uCount(uint32_t u) { return u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); }
|
||||
constexpr size_t bit_count(uint32_t u) { return ((uCount(u) + (uCount(u) >> 3)) & 030707070707) % 63; }
|
||||
#else
|
||||
constexpr size_t bit_count(uint32_t u) {
|
||||
size_t uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
|
||||
return ((uCount + (uCount >> 3)) & 030707070707) % 63;
|
||||
}
|
||||
#endif
|
||||
|
||||
using opcode_e = traits<tgc_c>::opcode_e;
|
||||
|
||||
/****************************************************************************
|
||||
* start opcode definitions
|
||||
****************************************************************************/
|
||||
struct instruction_desriptor {
|
||||
size_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
opcode_e op;
|
||||
};
|
||||
|
||||
const std::array<instruction_desriptor, 90> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */
|
||||
{32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, opcode_e::LUI},
|
||||
{32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, opcode_e::AUIPC},
|
||||
{32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, opcode_e::JAL},
|
||||
{32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, opcode_e::JALR},
|
||||
{32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, opcode_e::BEQ},
|
||||
{32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, opcode_e::BNE},
|
||||
{32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, opcode_e::BLT},
|
||||
{32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, opcode_e::BGE},
|
||||
{32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, opcode_e::BLTU},
|
||||
{32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, opcode_e::BGEU},
|
||||
{32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, opcode_e::LB},
|
||||
{32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, opcode_e::LH},
|
||||
{32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, opcode_e::LW},
|
||||
{32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, opcode_e::LBU},
|
||||
{32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, opcode_e::LHU},
|
||||
{32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, opcode_e::SB},
|
||||
{32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, opcode_e::SH},
|
||||
{32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, opcode_e::SW},
|
||||
{32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, opcode_e::ADDI},
|
||||
{32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, opcode_e::SLTI},
|
||||
{32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, opcode_e::SLTIU},
|
||||
{32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, opcode_e::XORI},
|
||||
{32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, opcode_e::ORI},
|
||||
{32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, opcode_e::ANDI},
|
||||
{32, 0b00000000000000000001000000010011, 0b11111110000000000111000001111111, opcode_e::SLLI},
|
||||
{32, 0b00000000000000000101000000010011, 0b11111110000000000111000001111111, opcode_e::SRLI},
|
||||
{32, 0b01000000000000000101000000010011, 0b11111110000000000111000001111111, opcode_e::SRAI},
|
||||
{32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::ADD},
|
||||
{32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::SUB},
|
||||
{32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, opcode_e::SLL},
|
||||
{32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, opcode_e::SLT},
|
||||
{32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, opcode_e::SLTU},
|
||||
{32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, opcode_e::XOR},
|
||||
{32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::SRL},
|
||||
{32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::SRA},
|
||||
{32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, opcode_e::OR},
|
||||
{32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, opcode_e::AND},
|
||||
{32, 0b00000000000000000000000000001111, 0b00000000000000000111000001111111, opcode_e::FENCE},
|
||||
{32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, opcode_e::ECALL},
|
||||
{32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, opcode_e::EBREAK},
|
||||
{32, 0b00000000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::URET},
|
||||
{32, 0b00010000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::SRET},
|
||||
{32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::MRET},
|
||||
{32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, opcode_e::WFI},
|
||||
{32, 0b01111011001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::DRET},
|
||||
{32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRW},
|
||||
{32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRS},
|
||||
{32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRC},
|
||||
{32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRWI},
|
||||
{32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRSI},
|
||||
{32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRCI},
|
||||
{32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, opcode_e::FENCE_I},
|
||||
{32, 0b00000010000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::MUL},
|
||||
{32, 0b00000010000000000001000000110011, 0b11111110000000000111000001111111, opcode_e::MULH},
|
||||
{32, 0b00000010000000000010000000110011, 0b11111110000000000111000001111111, opcode_e::MULHSU},
|
||||
{32, 0b00000010000000000011000000110011, 0b11111110000000000111000001111111, opcode_e::MULHU},
|
||||
{32, 0b00000010000000000100000000110011, 0b11111110000000000111000001111111, opcode_e::DIV},
|
||||
{32, 0b00000010000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::DIVU},
|
||||
{32, 0b00000010000000000110000000110011, 0b11111110000000000111000001111111, opcode_e::REM},
|
||||
{32, 0b00000010000000000111000000110011, 0b11111110000000000111000001111111, opcode_e::REMU},
|
||||
{16, 0b0000000000000000, 0b1110000000000011, opcode_e::CADDI4SPN},
|
||||
{16, 0b0100000000000000, 0b1110000000000011, opcode_e::CLW},
|
||||
{16, 0b1100000000000000, 0b1110000000000011, opcode_e::CSW},
|
||||
{16, 0b0000000000000001, 0b1110000000000011, opcode_e::CADDI},
|
||||
{16, 0b0000000000000001, 0b1110111110000011, opcode_e::CNOP},
|
||||
{16, 0b0010000000000001, 0b1110000000000011, opcode_e::CJAL},
|
||||
{16, 0b0100000000000001, 0b1110000000000011, opcode_e::CLI},
|
||||
{16, 0b0110000000000001, 0b1110000000000011, opcode_e::CLUI},
|
||||
{16, 0b0110000100000001, 0b1110111110000011, opcode_e::CADDI16SP},
|
||||
{16, 0b0110000000000001, 0b1111000001111111, opcode_e::__reserved_clui},
|
||||
{16, 0b1000000000000001, 0b1111110000000011, opcode_e::CSRLI},
|
||||
{16, 0b1000010000000001, 0b1111110000000011, opcode_e::CSRAI},
|
||||
{16, 0b1000100000000001, 0b1110110000000011, opcode_e::CANDI},
|
||||
{16, 0b1000110000000001, 0b1111110001100011, opcode_e::CSUB},
|
||||
{16, 0b1000110000100001, 0b1111110001100011, opcode_e::CXOR},
|
||||
{16, 0b1000110001000001, 0b1111110001100011, opcode_e::COR},
|
||||
{16, 0b1000110001100001, 0b1111110001100011, opcode_e::CAND},
|
||||
{16, 0b1010000000000001, 0b1110000000000011, opcode_e::CJ},
|
||||
{16, 0b1100000000000001, 0b1110000000000011, opcode_e::CBEQZ},
|
||||
{16, 0b1110000000000001, 0b1110000000000011, opcode_e::CBNEZ},
|
||||
{16, 0b0000000000000010, 0b1111000000000011, opcode_e::CSLLI},
|
||||
{16, 0b0100000000000010, 0b1110000000000011, opcode_e::CLWSP},
|
||||
{16, 0b1000000000000010, 0b1111000000000011, opcode_e::CMV},
|
||||
{16, 0b1000000000000010, 0b1111000001111111, opcode_e::CJR},
|
||||
{16, 0b1000000000000010, 0b1111111111111111, opcode_e::__reserved_cmv},
|
||||
{16, 0b1001000000000010, 0b1111000000000011, opcode_e::CADD},
|
||||
{16, 0b1001000000000010, 0b1111000001111111, opcode_e::CJALR},
|
||||
{16, 0b1001000000000010, 0b1111111111111111, opcode_e::CEBREAK},
|
||||
{16, 0b1100000000000010, 0b1110000000000011, opcode_e::CSWSP},
|
||||
{16, 0b0000000000000000, 0b1111111111111111, opcode_e::DII},
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct instruction_decoder<tgc_c> {
|
||||
using opcode_e = traits<tgc_c>::opcode_e;
|
||||
using code_word_t=traits<tgc_c>::code_word_t;
|
||||
|
||||
struct instruction_pattern {
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
opcode_e id;
|
||||
};
|
||||
|
||||
std::array<std::vector<instruction_pattern>, 4> qlut;
|
||||
|
||||
template<typename T>
|
||||
unsigned decode_instruction(T);
|
||||
|
||||
instruction_decoder() {
|
||||
for (auto instr : instr_descr) {
|
||||
auto quadrant = instr.value & 0x3;
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
unsigned instruction_decoder<tgc_c>::decode_instruction<traits<tgc_c>::code_word_t>(traits<tgc_c>::code_word_t instr){
|
||||
auto res = std::find_if(std::begin(qlut[instr&0x3]), std::end(qlut[instr&0x3]), [instr](instruction_pattern const& e){
|
||||
return !((instr&e.mask) ^ e.value );
|
||||
});
|
||||
return static_cast<unsigned>(res!=std::end(qlut[instr&0x3])? res->id : opcode_e::MAX_OPCODE);
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<instruction_decoder<tgc_c>> traits<tgc_c>::get_decoder(){
|
||||
return std::make_unique<instruction_decoder<tgc_c>>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -2,49 +2,49 @@
|
||||
#define _ISS_ARCH_TGC_MAPPER_H
|
||||
|
||||
#include "riscv_hart_m_p.h"
|
||||
#include "tgc_c.h"
|
||||
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
|
||||
#ifdef CORE_TGC_A
|
||||
#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/tgc_a.h>
|
||||
using tgc_a_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_a>;
|
||||
#include <iss/arch/tgc5a.h>
|
||||
using tgc5a_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc5a>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_B
|
||||
#ifdef CORE_TGC5B
|
||||
#include "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>;
|
||||
#include <iss/arch/tgc5b.h>
|
||||
using tgc5b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc5b>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_C_XRB_NN
|
||||
#ifdef CORE_TGC5C_XRB_NN
|
||||
#include "riscv_hart_m_p.h"
|
||||
#include "hwl.h"
|
||||
#include <iss/arch/tgc_c_xrb_nn.h>
|
||||
using tgc_c_xrb_nn_plat_type = iss::arch::hwl<iss::arch::riscv_hart_m_p<iss::arch::tgc_c_xrb_nn>>;
|
||||
#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_TGC_D
|
||||
#ifdef CORE_TGC5D
|
||||
#include "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)>;
|
||||
#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_TGC_D_XRB_MAC
|
||||
#ifdef CORE_TGC5D_XRB_MAC
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include <iss/arch/tgc_d_xrb_mac.h>
|
||||
using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_mac, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#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_TGC_D_XRB_NN
|
||||
#ifdef CORE_TGC5D_XRB_NN
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include "hwl.h"
|
||||
#include <iss/arch/tgc_d_xrb_nn.h>
|
||||
using tgc_d_xrb_nn_plat_type = iss::arch::hwl<iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_nn, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>>;
|
||||
#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_TGC_E
|
||||
#ifdef CORE_TGC5E
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include <iss/arch/tgc_e.h>
|
||||
using tgc_e_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_e, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#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_TGC_X
|
||||
#ifdef CORE_TGC5X
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include <iss/arch/tgc_x.h>
|
||||
using tgc_x_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_x, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N | iss::arch::FEAT_TCM)>;
|
||||
#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
|
||||
|
@ -81,7 +81,7 @@ public:
|
||||
using mem_write_f = typename BASE::mem_write_f;
|
||||
using phys_addr_t = typename BASE::phys_addr_t;
|
||||
|
||||
wt_cache();
|
||||
wt_cache(feature_config cfg = feature_config{});
|
||||
virtual ~wt_cache() = default;
|
||||
|
||||
unsigned size{4096};
|
||||
@ -103,7 +103,11 @@ protected:
|
||||
|
||||
|
||||
template<typename BASE>
|
||||
inline wt_cache<BASE>::wt_cache() {
|
||||
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);});
|
||||
|
@ -34,6 +34,12 @@
|
||||
#define _ISS_FACTORY_H_
|
||||
|
||||
#include <iss/iss.h>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace iss {
|
||||
|
||||
@ -57,6 +63,44 @@ std::tuple<cpu_ptr, vm_ptr> create_cpu(std::string const& backend, unsigned gdb_
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* _ISS_FACTORY_H_ */
|
||||
|
8
src/iss/plugin/README.md
Normal file
8
src/iss/plugin/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# 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).
|
@ -33,18 +33,13 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "cycle_estimate.h"
|
||||
#include <iss/plugin/calculator.h>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include <iss/arch_if.h>
|
||||
#include <util/logging.h>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/istreamwrapper.h>
|
||||
#include <rapidjson/writer.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
#include <rapidjson/ostreamwrapper.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
#include <fstream>
|
||||
|
||||
using namespace rapidjson;
|
||||
using namespace std;
|
||||
|
||||
iss::plugin::cycle_estimate::cycle_estimate(string const& config_file_name)
|
||||
@ -53,48 +48,46 @@ iss::plugin::cycle_estimate::cycle_estimate(string const& config_file_name)
|
||||
{
|
||||
}
|
||||
|
||||
iss::plugin::cycle_estimate::~cycle_estimate() {
|
||||
}
|
||||
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) {
|
||||
ifstream is(config_file_name);
|
||||
std::ifstream is(config_file_name);
|
||||
if (is.is_open()) {
|
||||
try {
|
||||
IStreamWrapper isw(is);
|
||||
Document d;
|
||||
ParseResult ok = d.ParseStream(isw);
|
||||
if(ok) {
|
||||
Value& val = d[core_name.c_str()];
|
||||
if(val.IsArray()){
|
||||
delays.reserve(val.Size());
|
||||
for (auto it = val.Begin(); it != val.End(); ++it) {
|
||||
auto& name = (*it)["name"];
|
||||
auto& size = (*it)["size"];
|
||||
auto& delay = (*it)["delay"];
|
||||
auto& branch = (*it)["branch"];
|
||||
if(delay.IsArray()) {
|
||||
auto dt = delay[0].Get<unsigned>();
|
||||
auto dnt = delay[1].Get<unsigned>();
|
||||
delays.push_back(instr_desc{size.Get<unsigned>(), dt, dnt, branch.Get<bool>()});
|
||||
} else if(delay.Is<unsigned>()) {
|
||||
auto d = delay.Get<unsigned>();
|
||||
delays.push_back(instr_desc{size.Get<unsigned>(), d, d, branch.Get<bool>()});
|
||||
} else
|
||||
throw runtime_error("JSON parse error");
|
||||
}
|
||||
} else {
|
||||
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<endl;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOG(ERR)<<"plugin cycle_estimate: could not parse in JSON file at "<< ok.Offset()<<": "<<GetParseError_En(ok.Code())<<endl;
|
||||
return false;
|
||||
}
|
||||
} catch (runtime_error &e) {
|
||||
auto root = YAML::LoadAll(is);
|
||||
if(root.size()!=1) {
|
||||
LOG(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) {
|
||||
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
|
||||
return false;
|
||||
}
|
||||
@ -104,15 +97,19 @@ bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if&
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info) {
|
||||
assert(instr_if && "No instrumentation interface available but callback executed");
|
||||
auto entry = delays[instr_info.instr_id];
|
||||
bool taken = instr_if->is_branch_taken();
|
||||
if (taken && (entry.taken > 1))
|
||||
instr_if->update_last_instr_cycles(entry.taken);
|
||||
else if (entry.not_taken > 1)
|
||||
instr_if->update_last_instr_cycles(entry.not_taken);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -40,24 +40,20 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace iss {
|
||||
|
||||
namespace plugin {
|
||||
|
||||
class cycle_estimate: public vm_plugin {
|
||||
BEGIN_BF_DECL(instr_desc, uint32_t)
|
||||
BF_FIELD(taken, 24, 8)
|
||||
BF_FIELD(not_taken, 16, 8)
|
||||
BF_FIELD(is_branch, 8, 8)
|
||||
BF_FIELD(size, 0, 8)
|
||||
instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken, bool branch): instr_desc() {
|
||||
this->size=size;
|
||||
this->taken=taken;
|
||||
this->not_taken=not_taken;
|
||||
this->is_branch=branch;
|
||||
}
|
||||
END_BF_DECL();
|
||||
struct instr_desc {
|
||||
size_t size{0};
|
||||
bool is_branch{false};
|
||||
unsigned not_taken{1};
|
||||
unsigned taken{1};
|
||||
std::function<unsigned(uint64_t)> f;
|
||||
};
|
||||
|
||||
public:
|
||||
cycle_estimate() = delete;
|
||||
@ -76,13 +72,16 @@ public:
|
||||
|
||||
bool registration(const char *const version, vm_if &arch) override;
|
||||
|
||||
sync_type get_sync() override { return POST_SYNC; };
|
||||
sync_type get_sync() override { return ALL_SYNC; };
|
||||
|
||||
void callback(instr_info_t instr_info) override;
|
||||
|
||||
private:
|
||||
iss::instrumentation_if *instr_if;
|
||||
iss::instrumentation_if *instr_if{nullptr};
|
||||
uint32_t* reg_base_ptr {nullptr};
|
||||
instr_desc illegal_desc{};
|
||||
std::vector<instr_desc> delays;
|
||||
unsigned current_delay{0};
|
||||
struct pair_hash {
|
||||
size_t operator()(const std::pair<uint64_t, uint64_t> &p) const {
|
||||
std::hash<uint64_t> hash;
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
#include "instruction_count.h"
|
||||
#include <iss/instrumentation_if.h>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include <iss/arch_if.h>
|
||||
#include <util/logging.h>
|
||||
@ -44,8 +45,30 @@ iss::plugin::instruction_count::instruction_count(std::string config_file_name)
|
||||
std::ifstream is(config_file_name);
|
||||
if (is.is_open()) {
|
||||
try {
|
||||
is >> root;
|
||||
} catch (Json::RuntimeError &e) {
|
||||
auto root = YAML::LoadAll(is);
|
||||
if(root.size()!=1) {
|
||||
LOG(ERR) << "Too many rro 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) {
|
||||
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) {
|
||||
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
|
||||
}
|
||||
} else {
|
||||
@ -57,7 +80,7 @@ iss::plugin::instruction_count::instruction_count(std::string config_file_name)
|
||||
iss::plugin::instruction_count::~instruction_count() {
|
||||
size_t idx=0;
|
||||
for(auto it:delays){
|
||||
if(rep_counts[idx]>0)
|
||||
if(rep_counts[idx]>0 && it.instr_name.find("__"!=0))
|
||||
LOG(INFO)<<it.instr_name<<";"<<rep_counts[idx];
|
||||
idx++;
|
||||
}
|
||||
@ -66,27 +89,6 @@ iss::plugin::instruction_count::~instruction_count() {
|
||||
bool iss::plugin::instruction_count::registration(const char* const version, vm_if& vm) {
|
||||
auto instr_if = vm.get_arch()->get_instrumentation_if();
|
||||
if(!instr_if) return false;
|
||||
const std::string core_name = instr_if->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()){
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -36,8 +36,8 @@
|
||||
#define _ISS_PLUGIN_INSTRUCTION_COUNTER_H_
|
||||
|
||||
#include <iss/vm_plugin.h>
|
||||
#include <json/json.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace iss {
|
||||
namespace plugin {
|
||||
@ -72,7 +72,6 @@ public:
|
||||
void callback(instr_info_t) override;
|
||||
|
||||
private:
|
||||
Json::Value root;
|
||||
std::vector<instr_delay> delays;
|
||||
std::vector<uint64_t> rep_counts;
|
||||
};
|
||||
|
@ -1,214 +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:
|
||||
* alex.com - initial implementation
|
||||
******************************************************************************/
|
||||
|
||||
#include <iss/arch_if.h>
|
||||
#include <iss/plugin/pctrace.h>
|
||||
#include <util/logging.h>
|
||||
#include <util/ities.h>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/istreamwrapper.h>
|
||||
#include <rapidjson/writer.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
#include <rapidjson/ostreamwrapper.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#ifdef WITH_LZ4
|
||||
#include <lz4frame.h>
|
||||
#endif
|
||||
|
||||
namespace iss {
|
||||
namespace plugin {
|
||||
|
||||
using namespace rapidjson;
|
||||
using namespace std;
|
||||
|
||||
#ifdef WITH_LZ4
|
||||
class lz4compress_steambuf: public std::streambuf {
|
||||
public:
|
||||
lz4compress_steambuf(const lz4compress_steambuf&) = delete;
|
||||
lz4compress_steambuf& operator=(const lz4compress_steambuf&) = delete;
|
||||
lz4compress_steambuf(std::ostream &sink, size_t buf_size)
|
||||
: sink(sink)
|
||||
, src_buf(buf_size)
|
||||
, dest_buf(LZ4F_compressBound(buf_size, nullptr))
|
||||
{
|
||||
auto errCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
|
||||
if (LZ4F_isError(errCode) != 0)
|
||||
throw std::runtime_error(std::string("Failed to create LZ4 context: ") + LZ4F_getErrorName(errCode));
|
||||
size_t ret = LZ4F_compressBegin(ctx, &dest_buf.front(), dest_buf.capacity(), nullptr);
|
||||
if (LZ4F_isError(ret) != 0)
|
||||
throw std::runtime_error(std::string("Failed to start LZ4 compression: ") + LZ4F_getErrorName(ret));
|
||||
setp(src_buf.data(), src_buf.data() + src_buf.size() - 1);
|
||||
sink.write(dest_buf.data(), ret);
|
||||
}
|
||||
|
||||
~lz4compress_steambuf() {
|
||||
close();
|
||||
}
|
||||
|
||||
void close() {
|
||||
if (closed)
|
||||
return;
|
||||
sync();
|
||||
auto ret = LZ4F_compressEnd(ctx, dest_buf.data(), dest_buf.capacity(), nullptr);
|
||||
if (LZ4F_isError(ret) != 0)
|
||||
throw std::runtime_error(std::string("Failed to finish LZ4 compression: ") + LZ4F_getErrorName(ret));
|
||||
sink.write(dest_buf.data(), ret);
|
||||
LZ4F_freeCompressionContext(ctx);
|
||||
closed = true;
|
||||
}
|
||||
|
||||
private:
|
||||
int_type overflow(int_type ch) override {
|
||||
compress_and_write();
|
||||
*pptr() = static_cast<char_type>(ch);
|
||||
pbump(1);
|
||||
return ch;
|
||||
}
|
||||
|
||||
int_type sync() override {
|
||||
compress_and_write();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void compress_and_write() {
|
||||
if (closed)
|
||||
throw std::runtime_error("Cannot write to closed stream");
|
||||
if(auto orig_size = pptr() - pbase()){
|
||||
auto ret = LZ4F_compressUpdate(ctx, dest_buf.data(), dest_buf.capacity(), pbase(), orig_size, nullptr);
|
||||
if (LZ4F_isError(ret) != 0)
|
||||
throw std::runtime_error(std::string("LZ4 compression failed: ") + LZ4F_getErrorName(ret));
|
||||
if(ret) sink.write(dest_buf.data(), ret);
|
||||
pbump(-orig_size);
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream &sink;
|
||||
std::vector<char> src_buf;
|
||||
std::vector<char> dest_buf;
|
||||
LZ4F_compressionContext_t ctx{ nullptr };
|
||||
bool closed{ false };
|
||||
};
|
||||
#endif
|
||||
|
||||
pctrace::pctrace(std::string const &filename)
|
||||
: instr_if(nullptr)
|
||||
, filename(filename)
|
||||
, output("output.trc")
|
||||
#ifdef WITH_LZ4
|
||||
, strbuf(new lz4compress_steambuf(output, 4096))
|
||||
, ostr(strbuf.get())
|
||||
#endif
|
||||
{ }
|
||||
|
||||
pctrace::~pctrace() { }
|
||||
|
||||
bool pctrace::registration(const char *const version, vm_if& vm) {
|
||||
instr_if = vm.get_arch()->get_instrumentation_if();
|
||||
if(!instr_if) return false;
|
||||
const string core_name = instr_if->core_type_name();
|
||||
if (filename.length() > 0) {
|
||||
ifstream is(filename);
|
||||
if (is.is_open()) {
|
||||
try {
|
||||
IStreamWrapper isw(is);
|
||||
Document d;
|
||||
ParseResult ok = d.ParseStream(isw);
|
||||
if(ok) {
|
||||
Value& val = d[core_name.c_str()];
|
||||
if(val.IsArray()){
|
||||
delays.reserve(val.Size());
|
||||
for (auto it = val.Begin(); it != val.End(); ++it) {
|
||||
auto& name = (*it)["name"];
|
||||
auto& size = (*it)["size"];
|
||||
auto& delay = (*it)["delay"];
|
||||
auto& branch = (*it)["branch"];
|
||||
if(delay.IsArray()) {
|
||||
auto dt = delay[0].Get<unsigned>();
|
||||
auto dnt = delay[1].Get<unsigned>();
|
||||
delays.push_back(instr_desc{size.Get<unsigned>(), dt, dnt, branch.Get<bool>()});
|
||||
} else if(delay.Is<unsigned>()) {
|
||||
auto d = delay.Get<unsigned>();
|
||||
delays.push_back(instr_desc{size.Get<unsigned>(), d, d, branch.Get<bool>()});
|
||||
} else
|
||||
throw runtime_error("JSON parse error");
|
||||
|
||||
}
|
||||
} else {
|
||||
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<endl;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOG(ERR)<<"plugin cycle_estimate: could not parse in JSON file at "<< ok.Offset()<<": "<<GetParseError_En(ok.Code())<<endl;
|
||||
return false;
|
||||
}
|
||||
} catch (runtime_error &e) {
|
||||
LOG(ERR) << "Could not parse input file " << filename << ", reason: " << e.what();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOG(ERR) << "Could not open input file " << filename;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void pctrace::callback(instr_info_t iinfo) {
|
||||
auto delay = 0;
|
||||
size_t id = iinfo.instr_id;
|
||||
auto entry = delays[id];
|
||||
auto instr = instr_if->get_instr_word();
|
||||
auto call = id==65 || id ==86 || ((id==2 || id==3) && bit_sub<7,5>(instr)!=0) ;//not taking care of tail calls (jalr with loading x6)
|
||||
bool taken = instr_if->is_branch_taken();
|
||||
bool compressed = (instr&0x3)!=0x3;
|
||||
if (taken) {
|
||||
delay = entry.taken;
|
||||
if(entry.taken > 1)
|
||||
instr_if->update_last_instr_cycles(entry.taken);
|
||||
} else {
|
||||
delay = entry.not_taken;
|
||||
if (entry.not_taken > 1)
|
||||
instr_if->update_last_instr_cycles(entry.not_taken);
|
||||
}
|
||||
#ifndef WITH_LZ4
|
||||
output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<"\n";
|
||||
#else
|
||||
auto rdbuf=ostr.rdbuf();
|
||||
ostr<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<"\n";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
473
src/main.cpp
473
src/main.cpp
@ -1,251 +1,222 @@
|
||||
/*******************************************************************************
|
||||
* 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 <iostream>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include "iss/factory.h"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include "iss/arch/tgc_mapper.h"
|
||||
#ifdef WITH_LLVM
|
||||
#include <iss/llvm/jit_helper.h>
|
||||
#endif
|
||||
#include <iss/log_categories.h>
|
||||
#include "iss/plugin/cycle_estimate.h"
|
||||
#include "iss/plugin/instruction_count.h"
|
||||
#include "iss/plugin/pctrace.h"
|
||||
#ifndef WIN32
|
||||
#include <iss/plugin/loader.h>
|
||||
#endif
|
||||
#if defined(HAS_LUA)
|
||||
#include <iss/plugin/lua.h>
|
||||
#endif
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
/*
|
||||
* Define and parse the program options
|
||||
*/
|
||||
po::variables_map clim;
|
||||
po::options_description desc("Options");
|
||||
// clang-format off
|
||||
desc.add_options()
|
||||
("help,h", "Print help message")
|
||||
("verbose,v", po::value<int>()->default_value(4), "Sets logging verbosity")
|
||||
("logfile,l", po::value<std::string>(), "Sets default log file.")
|
||||
("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")
|
||||
("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")
|
||||
("dump-ir", "dump the intermediate representation")
|
||||
("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load")
|
||||
("mem,m", po::value<std::string>(), "the memory input file")
|
||||
("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, tcc")
|
||||
("isa", po::value<std::string>()->default_value("tgc_c"), "isa to use for simulation");
|
||||
// clang-format on
|
||||
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
|
||||
try {
|
||||
po::store(parsed, clim); // can throw
|
||||
// --help option
|
||||
if (clim.count("help")) {
|
||||
std::cout << "DBT-RISE-RiscV simulator for RISC-V" << std::endl << desc << std::endl;
|
||||
return 0;
|
||||
}
|
||||
po::notify(clim); // throws on error, so do after help in case
|
||||
} catch (po::error &e) {
|
||||
// there are problems
|
||||
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
|
||||
std::cerr << desc << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::vector<std::string> args = collect_unrecognized(parsed.options, po::include_positional);
|
||||
|
||||
LOGGER(DEFAULT)::print_time() = false;
|
||||
LOGGER(connection)::print_time() = false;
|
||||
auto l = logging::as_log_level(clim["verbose"].as<int>());
|
||||
LOGGER(DEFAULT)::reporting_level() = l;
|
||||
LOGGER(connection)::reporting_level() = l;
|
||||
if (clim.count("logfile")) {
|
||||
// configure the connection logger
|
||||
auto f = fopen(clim["logfile"].as<std::string>().c_str(), "w");
|
||||
LOG_OUTPUT(DEFAULT)::stream() = f;
|
||||
LOG_OUTPUT(connection)::stream() = f;
|
||||
}
|
||||
|
||||
std::vector<iss::vm_plugin *> plugin_list;
|
||||
auto res = 0;
|
||||
try {
|
||||
#ifdef WITH_LLVM
|
||||
// application code comes here //
|
||||
iss::init_jit_debug(argc, argv);
|
||||
#endif
|
||||
bool dump = clim.count("dump-ir");
|
||||
// instantiate the simulator
|
||||
iss::vm_ptr vm{nullptr};
|
||||
iss::cpu_ptr cpu{nullptr};
|
||||
std::string isa_opt(clim["isa"].as<std::string>());
|
||||
if (isa_opt == "tgc_c") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_c_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#ifdef CORE_TGC_B
|
||||
if (isa_opt == "tgc_b") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_b_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
#ifdef CORE_TGC_C_XRB_NN
|
||||
if (isa_opt == "tgc_c_xrb_nn") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_c_xrb_nn_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
#ifdef CORE_TGC_D
|
||||
if (isa_opt == "tgc_d") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_d_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_MAC
|
||||
if (isa_opt == "tgc_d_xrb_mac") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_d_xrb_mac_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_NN
|
||||
if (isa_opt == "tgc_d_xrb_nn") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_d_xrb_nn_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
#ifdef CORE_TGC_E
|
||||
if (isa_opt == "tgc_e") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_e_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
LOG(ERR) << "Illegal argument value for '--isa': " << isa_opt << std::endl;
|
||||
return 127;
|
||||
}
|
||||
if(!cpu ){
|
||||
LOG(ERR) << "Could not create cpu for isa " << isa_opt << " and backend " <<clim["backend"].as<std::string>()<< std::endl;
|
||||
return 127;
|
||||
}
|
||||
if(!vm ){
|
||||
LOG(ERR) << "Could not create vm for isa " << isa_opt << " and backend " <<clim["backend"].as<std::string>()<< std::endl;
|
||||
return 127;
|
||||
}
|
||||
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('=');
|
||||
if (found != std::string::npos) {
|
||||
plugin_name = opt_val.substr(0, found);
|
||||
arg = opt_val.substr(found + 1, opt_val.size());
|
||||
}
|
||||
if (plugin_name == "ic") {
|
||||
auto *ic_plugin = new iss::plugin::instruction_count(arg);
|
||||
vm->register_plugin(*ic_plugin);
|
||||
plugin_list.push_back(ic_plugin);
|
||||
} else if (plugin_name == "ce") {
|
||||
auto *ce_plugin = new iss::plugin::cycle_estimate(arg);
|
||||
vm->register_plugin(*ce_plugin);
|
||||
plugin_list.push_back(ce_plugin);
|
||||
} else if (plugin_name == "pctrace") {
|
||||
auto *plugin = new iss::plugin::pctrace(arg);
|
||||
vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else {
|
||||
#ifndef 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
|
||||
{
|
||||
LOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
|
||||
return 127;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (clim.count("disass")) {
|
||||
vm->setDisassEnabled(true);
|
||||
LOGGER(disass)::reporting_level() = logging::INFO;
|
||||
LOGGER(disass)::print_time() = false;
|
||||
auto file_name = clim["disass"].as<std::string>();
|
||||
if (file_name.length() > 0) {
|
||||
LOG_OUTPUT(disass)::stream() = fopen(file_name.c_str(), "w");
|
||||
LOGGER(disass)::print_severity() = false;
|
||||
}
|
||||
}
|
||||
uint64_t start_address = 0;
|
||||
if (clim.count("mem"))
|
||||
vm->get_arch()->load_file(clim["mem"].as<std::string>());
|
||||
if (clim.count("elf"))
|
||||
for (std::string input : clim["elf"].as<std::vector<std::string>>()) {
|
||||
auto start_addr = vm->get_arch()->load_file(input);
|
||||
if (start_addr.second) start_address = start_addr.first;
|
||||
}
|
||||
for (std::string input : args) {
|
||||
auto start_addr = vm->get_arch()->load_file(input); // treat remaining arguments as elf files
|
||||
if (start_addr.second) start_address = start_addr.first;
|
||||
}
|
||||
if (clim.count("reset")) {
|
||||
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);
|
||||
}
|
||||
vm->reset(start_address);
|
||||
auto cycles = clim["instructions"].as<uint64_t>();
|
||||
res = vm->start(cycles, dump);
|
||||
} catch (std::exception &e) {
|
||||
LOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit"
|
||||
<< std::endl;
|
||||
res = 2;
|
||||
}
|
||||
// cleanup to let plugins report of needed
|
||||
for (auto *p : plugin_list) {
|
||||
delete p;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/*******************************************************************************
|
||||
* 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 <iostream>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <iss/factory.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include "iss/arch/tgc_mapper.h"
|
||||
#ifdef WITH_LLVM
|
||||
#include <iss/llvm/jit_init.h>
|
||||
#endif
|
||||
#include <iss/log_categories.h>
|
||||
#include "iss/plugin/cycle_estimate.h"
|
||||
#include "iss/plugin/instruction_count.h"
|
||||
#ifndef WIN32
|
||||
#include <iss/plugin/loader.h>
|
||||
#endif
|
||||
#if defined(HAS_LUA)
|
||||
#include <iss/plugin/lua.h>
|
||||
#endif
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
/*
|
||||
* Define and parse the program options
|
||||
*/
|
||||
po::variables_map clim;
|
||||
po::options_description desc("Options");
|
||||
// clang-format off
|
||||
desc.add_options()
|
||||
("help,h", "Print help message")
|
||||
("verbose,v", po::value<int>()->default_value(4), "Sets logging verbosity")
|
||||
("logfile,l", po::value<std::string>(), "Sets default log file.")
|
||||
("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")
|
||||
("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")
|
||||
("dump-ir", "dump the intermediate representation")
|
||||
("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load")
|
||||
("mem,m", po::value<std::string>(), "the memory input file")
|
||||
("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, tcc")
|
||||
("isa", po::value<std::string>()->default_value("tgc5c"), "core or isa name to use for simulation, use '?' to get list");
|
||||
// clang-format on
|
||||
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
|
||||
try {
|
||||
po::store(parsed, clim); // can throw
|
||||
// --help option
|
||||
if (clim.count("help")) {
|
||||
std::cout << "DBT-RISE-TGC simulator for TGC RISC-V cores" << std::endl << desc << std::endl;
|
||||
return 0;
|
||||
}
|
||||
po::notify(clim); // throws on error, so do after help in case
|
||||
} catch (po::error &e) {
|
||||
// there are problems
|
||||
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
|
||||
std::cerr << desc << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::vector<std::string> args = collect_unrecognized(parsed.options, po::include_positional);
|
||||
|
||||
LOGGER(DEFAULT)::print_time() = false;
|
||||
LOGGER(connection)::print_time() = false;
|
||||
auto l = logging::as_log_level(clim["verbose"].as<int>());
|
||||
LOGGER(DEFAULT)::reporting_level() = l;
|
||||
LOGGER(connection)::reporting_level() = l;
|
||||
if (clim.count("logfile")) {
|
||||
// configure the connection logger
|
||||
auto f = fopen(clim["logfile"].as<std::string>().c_str(), "w");
|
||||
LOG_OUTPUT(DEFAULT)::stream() = f;
|
||||
LOG_OUTPUT(connection)::stream() = f;
|
||||
}
|
||||
|
||||
std::vector<iss::vm_plugin *> plugin_list;
|
||||
auto res = 0;
|
||||
try {
|
||||
#ifdef WITH_LLVM
|
||||
// application code comes here //
|
||||
iss::init_jit_debug(argc, argv);
|
||||
#endif
|
||||
bool dump = clim.count("dump-ir");
|
||||
auto & f = iss::core_factory::instance();
|
||||
// instantiate the simulator
|
||||
iss::vm_ptr vm{nullptr};
|
||||
iss::cpu_ptr cpu{nullptr};
|
||||
std::string isa_opt(clim["isa"].as<std::string>());
|
||||
if(isa_opt.size()==0 || isa_opt == "?") {
|
||||
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) = f.create(isa_opt+"|"+clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else {
|
||||
auto base_isa = isa_opt.substr(0, 5);
|
||||
if(base_isa=="tgc5d" || base_isa=="tgc5e") {
|
||||
isa_opt += "|mu_p_clic_pmp|"+clim["backend"].as<std::string>();
|
||||
} else {
|
||||
isa_opt += "|m_p|"+clim["backend"].as<std::string>();
|
||||
}
|
||||
std::tie(cpu, vm) = f.create(isa_opt, clim["gdb-port"].as<unsigned>());
|
||||
}
|
||||
if(!cpu ){
|
||||
LOG(ERR) << "Could not create cpu for isa " << isa_opt << " and backend " <<clim["backend"].as<std::string>()<< std::endl;
|
||||
return 127;
|
||||
}
|
||||
if(!vm ){
|
||||
LOG(ERR) << "Could not create vm for isa " << isa_opt << " and backend " <<clim["backend"].as<std::string>()<< std::endl;
|
||||
return 127;
|
||||
}
|
||||
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('=');
|
||||
if (found != std::string::npos) {
|
||||
plugin_name = opt_val.substr(0, found);
|
||||
arg = opt_val.substr(found + 1, opt_val.size());
|
||||
}
|
||||
#if defined(WITH_PLUGINS)
|
||||
if (plugin_name == "ic") {
|
||||
auto *ic_plugin = new iss::plugin::instruction_count(arg);
|
||||
vm->register_plugin(*ic_plugin);
|
||||
plugin_list.push_back(ic_plugin);
|
||||
} else if (plugin_name == "ce") {
|
||||
auto *ce_plugin = new iss::plugin::cycle_estimate(arg);
|
||||
vm->register_plugin(*ce_plugin);
|
||||
plugin_list.push_back(ce_plugin);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
#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
|
||||
{
|
||||
LOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
|
||||
return 127;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (clim.count("disass")) {
|
||||
vm->setDisassEnabled(true);
|
||||
LOGGER(disass)::reporting_level() = logging::INFO;
|
||||
LOGGER(disass)::print_time() = false;
|
||||
auto file_name = clim["disass"].as<std::string>();
|
||||
if (file_name.length() > 0) {
|
||||
LOG_OUTPUT(disass)::stream() = fopen(file_name.c_str(), "w");
|
||||
LOGGER(disass)::print_severity() = false;
|
||||
}
|
||||
}
|
||||
uint64_t start_address = 0;
|
||||
if (clim.count("mem"))
|
||||
vm->get_arch()->load_file(clim["mem"].as<std::string>());
|
||||
if (clim.count("elf"))
|
||||
for (std::string input : clim["elf"].as<std::vector<std::string>>()) {
|
||||
auto start_addr = vm->get_arch()->load_file(input);
|
||||
if (start_addr.second) start_address = start_addr.first;
|
||||
}
|
||||
for (std::string input : args) {
|
||||
auto start_addr = vm->get_arch()->load_file(input); // treat remaining arguments as elf files
|
||||
if (start_addr.second) start_address = start_addr.first;
|
||||
}
|
||||
if (clim.count("reset")) {
|
||||
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);
|
||||
}
|
||||
vm->reset(start_address);
|
||||
auto cycles = clim["instructions"].as<uint64_t>();
|
||||
res = vm->start(cycles, dump);
|
||||
} catch (std::exception &e) {
|
||||
LOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit"
|
||||
<< std::endl;
|
||||
res = 2;
|
||||
}
|
||||
// cleanup to let plugins report of needed
|
||||
for (auto *p : plugin_list) {
|
||||
delete p;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -37,19 +37,20 @@
|
||||
#include <iss/debugger/target_adapter_if.h>
|
||||
#include <iss/iss.h>
|
||||
#include <iss/vm_types.h>
|
||||
#include "iss_factory.h"
|
||||
#ifndef WIN32
|
||||
#include <iss/plugin/loader.h>
|
||||
#endif
|
||||
#include "core_complex.h"
|
||||
#include "sc_core_adapter_if.h"
|
||||
#include <iss/arch/tgc_mapper.h>
|
||||
#include <scc/report.h>
|
||||
#include <util/ities.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <array>
|
||||
#include <numeric>
|
||||
#include <iss/plugin/cycle_estimate.h>
|
||||
#include <iss/plugin/instruction_count.h>
|
||||
#include <iss/plugin/pctrace.h>
|
||||
|
||||
// clang-format on
|
||||
|
||||
@ -85,136 +86,9 @@ using namespace sc_core;
|
||||
|
||||
namespace {
|
||||
iss::debugger::encoder_decoder encdec;
|
||||
|
||||
std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
|
||||
}
|
||||
|
||||
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->instr_if.get_total_cycles());
|
||||
}
|
||||
|
||||
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 + 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();
|
||||
}
|
||||
};
|
||||
|
||||
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, is_fetch(addr.access)) ? 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";
|
||||
while(this->reg.pending_trap == 0 && (this->csr[arch::mip] & this->csr[arch::mie]) == 0) {
|
||||
sc_core::wait(wfi_evt);
|
||||
}
|
||||
PLAT::wait_until(flags);
|
||||
}
|
||||
|
||||
void local_irq(short id, bool value) {
|
||||
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[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) {
|
||||
@ -253,8 +127,10 @@ public:
|
||||
core_wrapper(core_complex *owner) : owner(owner) { }
|
||||
|
||||
void reset(uint64_t addr){vm->reset(addr);}
|
||||
inline void start(){vm->start();}
|
||||
inline std::pair<uint64_t, bool> load_file(std::string const& name){ return cpu->load_file(name);};
|
||||
inline void start(bool dump = false){vm->start(std::numeric_limits<uint64_t>::max(), dump);}
|
||||
inline std::pair<uint64_t, bool> load_file(std::string const& name){
|
||||
iss::arch_if* cc = cpu->get_arch_if();
|
||||
return cc->load_file(name);};
|
||||
|
||||
std::function<unsigned(void)> get_mode;
|
||||
std::function<uint64_t(void)> get_state;
|
||||
@ -262,45 +138,35 @@ public:
|
||||
std::function<void(bool)> set_interrupt_execution;
|
||||
std::function<void(short, bool)> local_irq;
|
||||
|
||||
template<typename PLAT>
|
||||
std::tuple<cpu_ptr, vm_ptr> create_core(std::string const& backend, unsigned gdb_port, uint32_t hart_id){
|
||||
auto* lcpu = new core_wrapper_t<PLAT>(owner);
|
||||
lcpu->set_mhartid(hart_id);
|
||||
get_mode = [lcpu]() { return lcpu->get_mode(); };
|
||||
get_state = [lcpu]() { return lcpu->get_state().mstatus.backing.val; };
|
||||
get_interrupt_execution = [lcpu]() { return lcpu->get_interrupt_execution(); };
|
||||
set_interrupt_execution = [lcpu](bool b) { return lcpu->set_interrupt_execution(b); };
|
||||
local_irq = [lcpu](short s, bool b) { return lcpu->local_irq(s, b); };
|
||||
if(backend == "interp")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(static_cast<typename PLAT::core*>(lcpu), gdb_port)}};
|
||||
#ifdef WITH_LLVM
|
||||
if(backend == "llvm")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
#ifdef WITH_TCC
|
||||
if(backend == "tcc")
|
||||
s return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
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
|
||||
#ifdef CORE_TGC_D_XRB_MAC
|
||||
CREATE_CORE(tgc_d_xrb_mac)
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_NN
|
||||
CREATE_CORE(tgc_d_xrb_nn)
|
||||
#endif
|
||||
{
|
||||
LOG(ERR) << "Illegal argument value for core type: " << type << std::endl;
|
||||
auto & f = sysc::iss_factory::instance();
|
||||
if(type.size()==0 || type == "?") {
|
||||
std::cout<<"Available cores: "<<util::join(f.get_names(), ", ")<<std::endl;
|
||||
sc_core::sc_stop();
|
||||
} else if (type.find('|') != std::string::npos) {
|
||||
std::tie(cpu, vm) = f.create(type+"|"+backend);
|
||||
} else {
|
||||
auto base_isa = type.substr(0, 5);
|
||||
if(base_isa=="tgc5d" || base_isa=="tgc5e") {
|
||||
std::tie(cpu, vm) = f.create(type + "|mu_p_clic_pmp|" + backend, gdb_port, owner);
|
||||
} else {
|
||||
std::tie(cpu, vm) = f.create(type + "|m_p|" + backend, gdb_port, owner);
|
||||
}
|
||||
}
|
||||
if(!cpu ){
|
||||
SCCFATAL() << "Could not create cpu for isa " << type << " and backend " <<backend;
|
||||
}
|
||||
if(!vm ){
|
||||
SCCFATAL() << "Could not create vm for isa " << type << " and backend " <<backend;
|
||||
}
|
||||
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)
|
||||
@ -313,7 +179,7 @@ public:
|
||||
|
||||
core_complex * const owner;
|
||||
vm_ptr vm{nullptr};
|
||||
cpu_ptr cpu{nullptr};
|
||||
sc_cpu_ptr cpu{nullptr};
|
||||
iss::debugger::target_adapter_if *tgt_adapter{nullptr};
|
||||
};
|
||||
|
||||
@ -417,10 +283,6 @@ void core_complex::before_end_of_elaboration() {
|
||||
auto *plugin = new iss::plugin::cycle_estimate(filename);
|
||||
cpu->vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else if (plugin_name == "pctrace") {
|
||||
auto *plugin = new iss::plugin::pctrace(filename);
|
||||
cpu->vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else {
|
||||
#ifndef WIN32
|
||||
std::array<char const*, 1> a{{filename.c_str()}};
|
||||
@ -518,7 +380,7 @@ void core_complex::run() {
|
||||
}
|
||||
quantum_keeper.reset();
|
||||
cpu->set_interrupt_execution(false);
|
||||
cpu->start();
|
||||
cpu->start(dump_ir);
|
||||
} while (cpu->get_interrupt_execution());
|
||||
sc_stop();
|
||||
}
|
||||
@ -529,7 +391,10 @@ bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data,
|
||||
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();
|
||||
std::copy(lut_entry.get_dmi_ptr() + offset, lut_entry.get_dmi_ptr() + offset + length, data);
|
||||
quantum_keeper.inc(lut_entry.get_read_latency());
|
||||
if(is_fetch)
|
||||
ibus_inc+=lut_entry.get_read_latency()/curr_clk;
|
||||
else
|
||||
dbus_inc+=lut_entry.get_read_latency()/curr_clk;
|
||||
return true;
|
||||
} else {
|
||||
auto& sckt = is_fetch? ibus : dbus;
|
||||
@ -547,17 +412,22 @@ bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data,
|
||||
auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this);
|
||||
gp.set_extension(preExt);
|
||||
}
|
||||
sckt->b_transport(gp, delay);
|
||||
auto incr = delay-quantum_keeper.get_local_time();
|
||||
if(is_fetch)
|
||||
ibus_inc+=incr;
|
||||
else
|
||||
dbus_inc+=incr;
|
||||
auto pre_delay = delay;
|
||||
dbus->b_transport(gp, delay);
|
||||
if(pre_delay>delay) {
|
||||
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;
|
||||
}
|
||||
if (gp.is_dmi_allowed()) {
|
||||
if (gp.is_dmi_allowed() && !GET_PROP_VALUE(disable_dmi)) {
|
||||
gp.set_command(tlm::TLM_READ_COMMAND);
|
||||
gp.set_address(addr);
|
||||
tlm_dmi_ext dmi_data;
|
||||
@ -577,7 +447,7 @@ bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t *cons
|
||||
addr + length <= lut_entry.get_end_address() + 1) {
|
||||
auto offset = addr - lut_entry.get_start_address();
|
||||
std::copy(data, data + length, lut_entry.get_dmi_ptr() + offset);
|
||||
quantum_keeper.inc(lut_entry.get_read_latency());
|
||||
dbus_inc+=lut_entry.get_write_latency()/curr_clk;
|
||||
return true;
|
||||
} else {
|
||||
write_buf.resize(length);
|
||||
@ -593,13 +463,17 @@ bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t *cons
|
||||
auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this);
|
||||
gp.set_extension(preExt);
|
||||
}
|
||||
auto pre_delay = delay;
|
||||
dbus->b_transport(gp, delay);
|
||||
dbus_inc+=delay-quantum_keeper.get_local_time();
|
||||
if(pre_delay>delay)
|
||||
quantum_keeper.reset();
|
||||
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;
|
||||
}
|
||||
if (gp.is_dmi_allowed()) {
|
||||
if (gp.is_dmi_allowed() && !GET_PROP_VALUE(disable_dmi)) {
|
||||
gp.set_command(tlm::TLM_READ_COMMAND);
|
||||
gp.set_address(addr);
|
||||
tlm_dmi_ext dmi_data;
|
||||
@ -634,5 +508,5 @@ bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t *
|
||||
gp.set_streaming_width(length);
|
||||
return dbus->transport_dbg(gp) == length;
|
||||
}
|
||||
} /* namespace SiFive */
|
||||
} /* namespace tgfs */
|
||||
} /* namespace sysc */
|
||||
|
@ -94,9 +94,11 @@ public:
|
||||
|
||||
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<std::string> core_type{"core_type", "tgc_c"};
|
||||
cci::cci_param<std::string> core_type{"core_type", "tgc5c"};
|
||||
|
||||
cci::cci_param<std::string> backend{"backend", "interp"};
|
||||
|
||||
@ -119,9 +121,11 @@ public:
|
||||
|
||||
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<std::string> core_type{"core_type", "tgc_c"};
|
||||
scml_property<std::string> core_type{"core_type", "tgc5c"};
|
||||
|
||||
scml_property<std::string> backend{"backend", "interp"};
|
||||
|
||||
@ -139,7 +143,7 @@ public:
|
||||
, elf_file{"elf_file", ""}
|
||||
, enable_disass{"enable_disass", false}
|
||||
, reset_address{"reset_address", 0ULL}
|
||||
, core_type{"core_type", "tgc_c"}
|
||||
, core_type{"core_type", "tgc5c"}
|
||||
, backend{"backend", "interp"}
|
||||
, gdb_server_port{"gdb_server_port", 0}
|
||||
, dump_ir{"dump_ir", false}
|
||||
@ -156,17 +160,21 @@ public:
|
||||
|
||||
~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) {
|
||||
auto core_inc = curr_clk * (cycle - last_sync_cycle);
|
||||
auto incr = std::max(core_inc, std::max(ibus_inc, dbus_inc));
|
||||
quantum_keeper.inc(incr);
|
||||
quantum_keeper.inc(core_inc);
|
||||
if (quantum_keeper.need_sync()) {
|
||||
wait(quantum_keeper.get_local_time());
|
||||
quantum_keeper.reset();
|
||||
}
|
||||
last_sync_cycle = cycle;
|
||||
ibus_inc = sc_core::SC_ZERO_TIME;
|
||||
dbus_inc = sc_core::SC_ZERO_TIME;
|
||||
}
|
||||
|
||||
bool read_mem(uint64_t addr, unsigned length, uint8_t *const data, bool is_fetch);
|
||||
@ -198,7 +206,7 @@ protected:
|
||||
std::vector<uint8_t> write_buf;
|
||||
core_wrapper* cpu{nullptr};
|
||||
sc_core::sc_signal<sc_core::sc_time> curr_clk;
|
||||
sc_core::sc_time ibus_inc, dbus_inc;
|
||||
uint64_t ibus_inc{0}, dbus_inc{0};
|
||||
core_trace* trc{nullptr};
|
||||
std::unique_ptr<scc::tick2time> t2t;
|
||||
private:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017 - 2023, MINRES Technologies GmbH
|
||||
* Copyright (C) 2021 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -28,75 +28,61 @@
|
||||
* 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
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _ISS_PLUGIN_COV_H_
|
||||
#define _ISS_PLUGIN_COV_H_
|
||||
#ifndef _ISS_FACTORY_H_
|
||||
#define _ISS_FACTORY_H_
|
||||
|
||||
#include <iss/vm_plugin.h>
|
||||
#include "iss/instrumentation_if.h"
|
||||
#include <json/json.h>
|
||||
#include <iss/iss.h>
|
||||
#include "sc_core_adapter_if.h"
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace sysc {
|
||||
|
||||
namespace iss {
|
||||
namespace plugin {
|
||||
class lz4compress_steambuf;
|
||||
class pctrace : public iss::vm_plugin {
|
||||
struct instr_delay {
|
||||
std::string instr_name;
|
||||
size_t size;
|
||||
size_t not_taken_delay;
|
||||
size_t taken_delay;
|
||||
};
|
||||
BEGIN_BF_DECL(instr_desc, uint32_t)
|
||||
BF_FIELD(taken, 24, 8)
|
||||
BF_FIELD(not_taken, 16, 8)
|
||||
BF_FIELD(is_branch, 8, 8)
|
||||
BF_FIELD(size, 0, 8)
|
||||
instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken, bool branch): instr_desc() {
|
||||
this->size=size;
|
||||
this->taken=taken;
|
||||
this->not_taken=not_taken;
|
||||
this->is_branch=branch;
|
||||
}
|
||||
END_BF_DECL();
|
||||
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> ;
|
||||
|
||||
pctrace(const pctrace &) = delete;
|
||||
iss_factory() = default;
|
||||
iss_factory(const iss_factory &) = delete;
|
||||
iss_factory & operator=(const iss_factory &) = delete;
|
||||
|
||||
pctrace(const pctrace &&) = delete;
|
||||
static iss_factory & instance() { static iss_factory bf; return bf; }
|
||||
|
||||
pctrace(std::string const &);
|
||||
bool register_creator(const std::string & className, create_fn const& fn) {
|
||||
registry[className] = fn;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual ~pctrace();
|
||||
|
||||
pctrace &operator=(const pctrace &) = delete;
|
||||
|
||||
pctrace &operator=(const pctrace &&) = delete;
|
||||
|
||||
bool registration(const char *const version, vm_if &arch) override;
|
||||
|
||||
sync_type get_sync() override { return POST_SYNC; };
|
||||
|
||||
void callback(instr_info_t) override;
|
||||
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:
|
||||
iss::instrumentation_if *instr_if {nullptr};
|
||||
std::ofstream output;
|
||||
#ifdef WITH_LZ4
|
||||
std::unique_ptr<lz4compress_steambuf> strbuf;
|
||||
std::ostream ostr;
|
||||
#endif
|
||||
std::string filename;
|
||||
std::vector<instr_desc> delays;
|
||||
bool jumped{false}, first{true};
|
||||
registry_t registry;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* _ISS_PLUGIN_COV_H_ */
|
||||
#endif /* _ISS_FACTORY_H_ */
|
108
src/sysc/register_tgc_c.cpp
Normal file
108
src/sysc/register_tgc_c.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#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>
|
||||
|
||||
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)}};
|
||||
})
|
||||
};
|
||||
}
|
||||
#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)}};
|
||||
})
|
||||
};
|
||||
}
|
||||
#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)}};
|
||||
})
|
||||
};
|
||||
}
|
||||
#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)}};
|
||||
})
|
||||
};
|
||||
}
|
||||
#endif
|
||||
}
|
188
src/sysc/sc_core_adapter.h
Normal file
188
src/sysc/sc_core_adapter.h
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* sc_core_adapter.h
|
||||
*
|
||||
* Created on: Jul 5, 2023
|
||||
* Author: eyck
|
||||
*/
|
||||
|
||||
#ifndef _SYSC_SC_CORE_ADAPTER_H_
|
||||
#define _SYSC_SC_CORE_ADAPTER_H_
|
||||
|
||||
|
||||
#include <scc/report.h>
|
||||
#include <util/ities.h>
|
||||
#include "sc_core_adapter_if.h"
|
||||
#include <iss/iss.h>
|
||||
#include <iss/vm_types.h>
|
||||
#include <iostream>
|
||||
|
||||
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};
|
||||
};
|
||||
}
|
||||
#endif /* _SYSC_SC_CORE_ADAPTER_H_ */
|
31
src/sysc/sc_core_adapter_if.h
Normal file
31
src/sysc/sc_core_adapter_if.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 <scc/report.h>
|
||||
#include <util/ities.h>
|
||||
#include "core_complex.h"
|
||||
#include <iss/iss.h>
|
||||
#include <iss/vm_types.h>
|
||||
#include <iostream>
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
#endif /* _SYSC_SC_CORE_ADAPTER_IF_H_ */
|
474
src/vm/asmjit/helper_func.h
Normal file
474
src/vm/asmjit/helper_func.h
Normal file
@ -0,0 +1,474 @@
|
||||
|
||||
|
||||
x86::Mem get_reg_ptr(jit_holder& jh, unsigned idx){
|
||||
|
||||
x86::Gp tmp_ptr = jh.cc.newUIntPtr("tmp_ptr");
|
||||
jh.cc.mov(tmp_ptr, jh.regs_base_ptr);
|
||||
jh.cc.add(tmp_ptr, traits::reg_byte_offsets[idx]);
|
||||
switch(traits::reg_bit_widths[idx]){
|
||||
case 8:
|
||||
return x86::ptr_8(tmp_ptr);
|
||||
case 16:
|
||||
return x86::ptr_16(tmp_ptr);
|
||||
case 32:
|
||||
return x86::ptr_32(tmp_ptr);
|
||||
case 64:
|
||||
return x86::ptr_64(tmp_ptr);
|
||||
default:
|
||||
throw std::runtime_error("Invalid reg size in get_reg_ptr");
|
||||
}
|
||||
}
|
||||
x86::Gp get_reg_for(jit_holder& jh, unsigned idx){
|
||||
//can check for regs in jh and return them instead of creating new ones
|
||||
switch(traits::reg_bit_widths[idx]){
|
||||
case 8:
|
||||
return jh.cc.newInt8();
|
||||
case 16:
|
||||
return jh.cc.newInt16();
|
||||
case 32:
|
||||
return jh.cc.newInt32();
|
||||
case 64:
|
||||
return jh.cc.newInt64();
|
||||
default:
|
||||
throw std::runtime_error("Invalid reg size in get_reg_ptr");
|
||||
}
|
||||
}
|
||||
x86::Gp get_reg_for(jit_holder& jh, unsigned size, bool is_signed){
|
||||
if(is_signed)
|
||||
switch(size){
|
||||
case 8:
|
||||
return jh.cc.newInt8();
|
||||
case 16:
|
||||
return jh.cc.newInt16();
|
||||
case 32:
|
||||
return jh.cc.newInt32();
|
||||
case 64:
|
||||
return jh.cc.newInt64();
|
||||
default:
|
||||
throw std::runtime_error("Invalid reg size in get_reg_ptr");
|
||||
}
|
||||
else
|
||||
switch(size){
|
||||
case 8:
|
||||
return jh.cc.newUInt8();
|
||||
case 16:
|
||||
return jh.cc.newUInt16();
|
||||
case 32:
|
||||
return jh.cc.newUInt32();
|
||||
case 64:
|
||||
return jh.cc.newUInt64();
|
||||
default:
|
||||
throw std::runtime_error("Invalid reg size in get_reg_ptr");
|
||||
}
|
||||
}
|
||||
inline x86::Gp load_reg_from_mem(jit_holder& jh, unsigned idx){
|
||||
auto ptr = get_reg_ptr(jh, idx);
|
||||
auto reg = get_reg_for(jh, idx);
|
||||
jh.cc.mov(reg, ptr);
|
||||
return reg;
|
||||
}
|
||||
inline void write_reg_to_mem(jit_holder& jh, x86::Gp reg, unsigned idx){
|
||||
auto ptr = get_reg_ptr(jh, idx);
|
||||
jh.cc.mov(ptr, reg);
|
||||
}
|
||||
|
||||
void gen_instr_prologue(jit_holder& jh, addr_t pc){
|
||||
auto& cc = jh.cc;
|
||||
|
||||
cc.comment("\n//(*icount)++;");
|
||||
cc.inc(get_reg_ptr(jh, traits::ICOUNT));
|
||||
|
||||
cc.comment("\n//*pc=*next_pc;");
|
||||
cc.mov(get_reg_ptr(jh, traits::PC), jh.next_pc);
|
||||
|
||||
cc.comment("\n//*trap_state=*pending_trap;");
|
||||
cc.mov(get_reg_ptr(jh, traits::PENDING_TRAP), jh.trap_state);
|
||||
|
||||
cc.comment("\n//increment *next_pc");
|
||||
cc.mov(jh.next_pc, pc);
|
||||
|
||||
}
|
||||
void gen_instr_epilogue(jit_holder& jh){
|
||||
auto& cc = jh.cc;
|
||||
|
||||
cc.comment("\n//if(*trap_state!=0) goto trap_entry;");
|
||||
cc.test(jh.trap_state, jh.trap_state);
|
||||
cc.jnz(jh.trap_entry);
|
||||
|
||||
//Does this need to be done after every single instruction?
|
||||
cc.comment("\n//write back regs to mem");
|
||||
write_reg_to_mem(jh, jh.pc, traits::PC);
|
||||
write_reg_to_mem(jh, jh.next_pc, traits::NEXT_PC);
|
||||
write_reg_to_mem(jh, jh.trap_state, traits::TRAP_STATE);
|
||||
|
||||
|
||||
}
|
||||
void gen_block_prologue(jit_holder& jh) override{
|
||||
|
||||
jh.pc = load_reg_from_mem(jh, traits::PC);
|
||||
jh.next_pc = load_reg_from_mem(jh, traits::NEXT_PC);
|
||||
jh.trap_state = load_reg_from_mem(jh, traits::TRAP_STATE);
|
||||
}
|
||||
void gen_block_epilogue(jit_holder& jh) override{
|
||||
x86::Compiler& cc = jh.cc;
|
||||
cc.comment("\n//return *next_pc;");
|
||||
cc.ret(jh.next_pc);
|
||||
|
||||
cc.bind(jh.trap_entry);
|
||||
cc.comment("\n//enter_trap(core_ptr, *trap_state, *pc, 0);");
|
||||
|
||||
x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE);
|
||||
cc.mov(current_trap_state, get_reg_ptr(jh, traits::TRAP_STATE));
|
||||
|
||||
x86::Gp current_pc = get_reg_for(jh, traits::PC);
|
||||
cc.mov(current_pc, get_reg_ptr(jh, traits::PC));
|
||||
|
||||
x86::Gp instr = cc.newInt32("instr");
|
||||
cc.mov(instr, 0);
|
||||
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);
|
||||
cc.comment("\n//*last_branch = std::numeric_limits<uint32_t>::max();");
|
||||
cc.mov(get_reg_ptr(jh,traits::LAST_BRANCH), std::numeric_limits<uint32_t>::max());
|
||||
cc.comment("\n//return *next_pc;");
|
||||
cc.ret(jh.next_pc);
|
||||
|
||||
}
|
||||
//TODO implement
|
||||
|
||||
void gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t cause) {
|
||||
jh.cc.comment("//gen_raise");
|
||||
}
|
||||
void gen_wait(jit_holder& jh, unsigned type) {
|
||||
jh.cc.comment("//gen_wait");
|
||||
}
|
||||
void gen_leave(jit_holder& jh, unsigned lvl){
|
||||
jh.cc.comment("//gen_leave");
|
||||
}
|
||||
|
||||
enum operation {add, sub, band, bor, bxor, shl, sar , shr};
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value || std::is_same<T, x86::Gp>::value>>
|
||||
x86::Gp gen_operation(jit_holder& jh, operation op, x86::Gp a, T b){
|
||||
x86::Compiler& cc = jh.cc;
|
||||
switch (op) {
|
||||
case add: { cc.add(a, b); break; }
|
||||
case sub: { cc.sub(a, b); break; }
|
||||
case band: { cc.and_(a, b); break; }
|
||||
case bor: { cc.or_(a, b); break; }
|
||||
case bxor: { cc.xor_(a, b); break; }
|
||||
case shl: { cc.shl(a, b); break; }
|
||||
case sar: { cc.sar(a, b); break; }
|
||||
case shr: { cc.shr(a, b); break; }
|
||||
default: throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (operation)", op));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
enum three_operand_operation{imul, mul, idiv, div, srem, urem};
|
||||
|
||||
x86::Gp gen_operation(jit_holder& jh, three_operand_operation op, x86::Gp a, x86::Gp b){
|
||||
x86::Compiler& cc = jh.cc;
|
||||
switch (op) {
|
||||
case imul: {
|
||||
x86::Gp dummy = cc.newInt64();
|
||||
cc.imul(dummy, a.r64(), b.r64());
|
||||
return a;
|
||||
}
|
||||
case mul: {
|
||||
x86::Gp dummy = cc.newInt64();
|
||||
cc.mul(dummy, a.r64(), b.r64());
|
||||
return a;
|
||||
}
|
||||
case idiv: {
|
||||
x86::Gp dummy = cc.newInt64();
|
||||
cc.mov(dummy, 0);
|
||||
cc.idiv(dummy, a.r64(), b.r64());
|
||||
return a;
|
||||
}
|
||||
case div: {
|
||||
x86::Gp dummy = cc.newInt64();
|
||||
cc.mov(dummy, 0);
|
||||
cc.div(dummy, a.r64(), b.r64());
|
||||
return a;
|
||||
}
|
||||
case srem:{
|
||||
x86::Gp rem = cc.newInt32();
|
||||
cc.mov(rem, 0);
|
||||
auto a_reg = cc.newInt32();
|
||||
cc.mov(a_reg, a.r32());
|
||||
cc.idiv(rem, a_reg, b.r32());
|
||||
return rem;
|
||||
}
|
||||
case urem:{
|
||||
x86::Gp rem = cc.newInt32();
|
||||
cc.mov(rem, 0);
|
||||
auto a_reg = cc.newInt32();
|
||||
cc.mov(a_reg, a.r32());
|
||||
cc.div(rem, a_reg, b.r32());
|
||||
return rem;
|
||||
}
|
||||
|
||||
default: throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (three_operand)", op));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
|
||||
x86::Gp gen_operation(jit_holder& jh, three_operand_operation op, x86::Gp a, T b){
|
||||
x86::Gp b_reg = jh.cc.newInt32();
|
||||
/* switch(a.size()){
|
||||
case 1: b_reg = jh.cc.newInt8(); break;
|
||||
case 2: b_reg = jh.cc.newInt16(); break;
|
||||
case 4: b_reg = jh.cc.newInt32(); break;
|
||||
case 8: b_reg = jh.cc.newInt64(); break;
|
||||
default: throw std::runtime_error(fmt::format("Invalid size ({}) in gen operation", a.size()));
|
||||
} */
|
||||
jh.cc.mov(b_reg, b);
|
||||
return gen_operation(jh, op, a, b_reg);
|
||||
}
|
||||
enum comparison_operation{land, lor, eq, ne, lt, ltu, gt, gtu, lte, lteu, gte, gteu};
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value || std::is_same<T, x86::Gp>::value>>
|
||||
x86::Gp gen_operation(jit_holder& jh, comparison_operation op, x86::Gp a, T b){
|
||||
x86::Compiler& cc = jh.cc;
|
||||
x86::Gp tmp = cc.newInt8();
|
||||
cc.mov(tmp,1);
|
||||
Label label_then = cc.newLabel();
|
||||
cc.cmp(a,b);
|
||||
switch (op) {
|
||||
case eq: cc.je(label_then); break;
|
||||
case ne: cc.jne(label_then); break;
|
||||
case lt: cc.jl(label_then); break;
|
||||
case ltu: cc.jb(label_then); break;
|
||||
case gt: cc.jg(label_then); break;
|
||||
case gtu: cc.ja(label_then); break;
|
||||
case lte: cc.jle(label_then); break;
|
||||
case lteu: cc.jbe(label_then); break;
|
||||
case gte: cc.jge(label_then); break;
|
||||
case gteu: cc.jae(label_then); break;
|
||||
case land: {
|
||||
Label label_false = cc.newLabel();
|
||||
cc.cmp(a, 0);
|
||||
cc.je(label_false);
|
||||
auto b_reg = cc.newInt8();
|
||||
cc.mov(b_reg, b);
|
||||
cc.cmp(b_reg, 0);
|
||||
cc.je(label_false);
|
||||
cc.jmp(label_then);
|
||||
cc.bind(label_false);
|
||||
break;
|
||||
}
|
||||
case lor: {
|
||||
cc.cmp(a, 0);
|
||||
cc.jne(label_then);
|
||||
auto b_reg = cc.newInt8();
|
||||
cc.mov(b_reg, b);
|
||||
cc.cmp(b_reg, 0);
|
||||
cc.jne(label_then);
|
||||
break;
|
||||
}
|
||||
default: throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (comparison)", op));
|
||||
}
|
||||
cc.mov(tmp,0);
|
||||
cc.bind(label_then);
|
||||
return tmp;
|
||||
}
|
||||
enum binary_operation{lnot, inc, dec, bnot, neg};
|
||||
|
||||
x86::Gp gen_operation(jit_holder& jh, binary_operation op, x86::Gp a){
|
||||
x86::Compiler& cc = jh.cc;
|
||||
switch (op) {
|
||||
case lnot: throw std::runtime_error("Current operation not supported in gen_operation(lnot)");
|
||||
case inc: { cc.inc(a); break; }
|
||||
case dec: { cc.dec(a); break; }
|
||||
case bnot: { cc.not_(a); break; }
|
||||
case neg: { cc.neg(a); break; }
|
||||
default: throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (unary)", op));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/* template <typename T>
|
||||
inline typename std::enable_if_t<std::is_unsigned<T>::value, x86::Gp> gen_ext(jit_holder& jh, T val, unsigned size, bool is_signed) const {
|
||||
auto val_reg = get_reg_for(jh, sizeof(val)*8);
|
||||
auto tmp = get_reg_for(jh, size);
|
||||
jh.cc.mov(val_reg, val);
|
||||
if(is_signed) jh.cc.movsx(tmp, val_reg);
|
||||
else jh.cc.movzx(tmp,val_reg);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline typename std::enable_if_t<std::is_signed<T>::value, x86::Gp> gen_ext(jit_holder& jh, T val, unsigned size, bool is_signed) const {
|
||||
auto val_reg = get_reg_for(jh, sizeof(val)*8);
|
||||
auto tmp = get_reg_for(jh, size);
|
||||
jh.cc.mov(val_reg, val);
|
||||
if(is_signed) jh.cc.movsx(tmp, val_reg);
|
||||
else jh.cc.movzx(tmp,val_reg);
|
||||
return tmp;
|
||||
} */
|
||||
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
|
||||
inline x86::Gp gen_ext(jit_holder& jh, T val, unsigned size, bool is_signed) {
|
||||
auto val_reg = get_reg_for(jh, sizeof(val)*8);
|
||||
jh.cc.mov(val_reg, val);
|
||||
return gen_ext(jh, val_reg, size, is_signed);
|
||||
}
|
||||
//explicit Gp size cast
|
||||
inline x86::Gp gen_ext(jit_holder& jh, x86::Gp val, unsigned size, bool is_signed) {
|
||||
auto& cc = jh.cc;
|
||||
if(is_signed){
|
||||
switch(val.size()){
|
||||
case 1: cc.cbw(val); break;
|
||||
case 2: cc.cwde(val); break;
|
||||
case 4: cc.cdqe(val); break;
|
||||
case 8: break;
|
||||
default: throw std::runtime_error("Invalid register size in gen_ext");
|
||||
}
|
||||
}
|
||||
switch(size){
|
||||
case 8: cc.and_(val,std::numeric_limits<uint8_t>::max()); return val.r8();
|
||||
case 16: cc.and_(val,std::numeric_limits<uint16_t>::max()); return val.r16();
|
||||
case 32: cc.and_(val,std::numeric_limits<uint32_t>::max()); return val.r32();
|
||||
case 64: cc.and_(val,std::numeric_limits<uint64_t>::max()); return val.r64();
|
||||
case 128: return val.r64();
|
||||
default: throw std::runtime_error("Invalid size in gen_ext");
|
||||
}
|
||||
}
|
||||
|
||||
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, uint32_t length){
|
||||
x86::Compiler& cc = jh.cc;
|
||||
auto ret_reg = cc.newInt32();
|
||||
|
||||
auto mem_type_reg = cc.newInt32();
|
||||
cc.mov(mem_type_reg, type);
|
||||
|
||||
auto space_reg = cc.newInt32();
|
||||
cc.mov(space_reg, static_cast<uint16_t>(iss::address_type::VIRTUAL));
|
||||
|
||||
auto val_ptr = cc.newUIntPtr();
|
||||
cc.mov(val_ptr, read_mem_buf);
|
||||
|
||||
InvokeNode* invokeNode;
|
||||
uint64_t mask = 0;
|
||||
x86::Gp val_reg = cc.newInt64();
|
||||
|
||||
switch(length){
|
||||
case 1:{
|
||||
cc.invoke(&invokeNode, &read_mem1, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uintptr_t>());
|
||||
mask = std::numeric_limits<uint8_t>::max();
|
||||
break;
|
||||
}
|
||||
case 2:{
|
||||
cc.invoke(&invokeNode, &read_mem2, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uintptr_t>());
|
||||
mask = std::numeric_limits<uint16_t>::max();
|
||||
break;
|
||||
}
|
||||
case 4:{
|
||||
cc.invoke(&invokeNode, &read_mem4, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uintptr_t>());
|
||||
mask = std::numeric_limits<uint32_t>::max();
|
||||
break;
|
||||
}
|
||||
case 8:{
|
||||
cc.invoke(&invokeNode, &read_mem8, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uintptr_t>());
|
||||
mask = std::numeric_limits<uint64_t>::max();
|
||||
break;
|
||||
}
|
||||
default: throw std::runtime_error(fmt::format("Invalid length ({}) in gen_read_mem",length));
|
||||
}
|
||||
|
||||
invokeNode->setRet(0, ret_reg);
|
||||
invokeNode->setArg(0, jh.arch_if_ptr);
|
||||
invokeNode->setArg(1, space_reg);
|
||||
invokeNode->setArg(2, mem_type_reg);
|
||||
invokeNode->setArg(3, addr);
|
||||
invokeNode->setArg(4, val_ptr);
|
||||
|
||||
cc.mov(val_reg, x86::ptr_64(val_ptr));
|
||||
cc.and_(val_reg, mask);
|
||||
cc.cmp(ret_reg,0);
|
||||
cc.jne(jh.trap_entry);
|
||||
return val_reg;
|
||||
}
|
||||
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp length){
|
||||
uint32_t length_val = 0;
|
||||
auto length_ptr = jh.cc.newIntPtr();
|
||||
jh.cc.mov(length_ptr, &length_val);
|
||||
jh.cc.mov(x86::ptr_32(length_ptr),length);
|
||||
|
||||
return gen_read_mem(jh, type, addr, length);
|
||||
}
|
||||
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp length){
|
||||
auto addr_reg = jh.cc.newInt64();
|
||||
jh.cc.mov(addr_reg, addr);
|
||||
|
||||
uint32_t length_val = 0;
|
||||
auto length_ptr = jh.cc.newIntPtr();
|
||||
jh.cc.mov(length_ptr, &length_val);
|
||||
jh.cc.mov(x86::ptr_32(length_ptr),length);
|
||||
|
||||
return gen_read_mem(jh, type, addr_reg, length_val);
|
||||
}
|
||||
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, uint32_t length){
|
||||
auto addr_reg = jh.cc.newInt64();
|
||||
jh.cc.mov(addr_reg, addr);
|
||||
|
||||
return gen_read_mem(jh, type, addr_reg, length);
|
||||
}
|
||||
inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, int64_t val){
|
||||
auto val_reg = jh.cc.newInt64();
|
||||
jh.cc.mov(val_reg, val);
|
||||
gen_write_mem(jh, type, addr, val_reg);
|
||||
|
||||
}
|
||||
inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp val){
|
||||
x86::Compiler& cc = jh.cc;
|
||||
|
||||
auto mem_type_reg = cc.newInt32();
|
||||
jh.cc.mov(mem_type_reg, type);
|
||||
auto space_reg = cc.newInt32();
|
||||
jh.cc.mov(space_reg, static_cast<uint16_t>(iss::address_type::VIRTUAL));
|
||||
auto ret_reg = cc.newInt32();
|
||||
InvokeNode* invokeNode;
|
||||
|
||||
if(val.isGpb()){
|
||||
cc.invoke(&invokeNode, &write_mem1, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint8_t>());
|
||||
}
|
||||
else if(val.isGpw()){
|
||||
cc.invoke(&invokeNode, &write_mem2, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint16_t>());
|
||||
}
|
||||
else if(val.isGpd()){
|
||||
cc.invoke(&invokeNode, &write_mem4, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint32_t>());
|
||||
}
|
||||
else if(val.isGpq()){
|
||||
cc.invoke(&invokeNode, &write_mem8, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint64_t>());
|
||||
}
|
||||
else throw std::runtime_error("Invalid register size in gen_write_mem");
|
||||
|
||||
invokeNode->setRet(0,ret_reg);
|
||||
invokeNode->setArg(0, jh.arch_if_ptr);
|
||||
invokeNode->setArg(1, space_reg);
|
||||
invokeNode->setArg(2, mem_type_reg);
|
||||
invokeNode->setArg(3, addr);
|
||||
invokeNode->setArg(4, val);
|
||||
|
||||
cc.cmp(ret_reg,0);
|
||||
cc.jne(jh.trap_entry);
|
||||
|
||||
}
|
||||
inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp val){
|
||||
auto addr_reg = jh.cc.newInt64();
|
||||
jh.cc.mov(addr_reg, addr);
|
||||
gen_write_mem(jh, type, addr_reg, val);
|
||||
}
|
||||
inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, int64_t val){
|
||||
auto val_reg = jh.cc.newInt64();
|
||||
jh.cc.mov(val_reg, val);
|
||||
|
||||
auto addr_reg = jh.cc.newInt64();
|
||||
jh.cc.mov(addr_reg, addr);
|
||||
gen_write_mem(jh, type, addr_reg, val_reg);
|
||||
|
||||
}
|
3786
src/vm/asmjit/vm_tgc5c.cpp
Normal file
3786
src/vm/asmjit/vm_tgc5c.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2710
src/vm/interp/vm_tgc5c.cpp
Normal file
2710
src/vm/interp/vm_tgc5c.cpp
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
4561
src/vm/llvm/vm_tgc5c.cpp
Normal file
4561
src/vm/llvm/vm_tgc5c.cpp
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user