From 9b4ff47e62611961556f119102af992e3e15fa43 Mon Sep 17 00:00:00 2001 From: Knute Lingaard Date: Fri, 4 Jul 2025 10:32:32 -0500 Subject: [PATCH 1/4] Removed fsl submodule --- .gitmodules | 3 --- fsl | 1 - 2 files changed, 4 deletions(-) delete mode 160000 fsl diff --git a/.gitmodules b/.gitmodules index 1587bd6c..47909a15 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,6 +4,3 @@ [submodule "stf_lib"] path = stf_lib url = https://github.com/sparcians/stf_lib.git -[submodule "fsl"] - path = fsl - url = https://github.com/Condor-Performance-Modeling/fsl diff --git a/fsl b/fsl deleted file mode 160000 index a5d1091a..00000000 --- a/fsl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a5d1091acc368c21203b78783d47b71f8900d6c0 From e2ee8f83f1af56035225d8916c17c85c9aef2828 Mon Sep 17 00:00:00 2001 From: Knute Lingaard Date: Fri, 4 Jul 2025 10:34:07 -0500 Subject: [PATCH 2/4] Added FSL from CondorComputing under Apache License 2.0 --- fsl/.clang-format | 194 +++ fsl/.clang-tidy | 22 + fsl/.gitignore | 8 + fsl/CMakeLists.txt | 62 + fsl/LICENSE | 201 +++ fsl/Makefile | 48 + fsl/README.md | 72 + fsl/Vars.mk | 21 + fsl/docs/CMakeLists.txt | 41 + fsl/docs/DoxyApi | 368 +++++ fsl/docs/DoxyInterp | 358 +++++ fsl/docs/Makefile | 23 + fsl/docs/deprecated/BNF.md | 177 +++ fsl/docs/deprecated/FSL_x2.md | 1220 +++++++++++++++ fsl/docs/deprecated/FSL_x3.md | 1231 +++++++++++++++ fsl/docs/deprecated/commonlib.fsl | 11 + .../notes1_old_syntax_description.md | 205 +++ fsl/docs/deprecated/sequencelib.fsl | 75 + fsl/docs/deprecated/sequencelib.q.sav | 75 + fsl/docs/deprecated/test1.fsl | 33 + fsl/docs/deprecated/test2.fsl | 46 + fsl/docs/fsl_examples/dhrystone.fsl | 315 ++++ fsl/docs/md/FSL_API_USER_REF.md | 0 fsl/docs/md/FSL_APPLICATION_REF.md | 0 fsl/docs/md/FSL_USER_REF.md | 1249 +++++++++++++++ fsl/docs/md/RISCV_ENCODING_FORMATS.md | 142 ++ fsl/fsl_api/CMakeLists.txt | 4 + fsl/fsl_api/FieldExtractor.h | 280 ++++ fsl/fsl_api/Fusion.h | 427 ++++++ fsl/fsl_api/FusionContext.h | 144 ++ fsl/fsl_api/FusionExceptions.h | 235 +++ fsl/fsl_api/FusionGroup.h | 333 ++++ fsl/fsl_api/FusionTypes.h | 57 + fsl/fsl_api/HCache.h | 164 ++ fsl/fsl_api/Instruction.h | 146 ++ fsl/fsl_api/MachineInfo.h | 77 + fsl/fsl_api/Makefile | 4 + fsl/fsl_api/RadixTrie.h | 120 ++ fsl/fsl_api/uArchInfo.h | 191 +++ fsl/fsl_api/uArchInfoExceptions.h | 89 ++ fsl/fsl_interp/CMakeLists.txt | 179 +++ fsl/fsl_interp/Makefile.sav | 78 + fsl/fsl_interp/fsl.l | 290 ++++ fsl/fsl_interp/fsl.y | 767 ++++++++++ fsl/fsl_interp/inc/FslParser.h | 251 +++ fsl/fsl_interp/inc/Msg.h | 130 ++ fsl/fsl_interp/inc/Options.h | 75 + fsl/fsl_interp/src/FslParser.cpp | 138 ++ fsl/fsl_interp/src/Options.cpp | 105 ++ fsl/fsl_interp/src/c99.l | 212 +++ fsl/fsl_interp/src/c99.y | 482 ++++++ fsl/fsl_interp/src/fsl.l | 265 ++++ fsl/fsl_interp/src/fsl.l.sav | 136 ++ fsl/fsl_interp/src/fsl.y | 534 +++++++ fsl/fsl_interp/src/fsl.y.2 | 803 ++++++++++ fsl/fsl_interp/src/fsl.y.sav | 356 +++++ fsl/fsl_interp/src/main.cpp | 29 + fsl/test/CMakeLists.txt | 27 + fsl/test/Makefile | 17 + fsl/test/api/CMakeLists.txt | 46 + fsl/test/api/Makefile | 67 + fsl/test/api/fsl/syntax1.fsl | 12 + fsl/test/api/fsl/syntax2.fsl | 36 + fsl/test/api/fsl/test1.fsl | 35 + fsl/test/api/fsl/test2.fsl | 46 + fsl/test/api/fsl/test3.fsl | 46 + fsl/test/api/fsl/test4.fsl | 75 + fsl/test/api/fsl/test5.fsl | 78 + fsl/test/api/inc/ApiTestBench.h | 277 ++++ fsl/test/api/inc/Options.h | 83 + fsl/test/api/json/isa_rv64c.json | 293 ++++ fsl/test/api/json/isa_rv64g.json | 1354 +++++++++++++++++ fsl/test/api/src/ApiTestBench.cpp | 788 ++++++++++ fsl/test/api/src/FslTests.cpp | 103 ++ fsl/test/api/src/Options.cpp | 108 ++ fsl/test/api/src/TestData.cpp | 130 ++ fsl/test/api/src/TestFieldExtractor.cpp | 125 ++ fsl/test/api/src/main.cpp | 46 + fsl/test/api/symtab_actual.txt | 8 + fsl/test/api/symtab_expect.txt | 8 + fsl/test/common/Msg.h | 152 ++ fsl/test/interp/CMakeLists.txt | 29 + fsl/test/interp/Makefile | 35 + .../interp/syntax_tests/_1_syntax_test.fsl | 406 +++++ .../interp/syntax_tests/_2_syntax_test.fsl | 366 +++++ fsl/test/interp/syntax_tests/all_comments.fsl | 47 + fsl/test/interp/syntax_tests/empty_file.fsl | 0 fsl/test/interp/syntax_tests/sample1.fsl | 35 + fsl/test/interp/syntax_tests/syntax1.fsl | 12 + fsl/test/interp/syntax_tests/syntax2.fsl | 36 + fsl/test/interp/syntax_tests/test3.fsl | 46 + fsl/test/interp/syntax_tests/test4.fsl | 76 + fsl/version.txt | 1 + 93 files changed, 18347 insertions(+) create mode 100644 fsl/.clang-format create mode 100644 fsl/.clang-tidy create mode 100644 fsl/.gitignore create mode 100644 fsl/CMakeLists.txt create mode 100644 fsl/LICENSE create mode 100644 fsl/Makefile create mode 100644 fsl/README.md create mode 100644 fsl/Vars.mk create mode 100644 fsl/docs/CMakeLists.txt create mode 100644 fsl/docs/DoxyApi create mode 100644 fsl/docs/DoxyInterp create mode 100644 fsl/docs/Makefile create mode 100644 fsl/docs/deprecated/BNF.md create mode 100644 fsl/docs/deprecated/FSL_x2.md create mode 100644 fsl/docs/deprecated/FSL_x3.md create mode 100644 fsl/docs/deprecated/commonlib.fsl create mode 100644 fsl/docs/deprecated/notes1_old_syntax_description.md create mode 100644 fsl/docs/deprecated/sequencelib.fsl create mode 100644 fsl/docs/deprecated/sequencelib.q.sav create mode 100644 fsl/docs/deprecated/test1.fsl create mode 100644 fsl/docs/deprecated/test2.fsl create mode 100644 fsl/docs/fsl_examples/dhrystone.fsl create mode 100644 fsl/docs/md/FSL_API_USER_REF.md create mode 100644 fsl/docs/md/FSL_APPLICATION_REF.md create mode 100644 fsl/docs/md/FSL_USER_REF.md create mode 100644 fsl/docs/md/RISCV_ENCODING_FORMATS.md create mode 100644 fsl/fsl_api/CMakeLists.txt create mode 100644 fsl/fsl_api/FieldExtractor.h create mode 100644 fsl/fsl_api/Fusion.h create mode 100644 fsl/fsl_api/FusionContext.h create mode 100644 fsl/fsl_api/FusionExceptions.h create mode 100644 fsl/fsl_api/FusionGroup.h create mode 100644 fsl/fsl_api/FusionTypes.h create mode 100644 fsl/fsl_api/HCache.h create mode 100644 fsl/fsl_api/Instruction.h create mode 100644 fsl/fsl_api/MachineInfo.h create mode 100644 fsl/fsl_api/Makefile create mode 100644 fsl/fsl_api/RadixTrie.h create mode 100644 fsl/fsl_api/uArchInfo.h create mode 100644 fsl/fsl_api/uArchInfoExceptions.h create mode 100644 fsl/fsl_interp/CMakeLists.txt create mode 100644 fsl/fsl_interp/Makefile.sav create mode 100644 fsl/fsl_interp/fsl.l create mode 100644 fsl/fsl_interp/fsl.y create mode 100644 fsl/fsl_interp/inc/FslParser.h create mode 100644 fsl/fsl_interp/inc/Msg.h create mode 100644 fsl/fsl_interp/inc/Options.h create mode 100644 fsl/fsl_interp/src/FslParser.cpp create mode 100644 fsl/fsl_interp/src/Options.cpp create mode 100644 fsl/fsl_interp/src/c99.l create mode 100644 fsl/fsl_interp/src/c99.y create mode 100644 fsl/fsl_interp/src/fsl.l create mode 100644 fsl/fsl_interp/src/fsl.l.sav create mode 100644 fsl/fsl_interp/src/fsl.y create mode 100644 fsl/fsl_interp/src/fsl.y.2 create mode 100644 fsl/fsl_interp/src/fsl.y.sav create mode 100644 fsl/fsl_interp/src/main.cpp create mode 100644 fsl/test/CMakeLists.txt create mode 100644 fsl/test/Makefile create mode 100644 fsl/test/api/CMakeLists.txt create mode 100644 fsl/test/api/Makefile create mode 100644 fsl/test/api/fsl/syntax1.fsl create mode 100644 fsl/test/api/fsl/syntax2.fsl create mode 100644 fsl/test/api/fsl/test1.fsl create mode 100644 fsl/test/api/fsl/test2.fsl create mode 100644 fsl/test/api/fsl/test3.fsl create mode 100644 fsl/test/api/fsl/test4.fsl create mode 100644 fsl/test/api/fsl/test5.fsl create mode 100644 fsl/test/api/inc/ApiTestBench.h create mode 100644 fsl/test/api/inc/Options.h create mode 100644 fsl/test/api/json/isa_rv64c.json create mode 100644 fsl/test/api/json/isa_rv64g.json create mode 100644 fsl/test/api/src/ApiTestBench.cpp create mode 100644 fsl/test/api/src/FslTests.cpp create mode 100644 fsl/test/api/src/Options.cpp create mode 100644 fsl/test/api/src/TestData.cpp create mode 100644 fsl/test/api/src/TestFieldExtractor.cpp create mode 100644 fsl/test/api/src/main.cpp create mode 100644 fsl/test/api/symtab_actual.txt create mode 100644 fsl/test/api/symtab_expect.txt create mode 100644 fsl/test/common/Msg.h create mode 100644 fsl/test/interp/CMakeLists.txt create mode 100644 fsl/test/interp/Makefile create mode 100644 fsl/test/interp/syntax_tests/_1_syntax_test.fsl create mode 100644 fsl/test/interp/syntax_tests/_2_syntax_test.fsl create mode 100644 fsl/test/interp/syntax_tests/all_comments.fsl create mode 100644 fsl/test/interp/syntax_tests/empty_file.fsl create mode 100644 fsl/test/interp/syntax_tests/sample1.fsl create mode 100644 fsl/test/interp/syntax_tests/syntax1.fsl create mode 100644 fsl/test/interp/syntax_tests/syntax2.fsl create mode 100644 fsl/test/interp/syntax_tests/test3.fsl create mode 100644 fsl/test/interp/syntax_tests/test4.fsl create mode 100644 fsl/version.txt diff --git a/fsl/.clang-format b/fsl/.clang-format new file mode 100644 index 00000000..a8b12453 --- /dev/null +++ b/fsl/.clang-format @@ -0,0 +1,194 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: true + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true + +# To enable in format-16 +# BreakArrays: true +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Allman +BreakBeforeInheritanceComma: false +BreakInheritanceList: AfterColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: AfterColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 75 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: CurrentLine +BasedOnStyle: '' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: false +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Left +PPIndentWidth: -1 +ReferenceAlignment: Middle +ReflowComments: true +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Always +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +SortIncludes: false +# Supported in clang-format 15+ +#InsertBraces: true diff --git a/fsl/.clang-tidy b/fsl/.clang-tidy new file mode 100644 index 00000000..29337914 --- /dev/null +++ b/fsl/.clang-tidy @@ -0,0 +1,22 @@ +Checks: > + google-*, + -google-runtime-references, + -google-build-using-namespace, + -google-readability-todo, + modernize-*, + cppcoreguidelines-*, + clang-analyzer-*, + -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, + performance-* +WarningsAsErrors: '*' +HeaderFilterRegex: '.*' +FormatStyle: 'google' +CheckOptions: + - key: google-readability-braces-around-statements.ShortStatementLines + value: '1' + - key: google-readability-function-size.StatementThreshold + value: '800' + - key: google-readability-namespace-comments.ShortNamespaceLines + value: '10' + - key: google-readability-namespace-comments.SpacesBeforeComments + value: '2' diff --git a/fsl/.gitignore b/fsl/.gitignore new file mode 100644 index 00000000..0cf30228 --- /dev/null +++ b/fsl/.gitignore @@ -0,0 +1,8 @@ +fsl_interp/bin/ +fsl_interp/obj/ +modules/ +docs/*_warn.log +test/api/PASSFAIL +test/interp/PASSFAIL +release/ +build/ diff --git a/fsl/CMakeLists.txt b/fsl/CMakeLists.txt new file mode 100644 index 00000000..c8b47b20 --- /dev/null +++ b/fsl/CMakeLists.txt @@ -0,0 +1,62 @@ +cmake_minimum_required(VERSION 3.10) + +add_compile_options(-Wall -Werror) +find_package(FLEX 2.6 REQUIRED) +find_package(BISON 3.8 REQUIRED) + +project(fsl) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +set(CCSD ${CMAKE_CURRENT_SOURCE_DIR}) +set(CBD ${CMAKE_BINARY_DIR}) + +# Check if FSL_MAVIS_PATH is set +if(DEFINED FSL_MAVIS_PATH) + set(FSL_MAVIS_DIR ${FSL_MAVIS_PATH}) +else() + set(FSL_MAVIS_DIR "${CCSD}/modules/cpm.mavis") +endif() + +if(NOT TARGET mavis) + add_subdirectory(${FSL_MAVIS_DIR}) +endif() + +# Include subdirectories +#add_subdirectory(modules/cpm.mavis) +add_subdirectory(fsl_interp) +add_subdirectory(fsl_api) +add_subdirectory(docs EXCLUDE_FROM_ALL) +#add_subdirectory(test) + +# Custom target for building documentation +add_custom_target(docs + COMMAND ${CMAKE_COMMAND} --build ${CBD} + --target docs_internal + COMMENT "Generating all documentation" +) + +add_dependencies(docs docs_internal) + +# Find clang-tidy executable +find_program(CLANG_TIDY "clang-tidy") + +# Ensure all source and header files are included +file(GLOB_RECURSE TIDY_FILES + ${CCSD}/fsl_interp/src/*.cpp + ${CCSD}/fsl_interp/inc/*.h + ${CCSD}/fsl_api/*.cpp + ${CCSD}/fsl_api/*.h + # Add other directories or specific source files here +) + +# Custom target for running clang-tidy and logging output +if(CLANG_TIDY) + add_custom_target(clang-tidy + COMMAND ${CLANG_TIDY} -p ${CBD} ${TIDY_FILES} > ${CBD}/clang-tidy.log 2>&1 + COMMENT "Running clang-tidy and log output in clang-tidy.log" + WORKING_DIRECTORY ${CCSD} + ) +else() + message(WARNING "clang-tidy not found!") +endif() diff --git a/fsl/LICENSE b/fsl/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/fsl/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/fsl/Makefile b/fsl/Makefile new file mode 100644 index 00000000..b552e1bc --- /dev/null +++ b/fsl/Makefile @@ -0,0 +1,48 @@ +.PHONY: interp api fusion \ + test \ + regress \ + docs \ + docs_interp \ + docs_api \ + help \ + clean + +MAVIS_LIB = modules/cpm.mavis/release/libmavis.a + +default: $(MAVIS_LIB) interp api test docs + +$(MAVIS_LIB): + cd modules/cpm.mavis; \ + mkdir -p release; \ + cd release; \ + cmake .. -DCMAKE_BUILD_TYPE=Release; \ + make -j32; + +interp: $(MAVIS_LIB) + $(MAKE) -C fsl_interp only + +api: $(MAVIS_LIB) + # Header only. Nothing to do at the moment + # $(MAKE) -C fsl_api only + +test: $(MAVIS_LIB) regress + +regress: + $(MAKE) -C ./test regress + +docs: docs_interp docs_api + +docs_interp: + $(MAKE) -C ./docs docs_interp + +docs_api: + $(MAKE) -C ./docs docs_api + +help: + @echo "-E: Implement make help" + +clean: + $(MAKE) -C fsl_interp clean + $(MAKE) -C fsl_api clean + $(MAKE) -C test clean + $(MAKE) -C docs clean diff --git a/fsl/README.md b/fsl/README.md new file mode 100644 index 00000000..c1b452ce --- /dev/null +++ b/fsl/README.md @@ -0,0 +1,72 @@ +# Fusion/Fracture Specification Language + +# Brief +Repo for FSL Interpreter, FSL API and a fusion implementation + +- fsl/api - API source and stand alone tests +- fsl/docs - API and interpreter documentation +- fsl/interp - Interpreter source and stand alone tests +- fsl/fusion - Instruction fusion implementation for Olympia +- fsl/test - Combined API and interpreter tests + +# Submodules + +FSL has a copy of the cpm.mavis sub-module, https://github.com/Condor-Performance-Modeling/cpm.mavis + +# Quick start + +``` +git clone --recurse-submodules https://github.com/Condor-Performance-Modeling/fsl.git +cd fsl +mkdir release +cd release +cmake .. +make -j32 + +To make the docs: +make docs + +The html documentation will be in fsl/docs/docs_interp and fsl/docs/docs_api. +See below for user guides and references. + +``` + +# Documentation - fsl/docs + +Some of the references to docs below are forward looking to future docs. + +``` + docs/md/FSL_USER_REF.md -- Fusion/Fracture Specification Language + user reference guide, see also the + interp doxygen files + + docs/md/FSL_API_USER_REF.md -- Fusion/Fracture C++ API user reference, + see also the API doxygen files + (Planned) + + docs/md/FSL_APPLICATION_REF.md -- A walk through of the Olympia fusion + implementation using FSL. + (Planned) + + docs/md/RISCV_ENCODING_FORMATS.md -- Self created encoding formats. + You should consult the official RV + documents for critical uses. + + docs/docs_interp/index.html -- Doxygen generated implementation + documents for the interpreter. + Create with CMake. + + docs/docs_api/index.html -- Doxygen generated implementation + documents for the C++ API. + Create with CMake. +``` + +# FSL Examples + +``` + docs/fsl_examples -- FSL syntax examples + + test/interp/syntax_tests -- Syntax example used as part of the + regression. +``` + diff --git a/fsl/Vars.mk b/fsl/Vars.mk new file mode 100644 index 00000000..e9c9915e --- /dev/null +++ b/fsl/Vars.mk @@ -0,0 +1,21 @@ +# Default compiler/flags +CXX = g++ +CPP = g++ +CC = gcc + +CFLAGS = -Wall -g +CPPFLAGS = -Wall -g + +# Doxygen +DOXY=doxygen + +# Yacc/Bison +BISON = bison +#B_CNTR = -Wcounterexamples +BISONFLAGS = -d $(B_CNTR) + +# Lex/Flex +FLEX = flex + +BOOST_INC= -I/usr/include/boost +BOOST_LIB= -L/usr/lib/x86_64-linux-gnu diff --git a/fsl/docs/CMakeLists.txt b/fsl/docs/CMakeLists.txt new file mode 100644 index 00000000..b08614b7 --- /dev/null +++ b/fsl/docs/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.10) +project(fsl_docs) + +set(DOXY doxygen) +set(CCBD ${CMAKE_CURRENT_BINARY_DIR}) +set(CCSD ${CMAKE_CURRENT_SOURCE_DIR}) + +# Path to the Doxyfile configurations +set(DOXYFILE_INTERP ${CCSD}/DoxyInterp) +set(DOXYFILE_API ${CCSD}/DoxyApi) + + +# Define the docs_interp target +add_custom_target(docs_interp + COMMAND ${CMAKE_COMMAND} -E make_directory ${CCBD}/docs_interp + COMMAND ${DOXY} ${DOXYFILE_INTERP} + WORKING_DIRECTORY ${CCSD} + COMMENT "Generating documentation for interp" +) + +# Define the docs_api target +add_custom_target(docs_api + COMMAND ${CMAKE_COMMAND} -E make_directory ${CCBD}/docs_api + COMMAND ${DOXY} ${DOXYFILE_API} + WORKING_DIRECTORY ${CCSD} + COMMENT "Generating documentation for API" +) + +# Define the docs_internal target that depends on docs_interp and docs_api +add_custom_target(docs_internal + DEPENDS docs_interp docs_api + COMMENT "Generating all documentation" +) + +# Define the clean_docs target +add_custom_target(clean_docs + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CCSD}/docs_interp + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CCSD}/docs_api + COMMAND ${CMAKE_COMMAND} -E remove ${CCSD}/*_warn.log + COMMENT "Cleaning documentation directories and log files" +) diff --git a/fsl/docs/DoxyApi b/fsl/docs/DoxyApi new file mode 100644 index 00000000..5ea58f06 --- /dev/null +++ b/fsl/docs/DoxyApi @@ -0,0 +1,368 @@ +# Doxyfile 1.9.1 + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = ./docs_api_warn.log +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "CAM Fusion API" +PROJECT_NUMBER = +PROJECT_BRIEF = +PROJECT_LOGO = +OUTPUT_DIRECTORY = +CREATE_SUBDIRS = NO +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +#OUTPUT_TEXT_DIRECTION = None +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +JAVADOC_BANNER = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +PYTHON_DOCSTRING = YES +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +OPTIMIZE_OUTPUT_SLICE = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +TOC_INCLUDE_HEADINGS = 5 +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = YES +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +NUM_PROC_THREADS = 1 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_PRIV_VIRTUAL = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +RESOLVE_UNNAMED_PARAMS = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = \ + ../fsl_api/FieldExtractor.h \ + ../fsl_api/Fusion.h \ + ../fsl_api/FusionContext.h \ + ../fsl_api/FusionExceptions.h \ + ../fsl_api/FusionGroup.h \ + ../fsl_api/FusionTypes.h \ + ../fsl_api/HCache.h \ + ../fsl_api/MachineInfo.h \ + ../fsl_api/RadixTrie.h \ + ../test/common/Msg.h \ + ../test/api/inc/Options.h \ + ../test/api/inc/ApiTestBench.h + +# README.md + +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.in \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.m \ + *.markdown \ + *.md +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = README.md +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = docs_api +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +#HTML_TIMESTAMP = NO +HTML_DYNAMIC_MENUS = YES +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = NO +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +HTML_FORMULA_FORMAT = png +FORMULA_FONTSIZE = 10 +#FORMULA_TRANSPARENT = YES +FORMULA_MACROFILE = +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +LATEX_CMD_NAME = +MAKEINDEX_CMD_NAME = makeindex +LATEX_MAKEINDEX_CMD = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +#LATEX_TIMESTAMP = NO +LATEX_EMOJI_DIRECTORY = +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#RTF_SOURCE_CODE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +XML_NS_MEMB_FILE_SCOPE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +#DOCBOOK_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +#CLASS_DIAGRAMS = YES +DIA_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +DOT_NUM_THREADS = 0 +#DOT_FONTNAME = Helvetica +#DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +DOT_UML_DETAILS = NO +DOT_WRAP_THRESHOLD = 17 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_CFG_FILE = +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +#DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/fsl/docs/DoxyInterp b/fsl/docs/DoxyInterp new file mode 100644 index 00000000..4f765505 --- /dev/null +++ b/fsl/docs/DoxyInterp @@ -0,0 +1,358 @@ +# Doxyfile 1.9.1 + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = docs_interp_warn.log +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "CAM Fusion API" +PROJECT_NUMBER = +PROJECT_BRIEF = +PROJECT_LOGO = +OUTPUT_DIRECTORY = +CREATE_SUBDIRS = NO +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +#OUTPUT_TEXT_DIRECTION = None +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +JAVADOC_BANNER = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +PYTHON_DOCSTRING = YES +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +OPTIMIZE_OUTPUT_SLICE = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +TOC_INCLUDE_HEADINGS = 5 +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = YES +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +NUM_PROC_THREADS = 1 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_PRIV_VIRTUAL = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +RESOLVE_UNNAMED_PARAMS = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = \ + ../fsl_interp/inc/FslParser.h \ + ../fsl_interp/inc/Options.h \ + ../fsl_interp/inc/Msg.h + +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.in \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.m \ + *.markdown \ + *.md + +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = README.md +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = docs_interp +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +#HTML_TIMESTAMP = NO +HTML_DYNAMIC_MENUS = YES +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = NO +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +HTML_FORMULA_FORMAT = png +FORMULA_FONTSIZE = 10 +#FORMULA_TRANSPARENT = YES +FORMULA_MACROFILE = +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +LATEX_CMD_NAME = +MAKEINDEX_CMD_NAME = makeindex +LATEX_MAKEINDEX_CMD = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +#LATEX_TIMESTAMP = NO +LATEX_EMOJI_DIRECTORY = +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#RTF_SOURCE_CODE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +XML_NS_MEMB_FILE_SCOPE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +#DOCBOOK_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +#CLASS_DIAGRAMS = YES +DIA_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +DOT_NUM_THREADS = 0 +#DOT_FONTNAME = Helvetica +#DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +DOT_UML_DETAILS = NO +DOT_WRAP_THRESHOLD = 17 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_CFG_FILE = +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +#DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/fsl/docs/Makefile b/fsl/docs/Makefile new file mode 100644 index 00000000..8975ce70 --- /dev/null +++ b/fsl/docs/Makefile @@ -0,0 +1,23 @@ +.PHONY: default \ + docs \ + docs_interp \ + docs_api \ + clean + +include ../Vars.mk + +default: docs + +docs: docs_interp docs_api + +docs_interp: + -mkdir -p docs_interp + $(DOXY) DoxyInterp + +docs_api: + -mkdir -p docs_api + $(DOXY) DoxyApi + +clean: + -rm -rf interp fusion api docs_interp docs_api + -rm -f *_warn.log diff --git a/fsl/docs/deprecated/BNF.md b/fsl/docs/deprecated/BNF.md new file mode 100644 index 00000000..8f78fc1a --- /dev/null +++ b/fsl/docs/deprecated/BNF.md @@ -0,0 +1,177 @@ +# FSL BNF + +This is the raw BNF converted from the bison grammar + +``` + ::= | + + ::= | | + + ::= TRANSFORM '{' '}' | TRANSFORM '{' '}' + + ::= | + + ::= PROLOG | | | | | | | | + + ::= SETOF '=' '.' + + ::= '.' | + + ::= '(' ')' + + ::= /* empty */ | | | '{' '}' | '*' | '{' '}' + + ::= PROLOG '{' '}' | PROLOG '{' '}' + + ::= | + + ::= ISA | UARCH | IOPUT + + ::= ISA + + ::= UARCH + + ::= IOPUT + + ::= '=' | '=' '{' '}' + + ::= | + + ::= CONSTRAINTS '{' '}' | CONSTRAINTS '(' ')' '{' '}' + + ::= /* empty */ | + + ::= | + + ::= | | | LEFT_OP | '.' '.' | '.' | + + ::= LE_OP | GE_OP | EQ_OP | NE_OP + + ::= CONVERSION '{' '}' | CONVERSION '(' ')' '{' '}' + + ::= | + + ::= | | | | | | '.' | '.' REPLACE '(' ')' + + ::= | ',' + + ::= | | OPC | | '=' + + ::= /* empty */ | '.' + + ::= | ',' + + ::= '[' ']' | '[' ':' ']' | '[' ']' | '[' ':' ']' + + ::= | '.' + + ::= MNEMONIC | ENCODE_ORDER | WRITEPORTS | READPORTS | REQUIREDBITS | ENCODING | OPC | SRC | DST | RSX | IMM | TYPE | HASATTR | MORPH + + ::= INSTR + + ::= INSTR '(' ')' | INSTR '(' '{' '}' ')' | INSTR '(' '{' '}' ')' | INSTR '(' '.' '(' ')' ')' | INSTR '(' '(' ')' ')' + + ::= | ',' + + ::= '[' ']' '.' ENCODING + + ::= ENCODING + + ::= ENCODING '(' ')' | ENCODING '(' '{' '}' ')' + + ::= | ',' + + ::= '=' | '=' '{' '}' | '=' '{' '}' + + ::= PASS | FAIL + + ::= | | STRING_LITERAL | '(' ')' + + ::= | '[' ']' | '(' ')' | '.' | INC_OP | DEC_OP | '.' ENCODING '(' ')' + + ::= /* empty */ | + + ::= | ',' + + ::= | INC_OP | DEC_OP | + + ::= '&' | '*' | '+' | '-' | '~' | '!' + + ::= | '(' ')' + + ::= | '*' | '/' | '%' + + ::= | '+' | '-' + + ::= | LEFT_OP | RIGHT_OP + + ::= | '<' | '>' | LE_OP | GE_OP + + ::= | EQ_OP | NE_OP + + ::= | '&' + + ::= | '^' + + ::= | '|' + + ::= | AND_OP + + ::= | OR_OP + + ::= | '?' ':' + + ::= | + + ::= | ',' + + ::= '=' + + ::= ';' | ';' + + ::= | | | + + ::= | ',' + + ::= | '=' + + ::= EXTERN | AUTO + + ::= GPR | CSR | UN_CONST | S_CONST | STRING + + ::= + + ::= | '(' ')' | '[' '*' ']' | '[' ']' | '[' ':' ']' | '[' ']' | '(' ')' | '(' ')' | '(' ')' + + ::= | ',' + + ::= | + + ::= | ',' + + ::= + + ::= | + + ::= | '{' '}' | '{' ',' '}' + + ::= | ',' + + ::= | | | | + + ::= '{' '}' | '{' '}' + + ::= | + + ::= | + + ::= ';' | ';' + + ::= IF '(' ')' %prec NO_ELSE | IF '(' ')' ELSE + + ::= FOR '(' ')' | FOR '(' ')' | FOR '(' ')' | FOR '(' ')' + + ::= ID + + ::= CONSTANT | HEX_CONST | VLOG_CONST | QSTRING +``` diff --git a/fsl/docs/deprecated/FSL_x2.md b/fsl/docs/deprecated/FSL_x2.md new file mode 100644 index 00000000..fbf76819 --- /dev/null +++ b/fsl/docs/deprecated/FSL_x2.md @@ -0,0 +1,1220 @@ +# Fusion/Fracture Specification Language + +1. Document History + +1. Introduction to FSL + 1. High Level Operation + 1. FSL Example + 1. Is/Is not + +1. Language Description + 1. Scope + 1. Keywords + 1. Identifiers + 1. Constants + 1. Operators + 1. Arithmetic Operators + 1. Range Operators + 1. Relational Operators + 1. Logical Operators + 1. Assignment Operators + 1. Concatenation Operator + 1. Comments + 1. Preprocessor Support + 1. Conditional Compilation + 1. Includes + 1. Transform Structure + 1. Transform Specification + 1. Prolog Elements + 1. isa Element + 1. isa Methods + 1. uarch Element + 1. uarch methods + 1. ioput Element + 1. ioput methods + 1. Sequence Clause + 1. Sequence methods + 1. Constraints Clause + 1. Constraints methods + 1. Conversion Clause + +1. Tools and Utilities + 1. Condor Fusion API + 1. Olympia Performance Model + 1. Mavis + 1. STF Library + +1. Appendix + 1. FSL BNF + 1. FSL style considerations + 1. Encapsulated Style + 1. Library Style + 1. FSL Instruction Types + 1. Syntax Highlight Control File + 1. VIM +1. References + +---------------------------------------------------------------- +### Document History + +| Version | Date | Contact | Description | +|:-------:|:----------:|:---------:|:--------------------------------------| +| x.0 | 2024.03.04 | Jeff Nye | circulated for comment +| x.1 | 2024.03.08 | Jeff Nye | typos, replace asserts with exceptions, grammar changes +| x.2 | 2024.03.10 | Jeff Nye | removed operators, div/mod not needed,++/--/extensive assignment operators violate SA + +### TODO + +- Initiate some discussion on the copy-on-write vs in-place modification of the +instruction buffers. The goal is to support both without needing it reflected +in the conversion clause syntax. + +- Revisit the single assignment decisions + +- Revisit the decision to include instr types + +- Revisit the decision on minimal control flow. Is the ternary operator +sufficient or is if-then-else syntax more clear, are for loops required, +etc? + +- add the BNF or ANTRL/Bison grammar + +---------------------------------------------------------------- +# Introduction to FSL + +Fusion/Fracture Specification Language is used to express properties, +constraints and a process for conversion of standard microprocessor +instructions into alternative instruction forms. + +Generally, this transformation process converts an N-tuple of processor +instructions to an M-tuple of processor instructions. + +The most commonly referenced transforms are fusion and fracture. + +When N > M holds, this is the case for fusion. + +When N < M holds, this is the case for fracture. + +Informally, fusion converts simpler operations into more complex operations +with the intent of improving execution attributes. Fracture commonly replaces +more complex operations with a set of simpler operations, with the +same intent of improving execution attributes. + +Often N-tuple instructions are elements of a standardized ISA and +the M-tuple are customizations of the N-tuple set. The M-tuple +instructions are the result of transformation and are internal to the +processor. + +FSL assists the expression of the properties of these transformations and +takes advantage of the bounds of the domain to provide an efficient syntax +for these expressions. + +## High Level Operation + +Each N to M tuple mapping is expressed in a named FSL transform specification. + +The input to a transform is a sequence of instructions. The output of +a transform is a possibly transformed sequence. The input sequence can +be modified in place or into a separate buffer. This is controlled by +FSL syntax. + +The operation of an FSL transform consists of a matching phase, +a constraints checking phase, and the conversion phase. The transform +phases are represented by three clauses in an FSL transform specification. + +A phase returns an indication of success or failure. If a phase reports +a failure, control is returned to the Fusion API. The API will continue +processing and notify the system as required. + +The sequence clause declares the matching attributes to be applied to +the input sequence. The matching attributes are a list of +instruction objects, either as assembly language or as a list of UIDs. + +The output of the sequence clause indicates which instructions +are to be transformed, if any. If no match is found the sequence clause +returns fail. + +In the simplest case, a positive match is indicated by an index and a length. +The index is the position of the first matching instruction in the input +sequence, length is the number of instructions to be transformed, inclusive of +the index. + +A valid sequence indication is passed to the constraints clause. Subsequently, +the constraints specification is applied to the indicated range and a +true/false flag is returned. + +If the constraints are satisfied, the constraints clause passes true to the +conversion clause, along with the sequence indication. + +If the conversion clause receives true, it will apply the transformation +on the input sequence beginning at the specified index and places the result +in an output sequence or modifies the input sequence in place as directed +by syntax. + +## FSL Example + +An example of an FSL transform specification written in the encapsulated +style is shown below. + +The three clauses, sequence, constraints and conversion, are preceded by +the variables which declare the instruction set architecture, +the micro-architecture of the processor and a +sequence container reference, ioput. ioput links the transform to the +performance model's decoded instructions containers. + +The isa/uarch/ioput are referred to as the 'Prolog' in discussions +below. + +``` +transform fs1 { + + isa rv64g + uarch oly1 + ioput iop1 + + sequence seq1(iop1,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + _req_ 2 + c.xor g2, g2, g1 + c.slli g2, g2, c3 + _opt_ 1 + c.srli g2, c3 + } + + constraints cons1(iop1,seq1,rv64g,oly1) { + gpr g1,g2 + s20 c1 + s12 c2 + u6 c3 + + g1 != g2 + } + + conversion conv1(iop1,seq1,cons1) { + instr fused(opcode=0x1234) + iop1.input.replace(seq1,fused) + } +} +``` + +## Is/Is not + +FSL is not a programming language; it is a "constrained +transformation expression language". FSL operates on stylized or symbolic +microprocessor instructions. + +As such many aspects of a programming language are not required by FSL. + +The FSL syntax style is a reduced boilerplate style of C. e.g. braces are +used, no semi-colons, indentation is not a syntax element. + +There are no user defined functions. + +There are a limited number of data types unique to FSL. + +The standard native types are not in the syntax. + +For user defined variables type assignment is done my inference. + +This is no need for string or container types. The typical native +types such as float, double, and string are not required by FSL and +therefore not inferred. + +FSL uses single assignment for variables. When using object methods +multiple assignments with the same method is supported. + +There are no console or file I/O mechanisms. + +Expression operations are limited. + +Arithmetic expressions are limited. + +const'ness is not a feature of FSL. + +There are no namespaces. + +---------------------------------------------------------------- +# Language Description + +Note: This is the current state of the definition. The design choices +made for simplicity may change as the definition matures. + +## Scope + +Note: I'd like to keep the scoping requirements to a minimum. Time will +tell if this is practical. + +There is global scope for named tranforms and a local scoping +convention. Variable scoping is lexical. + +Anonymous block scoping, { ...scope... }, is not necessary for FSL operation. + +## Keywords + +The set of keywords is small. Some objects have process/method names +where legal use is indicated by context and are not keywords. + +``` +_req_ _opt_ _pass_ _fail_ emit +transform constraints sequence conversion +ioput isa uarch iword +instr encoding encode_order instr +csr fpr gpr vvr +``` + +## Identifiers + +Legal variable names are conventional. + +``` +^[a-zA-Z_][a-zA-Z0-9_]*$ +``` + +---------------------------------------------------------------- +## Constants + +The constraints and conversion clauses are the target use cases for +defining constant support in FSL. + +Constants are expressed as decimal, hexadecimal or the verilog style. + +``` +123 +0x456 +8'b10101010 +``` + +For Verilog style constants the '?' value indicates a match all or +don't care element. The width of '?' is relative to the width of +native elements within the constant's base. + +``` + 8'b1010101? bit 0 is a don't care +12'h45? bits [3:0] are a don't care +``` + +---------------------------------------------------------------- +## Operators + +The constraints clause is the target use case for defining operator +support in FSL. + +The list of operators and their support in FSL is listed below. FSL adds +the range operator to the standard C style operators. The syntax is +similar to Verilog. + +These operators are unnecessary in FSL: Divide, modulus, size_of, +pointer operations, type conversions cast/implicit/explicit. + +The comma operator support is limited to concatentaion expressions, operation +chaining is not necessary in FSL. + +Within the supported operators FSL uses conventional operator precedence. + + +### Arithmetic Operators + +``` + + (Addition) + - (Subtraction) + * (Multiplication) +``` + +### Range Operators + +``` + [M:N] (range select) + [M] (index) +``` + +### Relational Operators + +``` + == (Equal to) + != (Not equal to) + > (Greater than) + < (Less than) + >= (Greater than or equal to) + <= (Less than or equal to) +``` + +### Logical Operators + +``` + && (Logical AND) + || (Logical OR) + ! (Logical NOT) +``` + + +### Assignment Operator + +``` + = (Simple assignment) +``` + + +### Concatenation Operator + +Concatenation expressions use a style similar to verilog, {a,b,c}; + +``` + xyz = { 3'b00, 4'h3,8'd10 } + abc = { a, b, c } + +``` + +## Comments + +Comments use '# ' (hash/space) for single line comments or '###' as +the delimiter for comment blocks. Comments can be embedded in other comments. + +``` +# ### commenting out +# my multi line +# comment by +# prefixing the '#' +# end of ML comment ### +``` + +Mixing block and line comments is supported, the first comment token +takes precedence. This practice is not recommended. + +``` +# ### commenting out +# my multi line + this line will be processed +# prefixing the '#' +# end of ML comment ### +``` + +In this case the block comment start and stop markers are not processed +because they are delimited by line comments. This is supported but 'this +line will be processed' will be tokenized and tested for legal grammar. + +## Preprocessor Support + +The FSL parser uses a pre-processor with features similar to that found +in the C pre-processor. Within the constraints of the FSL language most +pre-processor operations found in C will be available in FSL with slight +changes for FSL syntax choices. + +Note that the typical # indicator, as in #include, is replaced with +'`' as in `include. + +### Conditional Compilation + +FSL supports a common set of conditional compilation directives, but +with the typical # replaced by back-tick. + +``` +`ifdef X +`ifndef X +`if X == Y + +`endif +`endif +`endif +``` + +### Includes + +The include keyword declares external files. The parser handles +included files by expanding them into the current position in +the current translation unit. Include recursion is illegal. + +The syntax is: + +`include myfile.fh + +The .fh extension is preferred but not enforced by the parser. Quotes +around the file name are not used. + +The single inclusion pragma is declared as: + +`once + +This pragma must be expressed before any other non-comment statement. + +## Transform Structure + +FSL transform specifications are read at runtime. The FSL file +list is passed to the Fusion API constructor. The API invokes the +FSL parser. + +A transform's internal structure consists of a number of clauses, +the sequence, constraints, and conversion clauses, along with a number +elements in the prolog which specify the context of the fusion operation, +ISA, microarchitecture and hooks into the performance model. + +## Transform Specification + +The transform statement is a top level structure. Each transform statement +is named. The name must be unique across all translation units. + +The generic form is shown below. The order of the sections and clauses +is arbitrary. What is shown is the recommended convention. + +``` +transform { + + + + +} +``` + +## Prolog Elements + +Prolog is not a keyword. The prolog elements provide the necessary +context for the transform operation and they are commonly referred to +as a group. The common elements are shown: + +``` + isa myIsa + uarch myImplementation + ioput iop1 +``` + +Following parsing/interpretation of the FSL files, the API will walk through +each transform specification to determine its pertinence to the current +context. + +The prolog elements are used for this purpose. The elements +of isa, uarch and ioput are matched to references in the Fusion API. +Unmatched references cause the API to throw an exception. + +## isa Element + +The isa element name is used by the Fusion API to match an instruction set +description API to the transform specification. The API looks up the +'myIsa' string to find the associated object pointer. + +The Fusion API will throw an exception if the named isa element does not have an +associated object. + +The ISA description API is used to validate instruction references in +the transform specification. + +Mavis is the instruction set description API supported in this release. + +### isa Methods + +The isa object has no internal methods accessible through FSL syntax. +Operations which use the isa element do so implicitly during FSL +parsing. + +## uarch Element + +The uarch element name is used by the Fusion API to match a micro-architecture +description class instance to the transform specification. + +The Fusion API will throw an exception if the named uarch element does not +have an associated object. + +The microarchitecture description class is used to validate processor +implementation queries made in the constraints and conversion clauses. + +### uarch methods + +The uarch methods are documented in MachineInfo.hpp as part of the +Fusion API doxygen documentation. + +## ioput Element + +The Fusion API links references to C++ buffers containing instruction +representations to the FSL parser. This linkage is done through a similar +name matching scheme as the other prolog elements. + +ioput is the keyword. Within ioput are two objects representing two +instruction buffers, by name they are simply .input and .output. + +During construction the Fusion API maps ioput.input and ioput.output +to the appropriate model containers. 'input' and 'output' are indexes +into a map containing references to the model's instruction buffers. + +The Fusion API will throw an exception if it can not match the elements in +ioput to STL container objects. Using Olympia as an example, the Fusion +API will attempt to match the specified name, ioput.input, to a +Fusion::InstQueue reference. + +Note: The FSL syntax implies a copy-on-write idiom. However by mapping the +ioput.input and ioput.output objects to the same buffer a modification +in-place idiom can be implemented. This isolates the style used in +the conversion clause from these external mechanics. + +### ioput methods + +ioput elements have these methods available. + +``` +.clear() empties the associated container +.erase(index,size) removes size elements begining with index, + size is inclusive of the index position. +.insert(index,instr) insert an instr object before index. + instr is an FSL type +.replace(sequence,instr) removes sequence.length objects beginning + at sequence.index, and inserts instr +``` + +## Sequence clause + +The sequence clause is used to match the incoming instructions to a +known transform. + +The arguments to the sequence clause are the input sequence name and +the Mavis facade name, declared using ioput and isa, respectively. + +The ioput and isa objects give the sequence clause access to the +instruction containers and known instruction definitions. This +access is used for validation of the sequence and for matching. + +The sequence clause implicitly uses the 1st element of ioput, the +input container. The sequence clause does not modify the ioput containers. + +``` +ioput iop1 + +sequence seq1(iop1,myISA) { + # sequence of instructions +} +``` + +The FSL parser uses the Fusion API and access to the isa object to +validate the instruction sequence. An exception is thrown if a problem +is detected. + +The specified sequence of instructions is pattern matched against +the contents of the input container. If a match is detected the sequence +object, seq1, will update its internal index field and length field. This +information is passed to the constraints clause. On a match the sequence +clause returns \_pass\_ to the Fusion API. + +The index field is the zero-referenced position of the start of the match +within ioput. The length is the number of instructions, inclusive of the +starting instruction. + +An instruction sequence is expressed as a simple list of Mavis-assigned +unique identifiers, or as a set of assembly language instructions with +abstracted operands. The choice is based on the constraints. + +The UID list is sufficient if there are no constraints on the operands +in the list of instructions in the sequence. + +For example, these two instructions are a frequent sequence in compiled +C. The left column is the encoding, the comment is the Mavis unique identifier +for each instruction which is independent of the operands. + +``` +0x0512 c.slli x10,4 ; 0xf +0x8111 c.srli x10,4 ; 0x13 +``` + +If you do not require constraints on the operands and therefore have no +need to refer to the operands by name, you can simply specify the UIDs +as a list, one per line. + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + 0xf + 0x13 +} +``` + +With the UID sequence expression there are no operand specific +constraints and therefore the conversion clause must handle any legal +combinations of the two rd and two constants. + +This results in a transform to a generalized fusion op of a shift left +followed by right and not the zero extension expressed by x10,4. + +If the constraints clause implements operand contraints the instruction +sequence should be expressed using the abstract assembly syntax so the +operands can be referenced by name. + +The expression below takes advantage of positional constraints: + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + c.slli g1,c1 + c.srli g1,c1 +} +``` + +In this case the operands labeled g1 are, by association, required to be +the same value, similarly with the constant operands. + +Another option would be to fully enumerate the operands and let the +constraints clause enforce the required limits on operands. + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + c.slli g1,c1 + c.srli g2,c2 +} +``` + +Note both the later two cases can be made equivalent by construction of +the equivalent constraints in the clause. + +Now in both cases the transformation expresses a fusion operation for +zero extention of the common rd register by the common constant. + +``` +g1 = g2 +c1 = c2 +``` + +In some cases positional constraints can save development time at no +expense to performance. + +The example sequences above have an implied strict ordering. There are +sequence pragmas to relax the strictness of sequence matching. + +The required pragma, \_req\_, indicates that an unspecified instruction +is required in that position. The \_req\_ case does not constrain +what instruction can be present in the gap. A trailing integer +can specify more than one required instruction. + +The optional pragma, \_opt\_, indicates that the match will not be +rejected if there is an instruction or not in this position. A +trailing integer can be used to specify up to N optional instructions. + +``` +_opt_ 2 indicates 0 - 2 instructions will match +_req_ 2 indicates there must be 2 instructions in this position + in the sequence. +``` + +The trailing integer is optional in the syntax: +``` +_opt_ and _opt_ 1 are equivalent +_req_ and _req_ 1 are equivalent +``` + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + _req_ 2 + c.xor g2, g2, g1 + c.slli g2, g2, c3 + _opt_ 2 + c.srli g2, c3 +} +``` + +Notes: The sequence pragmas are also supported for the UID case. Mixing UID +and abstract operand sequences is supported. + +### Sequence methods + +sequence objects have implicit data members + +``` +.state This is _pass_ or _fail_ match status +.length number of matching instructions, if non-zero this is + the number of UIDs or instruction object epxress in the + sequence. length is 0 if no match is found. + +.index if length is non-zero this index of the first matching + instruction +``` + +## Constraints clause + +The constraints clause defines relationships between operands and the +machine implementation. + +The sequence clause is provided to give the constraints access to +the operand abstractions and UID list. The ioput object is supplied +so the constraints clause can query the encoding of the instructions in +the input buffer. The isa object is supplied to validate field widths etc +used in the constraints declarations. Finally the uarch object provides +the constraints clause access to machine implementatain details. + +When the sequence object contains only UIDs there are no operand +specific constraints, and the constraints clause can simply return +\_pass\_. + +``` +constraints cons1() { + _pass_ +} +``` + +Having a populated argument list in this case is optional. +But if the arguments to the constraints clause is empty +the parser will expect only a \_pass\_ or (a \_fail\_) statement. +Anything else indicates a programming error. + +This is a contrived example for explanation. + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + c.slli g1,c1 + c.srli g2,c2 +} + +constraints cons1(seq1,iop1,rv64g,oly1) { + gpr g1,g2 + u6 c1,c2 + + g1 != g2 + c1[0] == c2[1] + +} +``` + +Variables beginning with s or u are signed/unsigned constants. +The number in the name is the bit width of the constant. + +gpr is a keyword, the signed and unsigned designators are treated +as keywords. + +When performing comparisons on register operands the comparison +is performed on the index of the operand and not the contents +of the operand. The inequality statement, g1 != g2, is testing that +g1 and g2 are not the same register. + +The \_pass\_ or \_fail\_ pragmas are implicit. If any statement is +false \_fail\_ is returned. If the clause is processed to the end +\_pass\_ is returned. + +For error checking any named operand in the sequence clause must +have a declaration in the constraints clause even if no operation +uses that declaration. + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + c.lui g1, c1 # c1 is s6 + c.addi g1, c2 # c2 is s6 + c.xor g2, g1 + c.slli g2, c3 # c3 is u6 + c.srli g2, c3 # c3 is u6 +} +``` + +As an example for this sequence the declared constraints clause +will return \_pass\_. + +``` +ioput iop1 + +constraints cons1(seq1,iop1,rv64g,oly1) { + gpr g1,g2 + u6 c1,c2,c3 +} +``` + +However this example will fail, because c3 is not declared. + +``` +ioput iop1 + +constraints cons1(seq1,iop1,rv64g,oly1) { + gpr g1,g2 + u6 c1,c2 # _fail_ because no c3 +} +``` + +Unused declarations also fail. This is considered a programming +aberration that should be reported to the developer. + +When specifying constraints on register operands the constraints +themselves are verified against the ISA. Constraints that violate +the requirements of the ISA are failed. + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + c.slli g1,c1 + c.srli g1,c1 +} + +constraints cons1(seq1,iop1,rv64g,oly1) { + gpr g1,g2 + u6 c1,c2 + + g1 == 0 # _fail_ the rd of c.slli/c.srli can not be x0 +} +``` + +Being strict with operand declarations is intended to assist +development by highlighting unexpected code construction. +TODO: is this having the desired effect? + +### Constraints methods + +The constraints clause has a single method. + +``` +.state This is _pass_ or _fail_ constraints status +``` + +In addition to the .state method, the constraints clause declarations +are made available without prefix to the conversion clause. This is +described in the next section. + +### Conversion clause + +The conversion clause performs the instruction morphing to create +the new instruction(s). + +The conversion clause takes a reference to the sequence clause for +access to the named operands or for access to the UID lists. + +The conversion clause takes a reference to the ioput object for +reading the input instruction list as a destination for converted +instructions. + +The constraints clause is provided to the conversion clause for +access to operand relationships and types. + +The conversion clause can modify the ioput object's input field +in place with converted instructions or it can place modified +instructions in the output field of the ioput object. + +instr objects are used to hold the newly created instructions. The +annotation fields for a new instruction are assigned to the instr +object. + +In the example presume the sequence match has returned an index of 2 and a +length of 3. In this conversion the 3 unfused instructions are replaced +by 1 fusion created instruction. + +The new instruction attributes are assigned. The ioput container +is modifed to remove the unfused instructions and insert the +fusion replacement. + +``` +ioput iop1 + +conversion conv1(seq1,iop1,cons1) { + instr newInstr + + newInstr(opc=0x1234,uid=0x3) + newInstr(src={g1},dst={g2},imm={c1,c1}) + newInstr(type="fused") + + iop1.input.replace(seq1,newInstr) +} +``` + +There are a large number of fields available in the instr object. Not +all are required by all models. Inclusion of these fields is implementation +dependent. + +### Conversion methods + +The conversion clause has a single method. + +``` +.state This is _pass_ or _fail_ constraints status +``` + +The instr type is valid within a conversion clause. + +---------------------------------------------------------------- +# Tools and Utilities + +A summary of tools and utilities useful for instruction transform work. + +## Condor Fusion API + +FSL domain specific language is a component of a larger C++ API. With this API +it is possible to directly create instruction transforms in C++, or through +the FSL domain specific language or other ad hoc schemes. The API has +been tested with the Condor Performance Model and the Olympia +performance model. + +The Fusion API shares a repository with the Olympia performance model. The +shared URL is contained here: +https://github.com/riscv-software-src/riscv-perf-model/tree/master/fusion. +Doxygen documentation is available for this API. + +## Olympia Performance Model + +Olympia is a performance model written in C++ for the RISC-V community as an +example of an Out-of-Order RISC-V CPU Performance Model based on the Sparta +Modeling Framework. + +The repository URL is https://github.com/riscv-software-src/riscv-perf-model/tree/master. + +## Mavis + +Mavis is a header only framework designed for decoding the RISC-V ISA into +custom instruction class types, along with custom extensions to those +class types. + +The repository URL is https://github.com/sparcians/mavis/tree/main. Doxygen +documentation is available for this API. + +## STF Library + +The STF (Simulation Tracing Format) library provides an API for +reading and generation of STF trace files. + +The repository URL is https://github.com/sparcians/stf_lib. Doxygen +documentation is available for this API. + +---------------------------------------------------------------- +# Appendix + +## FSL BNF + +## FSL style considerations + +There are two styles of FSL shown, the first shows an encapsulated +style, the second shows a library element style. + +Subjectively I think the first style is easier to comprehend and the second +style is where large implementations will likely migrate, because of the +opportunities for reuse. + +In operation there is no difference in the two examples. + +### Encapsulated Style +``` +transform fs1 { + + isa rv64g + uarch oly1 + ioput iop1 + + sequence seq1(iop1,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + _req_ + c.xor g2, g2, g1 + c.slli g2, g2, c3 + _opt_ + c.srli g2, c3 + } + + constraints cons1(seq1,iop1,rv64g,oly1) { + gpr g1,g2 + s20 c1 + s12 c2 + u6 c3 + + g1 != g2 + } + + conversion conv1(seq1,iop1,cons1) { + instr fused(opcode=0x1234) + iop1.input.replace(seq1,fused) + } +} +``` + +### Library Style + +transform fs1 { + prolog prolog1 + sequence seq1 + constraints cons1 + conversion conv1 +} + +prolog prolog1 { + isa rv64g + uarch oly1 + ioput iop1 +} + +sequence seq1(iop1,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + _req_ + c.xor g2, g2, g1 + c.slli g2, g2, c3 + _opt_ + c.srli g2, c3 +} + +constraints cons1(seq1,iop1,rv64g,oly1) { + gpr g1,g2 + s20 c1 + s12 c2 + u6 c3 + + g1 != g2 +} + +conversion conv1(seq1,iop1,cons1) { + instr fused(opcode=0x1234) + iop1.input.replace(seq1,fused) +} + +conversion conv2(seq1,iop1,cons1) { + encoding word1(seq1,opc=0x1234) { + u10 opc # 57:48 unsigned 10b + u6 c3 # 47:42 unsigned 6b + s12 c2 # 41:30 signed 12b + s20 c1 # 29:10 signed 20b + gpr g1 # 9:5 gpr 5b + gpr g2 # 4:0 gpr 5b + encode_order{opc,c3,c2,c1,g1,g2} + } + + instr fused(encoding=word1) + iop1.input.replace(seq1,fused) +} + +## FSL Instruction Types + +Instruction types have a mapping to the ISA description API. The +lower case strings here are mapped to an equivalent type in the ISA +API. When assigning a type to an FSL instr object use the lower +case strings below, without quotes. + +``` +"int" INT +"float" FLOAT +"arith" ARITH +"mul" MULTIPLY +"div" DIVIDE +"branch" BRANCH +"pc" PC +"cond" CONDITIONAL +"jal" JAL +"jalr" JALR +"load" LOAD +"store" STORE +"mac" MAC +"sqrt" SQRT +"convert" CONVERT +"compare" COMPARE +"move" MOVE +"classify" CLASSIFY +"vector" VECTOR +"maskable" MASKABLE +"unit_stride" UNIT_STRIDE +"stride" STRIDE +"ordered_indexed" ORDERED_INDEXED +"unordered_indexed" UNORDERED_INDEXED +"segment" SEGMENT +"faultfirst" FAULTFIRST +"whole" WHOLE +"mask" MASK +"widening" WIDENING +"hypervisor" HYPERVISOR +"crypto" CRYPTO +"prefetch" PREFETCH +"ntl" NTL +"hint" HINT +"cache" CACHE +"atomic" ATOMIC +"fence" FENCE +"system" SYSTEM +"csr" CSR +``` + +## Syntax Highlight Control Files + +### VIM +``` +" Vim syntax file +" Language: Fusion/Fracture Specification Language +" Maintainer: Jeff Nye +" Last Update: 2024 + +" For version 6.x: Quit when a syntax file was already loaded +if version < 600 + syntax clear +elseif exists("b:current_syntax") + finish +endif + +" Set the local value of the 'iskeyword' option. +if version >= 600 + setlocal iskeyword=@,48-57,63,_,192-255 +else + set iskeyword=@,48-57,63,_,192-255 +endif + +" Rules +syn keyword fslKeyword transform sequence constraints emit conversion +syn keyword fslKeyword isa uarch ioput +syn keyword fslSequence _req_ _opt_ _pass_ _fail_ + +syn match fslFunction /\w\+\ze\s*(/ + +syn keyword fslType fpr vvr gpr csr opc instr encoding encode_order iword +syn match fslType "\<[su]\d\+\>" + +syn keyword fslTODO contained TODO FIXME + +syn match fslOperator "[&|~>" +syn match fslVlogNumber "\(\<\d\+\|\)'[sS]\?[bB]\s*[0-1_xXzZ?]\+\>" +syn match fslVlogNumber "\(\<\d\+\|\)'[sS]\?[oO]\s*[0-7_xXzZ?]\+\>" +syn match fslVlogNumber "\(\<\d\+\|\)'[sS]\?[dD]\s*[0-9_xXzZ?]\+\>" +syn match fslVlogNumber "\(\<\d\+\|\)'[sS]\?[hH]\s*[0-9a-fA-F_xXzZ?]\+\>" +syn match fslVlogNumber "\<[+-]\=[0-9_]\+\(\.[0-9_]*\|\)\(e[0-9_]*\|\)\>" + +"Modify the following as needed. The trade-off is performance versus +"functionality. + +syn sync minlines=50 + +hi def link fslKeyword Statement +hi def link fslType FslType +hi def link fslSequence Label +hi def link fslDirective Label + +hi def link fslTODO Todo +hi def link fslComment Comment +hi def link fslFunction Function + +hi def link fslString String + +hi def link fslHexNumber Number +hi def link fslVlogNumber Number + +hi def link fslOperator Special + +hi def link fslIncline SpecialComment +hi def link fslFileName ThisType + +highlight FslType ctermfg=2 gui=bold guifg=SeaGreen + +let b:current_syntax = "fsl" +``` + +1. References + +[1] Celio, Christopher, et al. "The renewed case for the reduced instruction + set computer: Avoiding isa bloat with macro-op fusion for risc-v." arXiv + preprint arXiv:1607.02318 (2016). diff --git a/fsl/docs/deprecated/FSL_x3.md b/fsl/docs/deprecated/FSL_x3.md new file mode 100644 index 00000000..71373f52 --- /dev/null +++ b/fsl/docs/deprecated/FSL_x3.md @@ -0,0 +1,1231 @@ +# Fusion/Fracture Specification Language + +1. Document History + +1. Introduction to FSL + 1. High Level Operation + 1. FSL Example + 1. Is/Is not + +1. Language Description + 1. Scope + 1. Keywords + 1. Identifiers + 1. Constants + 1. Operators + 1. Arithmetic Operators + 1. Range Operators + 1. Relational Operators + 1. Logical Operators + 1. Assignment Operators + 1. Concatenation Operator + 1. Comments + 1. Preprocessor Support + 1. Conditional Compilation + 1. Includes + 1. Transform Structure + 1. Transform Specification + 1. Prolog Elements + 1. isa Element + 1. isa Methods + 1. uarch Element + 1. uarch methods + 1. ioput Element + 1. ioput methods + 1. Sequence Clause + 1. Sequence methods + 1. Constraints Clause + 1. Constraints methods + 1. Conversion Clause + +1. Tools and Utilities + 1. Condor Fusion API + 1. Olympia Performance Model + 1. Mavis + 1. STF Library + +1. Appendix + 1. FSL BNF + 1. FSL style considerations + 1. Encapsulated Style + 1. Library Style + 1. FSL Instruction Types + 1. Syntax Highlight Control File + 1. VIM +1. References + +---------------------------------------------------------------- +### Document History + +| Version | Date | Contact | Description | +|:-------:|:----------:|:---------:|:--------------------------------------| +| x.0 | 2024.03.04 | Jeff Nye | circulated for comment +| x.1 | 2024.03.08 | Jeff Nye | typos, replace asserts with exceptions, grammar changes +| x.2 | 2024.03.10 | Jeff Nye | removed operators, div/mod not needed,++/--/extensive assignment operators violate SA +| x.3 | 2024.04.09 | Jeff Nye | typo fixes, added mnemonic strings to instr and encoding structures + + +### TODO + +- Initiate some discussion on the copy-on-write vs in-place modification of the +instruction buffers. The goal is to support both without needing it reflected +in the conversion clause syntax. + +- Revisit the single assignment decisions + +- Revisit the decision to include instr types + +- Revisit the decision on minimal control flow. Is the ternary operator +sufficient or is if-then-else syntax more clear, are for loops required, +etc? + +- add the BNF or ANTRL/Bison grammar + +- Future feature: consider elimination of the arguments for the major clauses when + using the encapsulated style + +- Future feature: composition syntax for sequence declaration, sequences + built from other sequences with operators for combining. + +---------------------------------------------------------------- +# Introduction to FSL + +Fusion/Fracture Specification Language is used to express properties, +constraints and a process for conversion of standard microprocessor +instructions into alternative instruction forms. + +Generally, this transformation process converts an N-tuple of processor +instructions to an M-tuple of processor instructions. + +The most commonly referenced transforms are fusion and fracture. + +When N > M holds, this is the case for fusion. + +When N < M holds, this is the case for fracture. + +Informally, fusion converts simpler operations into more complex operations +with the intent of improving execution attributes. Fracture commonly replaces +more complex operations with a set of simpler operations, with the +same intent of improving execution attributes. + +Often N-tuple instructions are elements of a standardized ISA and +the M-tuple are customizations of the N-tuple set. The M-tuple +instructions are the result of transformation and are internal to the +processor. + +FSL assists the expression of the properties of these transformations and +takes advantage of the bounds of the domain to provide an efficient syntax +for these expressions. + +## High Level Operation + +Each N to M tuple mapping is expressed in a named FSL transform specification. + +The input to a transform is a sequence of instructions. The output of +a transform is a possibly transformed sequence. The input sequence can +be modified in place or into a separate buffer. This is controlled by +FSL syntax. + +The operation of an FSL transform consists of a matching phase, +a constraints checking phase, and the conversion phase. The transform +phases are represented by three clauses in an FSL transform specification. + +A phase returns an indication of success or failure. If a phase reports +a failure, control is returned to the Fusion API. The API will continue +processing and notify the system as required. + +The sequence clause declares the matching attributes to be applied to +the input sequence. The matching attributes are a list of +instruction objects, either as assembly language or as a list of UIDs. + +The output of the sequence clause indicates which instructions +are to be transformed, if any. If no match is found the sequence clause +returns fail. + +In the simplest case, a positive match is indicated by an index and a length. +The index is the position of the first matching instruction in the input +sequence, length is the number of instructions to be transformed, inclusive of +the index. + +A valid sequence indication is passed to the constraints clause. Subsequently, +the constraints specification is applied to the indicated range and a +true/false flag is returned. + +If the constraints are satisfied, the constraints clause passes true to the +conversion clause, along with the sequence indication. + +If the conversion clause receives true, it will apply the transformation +on the input sequence beginning at the specified index and places the result +in an output sequence or modifies the input sequence in place as directed +by syntax. + +## FSL Example + +An example of an FSL transform specification written in the encapsulated +style is shown below. + +The three clauses, sequence, constraints and conversion, are preceded by +the variables which declare the instruction set architecture, +the micro-architecture of the processor and a +sequence container reference, ioput. ioput links the transform to the +performance model's decoded instructions containers. + +The isa/uarch/ioput are referred to as the 'Prolog' in discussions +below. + +``` +transform fs1 { + + isa rv64g + uarch oly1 + ioput iop1 + + sequence seq1(iop1,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + _req_ 2 + c.xor g2, g2, g1 + c.slli g2, g2, c3 + _opt_ 1 + c.srli g2, c3 + } + + constraints cons1(iop1,seq1,rv64g,oly1) { + gpr g1,g2 + s20 c1 + s12 c2 + u6 c3 + + g1 != g2 + } + + conversion conv1(iop1,seq1,cons1) { + instr fused(opcode=0x1234) + iop1.input.replace(seq1,fused) + } +} +``` + +## Is/Is not + +FSL is not a programming language; it is a "constrained +transformation expression language". FSL operates on stylized or symbolic +microprocessor instructions. + +As such many aspects of a programming language are not required by FSL. + +The FSL syntax style is a reduced boilerplate style of C. e.g. braces are +used, no semi-colons, indentation is not a syntax element. + +There are no user defined functions. + +There are a limited number of data types unique to FSL. + +The standard native types are not in the syntax. + +For user defined variables type assignment is done by inference. + +This is no need for string or container types. The typical native +types such as float, double, and string are not required by FSL and +therefore not inferred. + +FSL uses single assignment for variables. When using object methods +multiple assignments with the same method is supported. + +There are no console or file I/O mechanisms. + +Expression operations are limited. + +Arithmetic expressions are limited. + +const'ness is not a feature of FSL. + +There are no namespaces. + +---------------------------------------------------------------- +# Language Description + +Note: This is the current state of the definition. The design choices +made for simplicity may change as the definition matures. + +## Scope + +Note: I'd like to keep the scoping requirements to a minimum. Time will +tell if this is practical. + +There is global scope for named tranforms and a local scoping +convention. Variable scoping is lexical. + +Anonymous block scoping, { ...scope... }, is not necessary for FSL operation. + +## Keywords + +The set of keywords is small. Some objects have process/method names +where legal use is indicated by context and are not keywords. + +``` +_req_ _opt_ _pass_ _fail_ emit +transform constraints sequence conversion +ioput isa uarch iword +instr encoding encode_order instr +csr fpr gpr vvr +``` + +## Identifiers + +Legal variable names are conventional. + +``` +^[a-zA-Z_][a-zA-Z0-9_]*$ +``` + +---------------------------------------------------------------- +## Constants + +The constraints and conversion clauses are the target use cases for +defining constant support in FSL. + +Constants are expressed as decimal, hexadecimal or the verilog style. + +``` +123 +0x456 +8'b10101010 +``` + +For Verilog style constants the '?' value indicates a match all or +don't care element. The width of '?' is relative to the width of +native elements within the constant's base. + +``` + 8'b1010101? bit 0 is a don't care +12'h45? bits [3:0] are a don't care +``` + +---------------------------------------------------------------- +## Operators + +The constraints clause is the target use case for defining operator +support in FSL. + +The list of operators and their support in FSL is listed below. FSL adds +the range operator to the standard C style operators. The syntax is +similar to Verilog. + +These operators are unnecessary in FSL: Divide, modulus, size_of, +pointer operations, type conversions cast/implicit/explicit. + +The comma operator support is limited to concatentaion expressions, operation +chaining is not necessary in FSL. + +Within the supported operators FSL uses conventional operator precedence. + + +### Arithmetic Operators + +``` + + (Addition) + - (Subtraction) + * (Multiplication) +``` + +### Range Operators + +``` + [M:N] (range select) + [M] (index) +``` + +### Relational Operators + +``` + == (Equal to) + != (Not equal to) + > (Greater than) + < (Less than) + >= (Greater than or equal to) + <= (Less than or equal to) +``` + +### Logical Operators + +``` + && (Logical AND) + || (Logical OR) + ! (Logical NOT) +``` + + +### Assignment Operator + +``` + = (Simple assignment) +``` + + +### Concatenation Operator + +Concatenation expressions use a style similar to verilog, {a,b,c}; + +``` + xyz = { 3'b00, 4'h3,8'd10 } + abc = { a, b, c } + +``` + +## Comments + +Comments use '# ' (hash/space) for single line comments or '###' as +the delimiter for comment blocks. Comments can be embedded in other comments. + +``` +# ### commenting out +# my multi line +# comment by +# prefixing the '#' +# end of ML comment ### +``` + +Mixing block and line comments is supported, the first comment token +takes precedence. This practice is not recommended. + +``` +# ### commenting out +# my multi line + this line will be processed +# prefixing the '#' +# end of ML comment ### +``` + +In this case the block comment start and stop markers are not processed +because they are delimited by line comments. This is supported but 'this +line will be processed' will be tokenized and tested for legal grammar. + +## Preprocessor Support + +The FSL parser uses a pre-processor with features similar to that found +in the C pre-processor. Within the constraints of the FSL language most +pre-processor operations found in C will be available in FSL with slight +changes for FSL syntax choices. + +Note that the typical # indicator, as in #include, is replaced with +'`' as in `include. + +### Conditional Compilation + +FSL supports a common set of conditional compilation directives, but +with the typical # replaced by back-tick. + +``` +`ifdef X +`ifndef X +`if X == Y + +`endif +`endif +`endif +``` + +### Includes + +The include keyword declares external files. The parser handles +included files by expanding them into the current position in +the current translation unit. Include recursion is illegal. + +The syntax is: + +`include myfile.fh + +The .fh extension is preferred but not enforced by the parser. Quotes +around the file name are not used. + +The single inclusion pragma is declared as: + +`once + +This pragma must be expressed before any other non-comment statement. + +## Transform Structure + +FSL transform specifications are read at runtime. The FSL file +list is passed to the Fusion API constructor. The API invokes the +FSL parser. + +A transform's internal structure consists of a number of clauses, +the sequence, constraints, and conversion clauses, along with a number +elements in the prolog which specify the context of the fusion operation, +ISA, microarchitecture and hooks into the performance model. + +## Transform Specification + +The transform statement is a top level structure. Each transform statement +is named. The name must be unique across all translation units. + +The generic form is shown below. The order of the sections and clauses +is arbitrary. What is shown is the recommended convention. + +``` +transform { + + + + +} +``` + +## Prolog Elements + +Prolog is not a keyword. The prolog elements provide the necessary +context for the transform operation and they are commonly referred to +as a group. The common elements are shown: + +``` + isa myIsa + uarch myImplementation + ioput iop1 +``` + +Following parsing/interpretation of the FSL files, the API will walk through +each transform specification to determine its pertinence to the current +context. + +The prolog elements are used for this purpose. The elements +of isa, uarch and ioput are matched to references in the Fusion API. +Unmatched references cause the API to throw an exception. + +## isa Element + +The isa element name is used by the Fusion API to match an instruction set +description API to the transform specification. The API looks up the +'myIsa' string to find the associated object pointer. + +The Fusion API will throw an exception if the named isa element does not have an +associated object. + +The ISA description API is used to validate instruction references in +the transform specification. + +Mavis is the instruction set description API supported in this release. +More information on Mavis can be found here [Mavis](https://github.com/sparcians/mavis) +and in the Mavis section under Tools and Utilities below. + +### isa Methods + +The isa object has no internal methods accessible through FSL syntax. +Operations which use the isa element do so implicitly during FSL +parsing. + +## uarch Element + +The uarch element name is used by the Fusion API to match a micro-architecture +description class instance to the transform specification. + +The Fusion API will throw an exception if the named uarch element does not +have an associated object. + +The microarchitecture description class is used to validate processor +implementation queries made in the constraints and conversion clauses. + +### uarch methods + +The uarch methods are documented in MachineInfo.hpp as part of the +Fusion API doxygen documentation. + +## ioput Element + +The Fusion API links references to C++ buffers containing instruction +representations to the FSL parser. This linkage is done through a similar +name matching scheme as the other prolog elements. + +ioput is the keyword. Within ioput are two objects representing two +instruction buffers, by name they are simply .input and .output. + +During construction the Fusion API maps ioput.input and ioput.output +to the appropriate model containers. 'input' and 'output' are indexes +into a map containing references to the model's instruction buffers. + +The Fusion API will throw an exception if it can not match the elements in +ioput to STL container objects. Using Olympia as an example, the Fusion +API will attempt to match the specified name, ioput.input, to a +Fusion::InstQueue reference. + +Note: The FSL syntax implies a copy-on-write idiom. However by mapping the +ioput.input and ioput.output objects to the same buffer a modification +in-place idiom can be implemented. This isolates the style used in +the conversion clause from these external mechanics. + +### ioput methods + +ioput elements have these methods available. + +``` +.clear() empties the associated container +.erase(index,size) removes size elements begining with index, + size is inclusive of the index position. +.insert(index,instr) insert an instr object before index. + instr is an FSL type +.replace(sequence,instr) removes sequence.length objects beginning + at sequence.index, and inserts instr +``` + +## Sequence clause + +The sequence clause is used to match the incoming instructions to a +known transform. + +The arguments to the sequence clause are the input sequence name and +the Mavis facade name, declared using ioput and isa, respectively. + +The ioput and isa objects give the sequence clause access to the +instruction containers and known instruction definitions. This +access is used for validation of the sequence and for matching. + +The sequence clause implicitly uses the 1st element of ioput, the +input container. The sequence clause does not modify the ioput containers. + +``` +ioput iop1 + +sequence seq1 { + # sequence of instructions +} +``` + +The FSL parser uses the Fusion API and access to the isa object to +validate the instruction sequence. An exception is thrown if a problem +is detected. + +The specified sequence of instructions is pattern matched against +the contents of the input container. If a match is detected the sequence +object, seq1, will update its internal index field and length field. This +information is passed to the constraints clause. On a match the sequence +clause returns \_pass\_ to the Fusion API. + +The index field is the zero-referenced position of the start of the match +within ioput. The length is the number of instructions, inclusive of the +starting instruction. + +An instruction sequence is expressed as a simple list of Mavis-assigned +unique identifiers which are independent of operands, or as a set of +assembly language instructions with abstracted operands. The choice is +based on the constraints. + +The UID list is sufficient if there are no constraints on the operands +in the list of instructions in the sequence. + +For example, these two instructions are a frequent sequence in compiled +C. The left column is the encoding, the comment is the Mavis unique identifier +for each instruction which is independent of the operands. + +``` +0x0512 c.slli x10,4 ; 0xf +0x8111 c.srli x10,4 ; 0x13 +``` + +If you do not require constraints on the operands and therefore have no +need to refer to the operands by name, you can simply specify the UIDs +as a list, one per line. + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + 0xf + 0x13 +} +``` + +With the UID sequence expression there are no operand specific +constraints and therefore the conversion clause must handle any legal +combinations of the two rd and two constants. + +This results in a transform to a generalized fusion op of a shift left +followed by right and not the zero extension expressed by x10,4. + +If the constraints clause implements operand contraints the instruction +sequence should be expressed using the abstract assembly syntax so the +operands can be referenced by name. + +The expression below takes advantage of positional constraints: + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + c.slli g1,c1 + c.srli g1,c1 +} +``` + +In this case the operands labeled g1 are, by association, required to be +the same value, similarly with the constant operands. + +Another option would be to fully enumerate the operands and let the +constraints clause enforce the required limits on operands. + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + c.slli g1,c1 + c.srli g2,c2 +} +``` + +Note both the later two cases can be made equivalent by construction of +the equivalent constraints in the clause. + +Now in both cases the transformation expresses a fusion operation for +zero extention of the common rd register by the common constant. + +``` +g1 = g2 +c1 = c2 +``` + +In some cases positional constraints can save development time at no +expense to performance. + +The example sequences above have an implied strict ordering. There are +sequence pragmas to relax the strictness of sequence matching. + +The required pragma, \_req\_, indicates that an unspecified instruction +is required in that position. The \_req\_ case does not constrain +what instruction can be present in the gap. A trailing integer +can specify more than one required instruction. + +The optional pragma, \_opt\_, indicates that the match will not be +rejected if there is an instruction or not in this position. A +trailing integer can be used to specify up to N optional instructions. + +``` +_opt_ 2 indicates 0 - 2 instructions will match +_req_ 2 indicates there must be 2 instructions in this position + in the sequence. +``` + +The trailing integer is optional in the syntax: +``` +_opt_ and _opt_ 1 are equivalent +_req_ and _req_ 1 are equivalent +``` + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + _req_ 2 + c.xor g2, g2, g1 + c.slli g2, g2, c3 + _opt_ 2 + c.srli g2, c3 +} +``` + +Notes: The sequence pragmas are also supported for the UID case. Mixing UID +and abstract operand sequences is supported. + +### Sequence methods + +sequence objects have implicit data members + +``` +.state This is _pass_ or _fail_ match status +.length number of matching instructions, if non-zero this is + the number of UIDs or instruction object epxress in the + sequence. length is 0 if no match is found. + +.index if length is non-zero this index of the first matching + instruction +``` + +## Constraints clause + +The constraints clause defines relationships between operands and the +machine implementation. + +The sequence clause is provided to give the constraints access to +the operand abstractions and UID list. The ioput object is supplied +so the constraints clause can query the encoding of the instructions in +the input buffer. The isa object is supplied to validate field widths etc +used in the constraints declarations. Finally the uarch object provides +the constraints clause access to machine implementatain details. + +When the sequence object contains only UIDs there are no operand +specific constraints, and the constraints clause can simply return +\_pass\_. + +``` +constraints cons1() { + _pass_ +} +``` + +Having a populated argument list in this case is optional. +But if the arguments to the constraints clause is empty +the parser will expect only a \_pass\_ or (a \_fail\_) statement. +Anything else indicates a programming error. + +This is a contrived example for explanation. + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + c.slli g1,c1 + c.srli g2,c2 +} + +constraints cons1(seq1,iop1,rv64g,oly1) { + gpr g1,g2 + u6 c1,c2 + + g1 != g2 + c1[0] == c2[1] + +} +``` + +Variables beginning with s or u are signed/unsigned constants. +The number in the name is the bit width of the constant. + +gpr is a keyword, the signed and unsigned designators are treated +as keywords. + +When performing comparisons on register operands the comparison +is performed on the index of the operand and not the contents +of the operand. The inequality statement, g1 != g2, is testing that +g1 and g2 are not the same register. + +The \_pass\_ or \_fail\_ pragmas are implicit. If any statement is +false \_fail\_ is returned. If the clause is processed to the end +\_pass\_ is returned. + +For error checking any named operand in the sequence clause must +have a declaration in the constraints clause even if no operation +uses that declaration. + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + c.lui g1, c1 # c1 is s6 + c.addi g1, c2 # c2 is s6 + c.xor g2, g1 + c.slli g2, c3 # c3 is u6 + c.srli g2, c3 # c3 is u6 +} +``` + +As an example for this sequence the declared constraints clause +will return \_pass\_. + +``` +ioput iop1 + +constraints cons1(seq1,iop1,rv64g,oly1) { + gpr g1,g2 + u6 c1,c2,c3 +} +``` + +However this example will fail, because c3 is not declared. + +``` +ioput iop1 + +constraints cons1(seq1,iop1,rv64g,oly1) { + gpr g1,g2 + u6 c1,c2 # _fail_ because no c3 +} +``` + +Unused declarations also fail. This is considered a programming +aberration that should be reported to the developer. + +When specifying constraints on register operands the constraints +themselves are verified against the ISA. Constraints that violate +the requirements of the ISA are failed. + +``` +ioput iop1 + +sequence seq1(iop1,rv64g) { + c.slli g1,c1 + c.srli g1,c1 +} + +constraints cons1(seq1,iop1,rv64g,oly1) { + gpr g1,g2 + u6 c1,c2 + + g1 == 0 # _fail_ the rd of c.slli/c.srli can not be x0 +} +``` + +Being strict with operand declarations is intended to assist +development by highlighting unexpected code construction. +TODO: is this having the desired effect? + +### Constraints methods + +The constraints clause has a single method. + +``` +.state This is _pass_ or _fail_ constraints status +``` + +In addition to the .state method, the constraints clause declarations +are made available without prefix to the conversion clause. This is +described in the next section. + +### Conversion clause + +The conversion clause performs the instruction morphing to create +the new instruction(s). + +The conversion clause takes a reference to the sequence clause for +access to the named operands or for access to the UID lists. + +The conversion clause takes a reference to the ioput object for +reading the input instruction list as a destination for converted +instructions. + +The constraints clause is provided to the conversion clause for +access to operand relationships and types. + +The conversion clause can modify the ioput object's input field +in place with converted instructions or it can place modified +instructions in the output field of the ioput object. + +instr objects are used to hold the newly created instructions. The +annotation fields for a new instruction are assigned to the instr +object. + +In the example presume the sequence match has returned an index of 2 and a +length of 3. In this conversion the 3 unfused instructions are replaced +by 1 fusion created instruction. + +The new instruction attributes are assigned. The ioput container +is modifed to remove the unfused instructions and insert the +fusion replacement. + +``` +ioput iop1 + +conversion conv1(seq1,iop1,cons1) { + instr newInstr + + newInstr(mnemonic="SEQ1",opc=0x1234,uid=0x3) + newInstr(src={g1},dst={g2},imm={c1,c1}) + newInstr(type="fused") + + iop1.input.replace(seq1,newInstr) +} +``` + +There are a large number of fields available in the instr object. Not +all are required by all models. Inclusion of these fields is implementation +dependent. + +### Conversion methods + +The conversion clause has a single method. + +``` +.state This is _pass_ or _fail_ constraints status +``` + +The instr type is valid within a conversion clause. + +---------------------------------------------------------------- +# Tools and Utilities + +A summary of tools and utilities useful for instruction transform work. + +## Condor Fusion API + +FSL domain specific language is a component of a larger C++ API. With this API +it is possible to directly create instruction transforms in C++, or through +the FSL domain specific language or other ad hoc schemes. The API has +been tested with the Condor Performance Model and the Olympia +performance model. + +The Fusion API shares a repository with the Olympia performance model. The +shared URL is contained here: +https://github.com/riscv-software-src/riscv-perf-model/tree/master/fusion. +Doxygen documentation is available for this API. + +## Olympia Performance Model + +Olympia is a performance model written in C++ for the RISC-V community as an +example of an Out-of-Order RISC-V CPU Performance Model based on the Sparta +Modeling Framework. + +The repository URL is https://github.com/riscv-software-src/riscv-perf-model/tree/master. + +## Mavis + +Mavis is a header only framework designed for decoding the RISC-V ISA into +custom instruction class types, along with custom extensions to those +class types. + +The repository URL is https://github.com/sparcians/mavis/tree/main. Doxygen +documentation is available for this API. + +## STF Library + +The STF (Simulation Tracing Format) library provides an API for +reading and generation of STF trace files. + +The repository URL is https://github.com/sparcians/stf_lib. Doxygen +documentation is available for this API. + +---------------------------------------------------------------- +# Appendix + +## FSL BNF + +## FSL style considerations + +There are two styles of FSL shown, the first shows an encapsulated +style, the second shows a library element style. + +Subjectively I think the first style is easier to comprehend and the second +style is where large implementations will likely migrate, because of the +opportunities for reuse. + +In operation there is no difference in the two examples. + +### Encapsulated Style +``` +transform fs1 { + + isa rv64g + uarch oly1 + ioput iop1 + + sequence seq1(iop1,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + _req_ + c.xor g2, g2, g1 + c.slli g2, g2, c3 + _opt_ + c.srli g2, c3 + } + + constraints cons1(seq1,iop1,rv64g,oly1) { + gpr g1,g2 + s20 c1 + s12 c2 + u6 c3 + + g1 != g2 + } + + conversion conv1(seq1,iop1,cons1) { + instr fused(opcode=0x1234) + iop1.input.replace(seq1,fused) + } +} +``` + +### Library Style + +transform fs1 { + prolog prolog1 + sequence seq1 + constraints cons1 + conversion conv1 +} + +prolog prolog1 { + isa rv64g + uarch oly1 + ioput iop1 +} + +sequence seq1(iop1,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + _req_ + c.xor g2, g2, g1 + c.slli g2, g2, c3 + _opt_ + c.srli g2, c3 +} + +constraints cons1(seq1,iop1,rv64g,oly1) { + gpr g1,g2 + s20 c1 + s12 c2 + u6 c3 + + g1 != g2 +} + +conversion conv1(seq1,iop1,cons1) { + instr fused(mnemonic="SEQ1",opcode=0x1234) + iop1.input.replace(seq1,fused) +} + +conversion conv2(seq1,iop1,cons1) { + encoding word1(seq1,mnemonic="SEQ1",opc=0x1234) { + u10 opc # 57:48 unsigned 10b + u6 c3 # 47:42 unsigned 6b + s12 c2 # 41:30 signed 12b + s20 c1 # 29:10 signed 20b + gpr g1 # 9:5 gpr 5b + gpr g2 # 4:0 gpr 5b + encode_order{opc,c3,c2,c1,g1,g2} + } + + instr fused(encoding=word1) + iop1.input.replace(seq1,fused) +} + +## FSL Instruction Types + +Instruction types have a mapping to the ISA description API. The +lower case strings here are mapped to an equivalent type in the ISA +API. When assigning a type to an FSL instr object use the lower +case strings below, without quotes. + +``` +"int" INT +"float" FLOAT +"arith" ARITH +"mul" MULTIPLY +"div" DIVIDE +"branch" BRANCH +"pc" PC +"cond" CONDITIONAL +"jal" JAL +"jalr" JALR +"load" LOAD +"store" STORE +"mac" MAC +"sqrt" SQRT +"convert" CONVERT +"compare" COMPARE +"move" MOVE +"classify" CLASSIFY +"vector" VECTOR +"maskable" MASKABLE +"unit_stride" UNIT_STRIDE +"stride" STRIDE +"ordered_indexed" ORDERED_INDEXED +"unordered_indexed" UNORDERED_INDEXED +"segment" SEGMENT +"faultfirst" FAULTFIRST +"whole" WHOLE +"mask" MASK +"widening" WIDENING +"hypervisor" HYPERVISOR +"crypto" CRYPTO +"prefetch" PREFETCH +"ntl" NTL +"hint" HINT +"cache" CACHE +"atomic" ATOMIC +"fence" FENCE +"system" SYSTEM +"csr" CSR +``` + +## Syntax Highlight Control Files + +### VIM +``` +" Vim syntax file +" Language: Fusion/Fracture Specification Language +" Maintainer: Jeff Nye +" Last Update: 2024 + +" For version 6.x: Quit when a syntax file was already loaded +if version < 600 + syntax clear +elseif exists("b:current_syntax") + finish +endif + +" Set the local value of the 'iskeyword' option. +if version >= 600 + setlocal iskeyword=@,48-57,63,_,192-255 +else + set iskeyword=@,48-57,63,_,192-255 +endif + +" Rules +syn keyword fslKeyword transform sequence constraints emit conversion +syn keyword fslKeyword isa uarch ioput +syn keyword fslSequence _req_ _opt_ _pass_ _fail_ + +syn match fslFunction /\w\+\ze\s*(/ + +syn keyword fslType fpr vvr gpr csr opc instr encoding encode_order iword +syn match fslType "\<[su]\d\+\>" + +syn keyword fslTODO contained TODO FIXME + +syn match fslOperator "[&|~>" +syn match fslVlogNumber "\(\<\d\+\|\)'[sS]\?[bB]\s*[0-1_xXzZ?]\+\>" +syn match fslVlogNumber "\(\<\d\+\|\)'[sS]\?[oO]\s*[0-7_xXzZ?]\+\>" +syn match fslVlogNumber "\(\<\d\+\|\)'[sS]\?[dD]\s*[0-9_xXzZ?]\+\>" +syn match fslVlogNumber "\(\<\d\+\|\)'[sS]\?[hH]\s*[0-9a-fA-F_xXzZ?]\+\>" +syn match fslVlogNumber "\<[+-]\=[0-9_]\+\(\.[0-9_]*\|\)\(e[0-9_]*\|\)\>" + +"Modify the following as needed. The trade-off is performance versus +"functionality. + +syn sync minlines=50 + +hi def link fslKeyword Statement +hi def link fslType FslType +hi def link fslSequence Label +hi def link fslDirective Label + +hi def link fslTODO Todo +hi def link fslComment Comment +hi def link fslFunction Function + +hi def link fslString String + +hi def link fslHexNumber Number +hi def link fslVlogNumber Number + +hi def link fslOperator Special + +hi def link fslIncline SpecialComment +hi def link fslFileName ThisType + +highlight FslType ctermfg=2 gui=bold guifg=SeaGreen + +let b:current_syntax = "fsl" +``` + +1. References + +[1] Celio, Christopher, et al. "The renewed case for the reduced instruction + set computer: Avoiding isa bloat with macro-op fusion for risc-v." arXiv + preprint arXiv:1607.02318 (2016). diff --git a/fsl/docs/deprecated/commonlib.fsl b/fsl/docs/deprecated/commonlib.fsl new file mode 100644 index 00000000..b2d8914f --- /dev/null +++ b/fsl/docs/deprecated/commonlib.fsl @@ -0,0 +1,11 @@ +export gpr fpr cgpr + +// name mnemonic encoding +encode_rule gpr x[0..31] 5'h0..5'h1f +encode_rule fpr f[0..31] 5'h0..5'h1f +encode_rule cgpr x[8..15] 3'h0..3'h7 + +// name mnemonic alias +alias_rule gpr zero,ra,sp,gp,tp,t0..t2,(s0|fp),s1,a[0..7],s[2..11],t[3..6] +alias_rule fpr ft[0..7],fs0,fs1,fa[0..7],fs[2..11],ft[8..11] +alias_rule cgpr s0,s1,a[0..5] diff --git a/fsl/docs/deprecated/notes1_old_syntax_description.md b/fsl/docs/deprecated/notes1_old_syntax_description.md new file mode 100644 index 00000000..5ae16725 --- /dev/null +++ b/fsl/docs/deprecated/notes1_old_syntax_description.md @@ -0,0 +1,205 @@ +# 5. Syntax description +## 5.1 Example sequence +This sample input sequence is used to explain the constraint syntax design. Presume this is a sequence which has a fused version. + +``` +1. UID endcoding mnem operands +2. +3. 0xb 0x76e9 c.lui x13, +0xffffffffffffa000 +4. 0xd 0x0685 c.addi x13, x13, +0x1 +5. 0x1c 0x8d35 c.xor x10, x10, x13 +6. 0xf 0x1542 c.slli x10, x10, 0x30 +7. 0x13 0x9141 c.srli x10, 0x30 +``` +With the exception of the UID column, the other columns are typical of objdump. The UID column is the Mavis assigned unique identifier. + +## 5.2 Example constraints +This is the set of constraints expressed using the proposed syntax: + +``` +C1. The operands in the x13 positions can be any gpr as long as they are all the same gpr. +C2. The operands in the x10 positions can be any gpr as long as they are all the same gpr +C3. The operands in the x10 and x13 positions may not be the same gpr (contrived) +C4. The operands in the IMM=0x30 positions can be any value as long as they are the same value +C5. The value of the immediate in the c.lui instruction is not explicitly constrained +C6. The value of the immediate in the c.addi instruction is not explicitly constrained +``` + +## 5.3 Abstracting the operands +The syntax for sequence expression is derived from assembly language syntax. The operand expressions are abstracted to allow using sequences in multiple scenarios. Below is an example, the left column is common assembly syntax. The right column shows the abstracted form. +``` +1. SAMPLE ABSTRACTED OPERANDS +2. c.lui x13, +0xffffffffffffa000 c.lui g1, c1 +3. c.addi x13, x13, +0x1 c.addi g2, g3, c2 +4. c.xor x10, x10, x13 c.xor g4, g5, g6 +5. c.slli x10, x10, 0x30 c.slli g7, g8, c3 +6. c.srli x10, 0x30 c.srli x10, c4 +``` + +The explicit operands on the left (x13, x10, etc) have been replace with named placeholder variables gN and the immediate constants are cN. + +The constraints are expressed as relationships between the variables. There is an explicit constraint form and a form which makes use of implicit positional constraints. + +This syntax declares an anonymous sequence. A sequence is an ordered list. ‘;’ is an optional statement separator. The sequence order is a principal constraint. +``` +1. sequence seq1 { +2. c.lui g1, c1 +3. c.addi g2, g3, c2 +4. c.xor g4, g5, g6 +5. c.slli g7, g8, c3 +6. c.srli g9, c4 +7. } +``` +Variables are declared as objects of known base types, gpr, csr, fpr, etc, constants are expressed as signed or unsigned with a bit range, s16, u6, etc. Using the case above, declaration of the variables and expressions implementing the constraints is shown below +``` +1. constraints { +2. gpr g1,g2,g3,g4,g5,g6,g7,g8,g9 +3. s20 c1 +4. s12 c2 +5. u6 c3,c4 +6. +7. g1 = g2 = g3 = g6 // This expresses C1 +8. g4 = g5 = g7 = g8 = g9 // C2 +9. g1 != g4 // C3, the contrived constraint +10. c3 = c4 // C4 +11. } // C5 and C6 do not require a statement +``` + +Aspects of the syntax + - Sequence and constraint sections can be anonymous or named + - In the above sample the constraints are anonymous and the sequence has a declared identifier seq1 + - The section declaration syntax, sequence{} and constraints{}, is optional + - The statements within a sequence must be in the correct order + - A sequence with relaxed adjacency requirements uses two key words to identify gaps in the sequence, see Section 6.4 + - The sequence statements must appear before any of the statements associated with the constraints + - The constraints statements must occur before any statements associated with transforms. + +Syntax for simple assignment is also proposed. For example: +``` +g1 = x13 +``` + +## 5.4 Source using explicit constraints +Below is an example declaration of a fusion operation that uses explicit constraints between operands uses +``` +1. fusion_decl fs1 { +2. sequence seq { +3. c.lui g1, c1 +4. c.addi g2, g3, c2 +5. c.xor g4, g5, g6 +6. c.slli g7, g8, c3 +7. c.srli g9, c4 +8. } +9. +10. constraints cons { +11. gpr g1,g2,g3,g4,g5,g6,g7,g8,g9 +12. s20 c1 +13. s12 c2 +14. u6 c3,c4 +15. +16. g1 = g2 = g3 = g6 // This expresses C1 +17. g4 = g5 = g7 = g8 = g9 // C2 +18. g1 != g4 // C3, the contrived constraint +19. c3 = c4 // C4 +20. } +21. +22. transform t1.seq.cons // Still working on the transform syntax +23. // this statement is a reference to an +24. // externally described transform +25. } +``` +## 5.5 Source using positional constraints +The above can be simplified by redefining the variables and using the implicit constraints of the sequence operand positions. G[1,2,3,6] are replaced with g1, g[4,5,7,8,9] are replaced by g2. The result is that the constraints can be simplified as well. +``` +1. fusion_decl fs1 { +2. sequence { // Sequence using positional constraints +3. 0xb g1, c1 // I’ve shown the alternative syntax where +4. c.addi g1, g1, c2 // the mnemonic is replaced with the Mavis +5. c.xor g2, g2, g1 // UID, for the c.lui equiv function +6. c.slli g2, g2, c3 +7. c.srli g2, c3 +8. } +9. +10. gpr g1,g2 +11. s20 c1 +12. s12 c2 +13. u6 c3 +14. +15. //The constraints declarations +16. g1 != g2 // C3, the contrived constraint +17. // In this version of the syntax the +18. transform t1 // scope of sequence and constraints is +19. // within this fusion_decl +20. } +``` + +## 5.6 Using externally defined functions +The final bit of syntax is proposed to allow for sharing of sequences and transforms across groups. Transform sharing is implied above. Transforms, constraints and sequences can be predefined and reused. The proposed syntax for this is: +``` +1. fusion_decl fs1 { +2. sequence seq1 // S1/C1 and T1 are defined elsewhere +3. constraints con1.seq1 // The ‘.’ Is the chaining operator +4. transform t1.seq1.con1 // ordering of the chained elements does not +5. } // matter t1.con1.seq1 is also fine. +``` + +## 5.7 Common library +Implicit in the source above is inclusion of the common library. This can also be done explicitly using the include keyword. + +The native types are defined in the common library, as are standard operators. This is an example of the common library native type definitions +``` +1. export gpr fpr +2. +3. basetype gpr x0..x31 +4. basetype fpr f0..f31 +5. aliastype gpr zero,ra,sp,gp,tp,t0..t2,(s0|fp),s1,a0..a7,s2..s11,t3..t6 +6. aliastype fpr ft0..ft7,fs0,fs1,fa0..fa7,fs2..fs11,ft8..ft11 +``` + +## 5.8 Expressing non-adjacent sequences +Two keywords are used to express two types of adjacency patterns. + - _req_ this expresses a required gap in the sequence. + - _opt_ this expresses an optional gap in the sequence + +Presume we have this sequence; the operands are not shown: +``` +1. Sequence seq2 { +2. AAA +3. _req_ //required gap +4. BBB +5. CCC +6. _opt_ //optional gap +7. DDD +8. } +``` + +Expressing the incoming sequence using lower case, This sequence will not +match seq2 because it lacks a required gap between the A position and B +position. + +``` +1. aaa +2. bbb +3. ccc +4. ddd +``` + +This new sequence will match seq2 ‘xxx’ indicates a sequence element between the A and B positions. + +``` +1. aaa +2. xxx // an arbitrary instruction in the required position +3. bbb +4. ccc +5. ddd +``` + +This sequence will also match seq2, it has the required non-adjacent element and an element in the optional space. +``` +1. aaa +2. xxx // an arbitrary instruction in the required position +3. bbb +4. ccc +5. yyy // an arbitrary instruction in the optional position +6. ddd +``` diff --git a/fsl/docs/deprecated/sequencelib.fsl b/fsl/docs/deprecated/sequencelib.fsl new file mode 100644 index 00000000..bd62d1dc --- /dev/null +++ b/fsl/docs/deprecated/sequencelib.fsl @@ -0,0 +1,75 @@ +// ========================================================= +// ========================================================= +fusion fs1 { + sequence seq1 { + c.lui g1, c1 + c.addi g1, g1, c2 + c.xor g2, g2, g1 + c.slli g2, g2, c3 + c.srli g2, c3 + } + + constraints cons1 { + gpr g1,g2 + s20 c1 + s12 c2 + u6 c3 + + g1 != g2 + } + + iword word1 { + u1 f //59 1b + u1 c //58 1b + u10 fopc //57:48 unsigned 10b + u6 c3 //47:42 unsigned 6b + s12 c2 //41:30 signed 12b + s20 c1 //29:10 signed 20b + gpr g1 //9:5 gpr 5b + gpr g2 //4:0 gpr 5b + + encode_order(f,c,fopc,c3,c2,c1,g1,g2) + } + + transform T1 { + encoding word1(f=1,c=0,S1) + } +} +// ========================================================= +sequence S1_A { + li g1,c1 + li g2,c1 + li g3,c1 + li g4,c1 +} + +constraints C1_A { + gpr g1,g2,g3,g4 + u12 c1 + g1 != g2 != g3 != g4 + c1 == 0 +} + +iword word2 { + u1 f //59 1b + u1 c //58 1b + u10 fopc //57:48 unsigned 10b + u6 c3 //47:42 unsigned 6b + s12 c2 //41:30 signed 12b + s20 c1 //29:10 signed 20b + gpr g1 //9:5 gpr 5b + gpr g2 //4:0 gpr 5b + + encode_order(f,c,fopc,c3,c2,c1,g1,g2) +} + +transform T1 { + encoding word2(f=1,c=0,S1) +} + +fusion fs2 { + sequence S1_A() + constraints C1_A(S1_A) + transform T1_A(S1_A) +} + diff --git a/fsl/docs/deprecated/sequencelib.q.sav b/fsl/docs/deprecated/sequencelib.q.sav new file mode 100644 index 00000000..dfb2ad05 --- /dev/null +++ b/fsl/docs/deprecated/sequencelib.q.sav @@ -0,0 +1,75 @@ +// ------------------------------------ +// Known encoding for fusable sequences +// ------------------------------------ + +// ------------------------------------ +// Example fusion declaration +// ------------------------------------ +fusion fs1 { + sequence S1 { + c.lui g1, c1 + c.addi g1, g1, c2 + c.xor g2, g2, g1 + c.slli g2, g2, c3 + c.srli g2, c3 + } +} +// constraints C1 { +// gpr g1,g2 +// s20 c1 +// s12 c2 +// u6 c3 +// +// g1 != g2 +// } +// iword W1 { +// u1 f //59 1b +// u1 c //58 1b +// u10 fopc //57:48 unsigned 10b +// u6 c3 //47:42 unsigned 6b +// s12 c2 //41:30 signed 12b +// s20 c1 //29:10 signed 20b +// gpr g1 //9:5 gpr 5b +// gpr g2 //4:0 gpr 5b +// +// encode_order(f,c,fopc,c3,c2,c1,g1,g2) +// } +// +// transform T1 { +// //60b fused op encoding +// encoding W1(f=1,c=0,S1) +// } +//} + +//sequence S1_A { +// li g1,c1 +// li g2,c1 +// li g3,c1 +// li g4,c1 +//} +// +//constraints C1_A(sequence S) { +// gpr g1,g2,g3,g4 +// u12 c1 +// S.g1 != S.g2 != S.g3 != S.g4 +// S.c1 == 0 +//} +// +//transform T1_A(sequence S,constraints C) { +// iword<8> +// +//} +// +// +//transform T1_A(sequence S,constraints C) { +// encoding.r_type enc +// encoding.custom(8) addendum +// encoding.custom(40) fused +// +//} +// +//fs2 { +// sequence S1_A +// constraints C1_A +// transform T1_A(S1_A,C1_A) +//} diff --git a/fsl/docs/deprecated/test1.fsl b/fsl/docs/deprecated/test1.fsl new file mode 100644 index 00000000..0adc7948 --- /dev/null +++ b/fsl/docs/deprecated/test1.fsl @@ -0,0 +1,33 @@ +transform fs1 { + + isa rv64g + uarch oly1 + ioput in_seq + + sequence seq1(in_seq,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + c.xor g2, g2, g1 + c.slli g2, g2, c3 + c.srli g2, c3 + } + + constraints cons1(seq1,in_seq,rv64g,oly1) { + gpr g1,g2 + g1 != g2 + } + + transform t1(seq1,cons1) { + encoding word1(seq1,opc) { + u10 opc //57:48 unsigned 10b + u6 c3 //47:42 unsigned 6b + s12 c2 //41:30 signed 12b + s20 c1 //29:10 signed 20b + gpr g1 //9:5 gpr 5b + gpr g2 //4:0 gpr 5b + encode_order(opc,c3,c2,c1,g1,g2) + } + emit(word1(seq1,opc=0x234)) + } +} + diff --git a/fsl/docs/deprecated/test2.fsl b/fsl/docs/deprecated/test2.fsl new file mode 100644 index 00000000..ba5b4659 --- /dev/null +++ b/fsl/docs/deprecated/test2.fsl @@ -0,0 +1,46 @@ +transform fs1 { + + isa rv64g + uarch oly1 + ioput in_seq + + sequence seq1(in_seq,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + _req_ + c.xor g2, g2, g1 + c.slli g2, g2, c3 + _opt_ + c.srli g2, c3 + } + + constraints cons1(seq1,in_seq,rv64g,oly1) { + gpr g1,g2 + g1 != g2 + } + + transform t1(seq1,cons1) { + encoding word1(seq1,opc) { + u10 opc //57:48 unsigned 10b + u6 c3 //47:42 unsigned 6b + s12 c2 //41:30 signed 12b + s20 c1 //29:10 signed 20b + gpr g1 //9:5 gpr 5b + gpr g2 //4:0 gpr 5b + encode_order(opc,c3,c2,c1,g1,g2) + } + emit(word1(seq1,opc=0x234)) + } +} + +//Future feature allow flat decl of fusion elements +//sequence seq1(input_seq in_seq,isa rv64g) +//{ +// c.lui g1, c1 +// c.addi g1, g1, c2 +// _req_ +// c.xor g2, g2, g1 +// c.slli g2, g2, c3 +// _opt_ +// c.srli g2, c3 +//} diff --git a/fsl/docs/fsl_examples/dhrystone.fsl b/fsl/docs/fsl_examples/dhrystone.fsl new file mode 100644 index 00000000..6cd36bb3 --- /dev/null +++ b/fsl/docs/fsl_examples/dhrystone.fsl @@ -0,0 +1,315 @@ +// ---------------------------------------------------------------- +// Fusion group FSL definition set for dhrystone +// TODO: record dhrystone compile options used +// +// ISA definition files are the defined in +// mavis isa_rv64g.json isa_rv64c.json +// +// This example is using olympia and mavis to help make the +// discussion concrete. But mapping of the rv64gc and oly +// names for isa and uarch can be independent of the specifics +// of Mavis (isa def) and Olympia (riscv-perf-model). +// +// See FSL_ENCODING_FORMATS.md file for RISC-V encoding reference +// $TOP/utils/fusion/FSL_ENCODING_FORMATS.md +// +// 188390 instructions in small test case trace +// +// ---------------------------------------------------------------- +//transform TEMPLATE { +// prolog plg +// sequence seq_uXX { +// SSS +// } +// +// constraints cns_uXX { +// CCC +// } +// +// conversion cnv_uXX { +// VVV +// } +//} +// ---------------------------------------------------------------- +// Shared prolog +// ---------------------------------------------------------------- +prolog plg +{ + isa rv64gc + uarch oly + ioput iop +} +// ---------------------------------------------------------------- +// UF1 - 11.7% of trace +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x2f 0xf511c783 lbu x15, -175(x3) I imm is s12 +// 0x0d 0xfbf78793 addi x15, x15,-65 I imm is s12 +// ---------------------------------------------------------------- +transform uf1 +{ + prolog plg + //if there are no constraints the explicit constraints clause is not needed + //constraints cns_uf1 { _pass_ } + //If the conversion is a morph of the sequence, this + //sequence seq_uf1 { 0x2f 0x0d } + //conversion cnv_uf1 { plg.iop.input.replace(seq_uf1,instr(morph(seq_uf1))) } + //is replaced by this: + sequence { 0x2f 0x0d } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x2f 0xfff5c703 lbu x14,-1(x11), I imm is s12 +// 0x03 0xc799 c.beqz x15, 14 CB imm is s8 +// ---------------------------------------------------------------- +transform uf4 +{ + prolog plg + sequence { 0x2f 0x3 } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF8 - minimal +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x33 0xf6b41623 sh x11,-148(x8) S s12 +// 0x2f 0x01e74783 lbu x15, 0(x14) I s12 +// ---------------------------------------------------------------- +transform uf8 +{ + prolog plg + sequence { 0x33 0x2f } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF10 - 3.4% +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x35 0xe290 sd x12,0(x13) CS u5 +// 0x35 0xf6743023 sd x7,-160(x8) S s12 +// ---------------------------------------------------------------- +transform uf10 +{ + prolog plg + sequence { 0x35 0x35 } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF12 - 3.4% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0xa 0xdebff0ef jal x1, -534 J s20 +// 0xd 0x7139 addi x2, x2, -64 CI s6 +// ---------------------------------------------------------------- +transform uf12 { + prolog plg + sequence { 0xa 0xd } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF14 - 2% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x2e 0x00093783 ld x15,0(x18) I s12 +// 0x35 0xe822 sd x8,16(x2) CSS u6 +// ---------------------------------------------------------------- +transform uf14 +{ + prolog plg + sequence { 0x2e 0x35 } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF16 - 3.2% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x34 0xf401aa23 sw x0, -172(x3) S s12 +// 0x9 0x8082 ret CR +// ---------------------------------------------------------------- +transform uf16 +{ + prolog plg + sequence { 0x34 0x09 } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF18 - 2.6% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x34 0x64f72e23 sw x15,1628(x14) S s12 +// 0xa 0xdebff0ef jal x1,-534 J s20 +// ---------------------------------------------------------------- +transform uf18 +{ + prolog plg + sequence { 0x34 0x0a } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF20 - 3.2% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x35 0xec06 sd x1, 24(x2) CSS u6 +// 0x18 0x842a mv x8, x10 CR +// ---------------------------------------------------------------- +transform uf20 +{ + prolog plg + sequence { 0x35 0x18 } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF22 - 2.12% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x18 0x8522 mv x10, x8 CR +// 0xa 0xfa7ff0ef jal x1, -90 J S20 +// ---------------------------------------------------------------- +transform uf22 +{ + prolog plg + sequence { 0x18 0xa } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF24 - 3.4% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x35 0x00fcb023 sd x15,0(x25) S s12 +// 0x35 0xf5243823 sd x18,-176(x8) S s12 +// 0x35 0xf4943c23 sd x9, -168(x8) S s12 +// ---------------------------------------------------------------- +transform uf24 +{ + + prolog plg + gpr g1,g2,g3,g4,g5,g6 + s12 C,D,E + + sequence seq_uf24 { + sd g1, c1(g2) + sd g3, c2(g4) + sd g5, c3(g6) + } + + //The only constraints on this tuple are wr/rd port limits + //we do not need to test the operands only the wr/rd port + //requirements of the combined operand set. Within those + //limits any combination of operands will do. + constraints cns_uf24 { + seq_uf24.writePorts() <= plg.oly.writePorts() + seq_uf24.readPorts() <= plg.oly.readPorts() + } + + // This is a generic transform but with mnemonic assigned + conversion { + instr i_uf24(morph(seq_uf24)) + plg.iop.input.replace(seq_uf24,i_uf24) + } +} +// ---------------------------------------------------------------- +// UF24_example - This version has artifical constraints to show +// syntax options. +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x35 0x00fcb023 sd x15,0(x25) S s12 +// 0x35 0xf5243823 sd x18,-176(x8) S s12 +// 0x35 0xf4943c23 sd x9, -168(x8) S s12 +// ---------------------------------------------------------------- +transform uf24_example +{ + prolog plg + gpr g1,g2,g3,g4,g5,g6 + s12 C,D,E + + sequence seq_uf24_example { + sd g1, c1(g2) + sd g3, c2(g4) + sd g5, c3(g6) + } + + // We could do these constraints all in one block but what is below + // is the example for constraints composition + + //Constraint: the combined encoding for the immediates <= 24bits + //Constraint: the number of wr/rd ports must be compatible with + // the micro architecture limits expressed in plg.oly + + //This constraint checks the ranges on the immediates + //If this fails the fusion group can not be matched + constraints cns_uf24_examplea { + fsl.requiredBits(c1) <= 8 + fsl.requiredBits(c2) <= 8 + fsl.requiredBits(c3) <= 8 + } + + //This constraint just checks for read/write port limits, pass/fail + // + // Fully generalized with g1-g6 all unique represents 6 required + // read ports. If the uarch only supports 4 for example we must + // constrain the match function + // + // This is a simplified all or nothing constraint + constraints cns_uf24_exampleb { + seq_uf24_example.writePorts() <= plg.oly.writePorts() + seq_uf24_example.readPorts() <= plg.oly.readPorts() + } + + constraints cns_uf24_examplec { + //We are going to pretend we can only accept 24 bits of immediate + //8 for each instruction + fsl.requiredBits(c1) <= 8 //if any of these are not true + fsl.requiredBits(c2) <= 8 //the clause exits with _fail_ + fsl.requiredBits(c3) <= 8 + } + + //Given the way it's coded above this is redundant + if(!cns_uf24_examplea || !cns_uf24_exampleb || !cns_uf24_examplec) { _fail_ } + + //The encoding extracts the common info from the S-type format + // S-type + // |---------------------------------------------------------------------| + // | 31 25|24 20|19 15|14 12|11 7|6 0| + // |---------------------------------------------------------------------| + // | imm[11:5] | rs2 | rs1 | funct3 | imm[4:0] | opcode | + // |---------------------------------------------------------------------| + // | 7 bits | 5 bits | 5 bits | 3 bits | 5 bits | 7 bits | + // |---------------------------------------------------------------------| + // + // With the above we are going to assume that since we are executing + // the conversion clause our machine has enough rd/wr ports so we will + // express the rs2/rs1/imm for each, but share the opcode and funct3 + // + // seq[0] seq[1] seq[0] funct3 opcode + // rs2 rs1 imm rs2 rs1 imm rs2 rs1 imm + conversion cnv_uf24_example { + // Our new encoding contains 24 bits for immediate evenly distributed + s8 c1e(fsl.encodeSigned(c1,8)) + s8 c2e(fsl.encodeSigned(c2,8)) + s8 c3e(fsl.encodeSigned(c3,8)) + + //10b of opcode extracted from the 1st seq element, {funct3,opcode} + u10 opcf = {seq_uf24_example[0][14:12],seq_uf24_example[0][6:0]} + + u13 seq0 = {seq_uf24_example[0].rs2,seq_uf24_example[0].rs1,c1e} + u13 seq1 = {seq_uf24_example[1].rs2,seq_uf24_example[1].rs1,c2e} + u13 seq2 = {seq_uf24_example[2].rs2,seq_uf24_example[2].rs1,c3e} + + //Encoding simply skips the need to explicitly declare an unsigned + //bit width, it figures it out + encoding enc({seq0,seq1,seq2,opcf}) + //The mnemonic will be "i_uf24_example" + instr i_uf24_example(encoding(enc)) + } +} diff --git a/fsl/docs/md/FSL_API_USER_REF.md b/fsl/docs/md/FSL_API_USER_REF.md new file mode 100644 index 00000000..e69de29b diff --git a/fsl/docs/md/FSL_APPLICATION_REF.md b/fsl/docs/md/FSL_APPLICATION_REF.md new file mode 100644 index 00000000..e69de29b diff --git a/fsl/docs/md/FSL_USER_REF.md b/fsl/docs/md/FSL_USER_REF.md new file mode 100644 index 00000000..ef96436f --- /dev/null +++ b/fsl/docs/md/FSL_USER_REF.md @@ -0,0 +1,1249 @@ +--- +title: "Fusion/Fracture Specification Language" +author: "Jeff Nye" +date: "2024-06-03" +--- + +# Fusion/Fracture Specification Language + +## Table of contents + +1. Document Information + 1. Change History + 1. Related Documents + 1. TODOs + 1. Future Features + +1. Introduction to FSL + 1. High Level Operation + 1. FSL Example + 1. Is/Is not + +1. Language Description + 1. Scope + 1. Keywords + 1. Identifiers + 1. Literals + 1. FSL Native Types + 1. Signed/unsigned numberic + 1. GPR/CSR + 1. instr + 1. setof + 1. encoding + 1. Operators + 1. Arithmetic + 1. Boolean + 1. Range + 1. Relational + 1. Logical + 1. Assignment + 1. Concatenation + 1. Comments + 1. Preprocessor Support + 1. Conditional Inclusion + 1. Includes + 1. Defines + 1. Transform Structure + 1. Transform Methods + 1. Transform Specification + 1. Prolog Elements + 1. isa Element + 1. isa Methods + 1. uarch Element + 1. uarch Methods + 1. ioput Element + 1. ioput Methods + 1. Sequence Clause + 1. Abstract Operands + 1. Optional Instructions + 1. Sequence Methods + 1. Constraints Clause + 1. Constraints Methods + 1. Conversion Clause + 1. Conversion Methods + +1. Example Use Cases + +1. Tools and Utilities + 1. Condor FSL API + 1. Olympia Performance Model + 1. Mavis + 1. STF Library + +1. Appendix + 1. FSL BNF + 1. FSL style considerations + 1. Encapsulated Style + 1. Library Style + 1. FSL Instruction Types + 1. Syntax Highlight Control File + 1. VIM +1. References + +---------------------------------------------------------------- +# Document Information + +## Change History + +| Version | Date | Contact | Description | +|:-------:|:----------:|:---------:|:--------------------------------------| +| x.4 | 2024.07.xx | Jeff Nye | Prepared for wider review, related documents, expanding language description, detailed use cases, BNF | +| x.3 | 2024.06.03 | Jeff Nye | resolving all SIG review comments and previous TODOs. 1st draft of user reference in preparation for wider review. +| x.2 | 2024.03.10 | Jeff Nye | removed operators, div/mod not needed,++/--/extensive assignment operators violate S +| x.1 | 2024.03.08 | Jeff Nye | typos, replace asserts with exceptions, grammar changes +| x.0 | 2024.03.04 | Jeff Nye | circulated for comment + +## Related Documents +- FSL Repo + - https://github.com/Condor-Performance-Modeling/fsl +- Olympia Repo + - https://github.com/riscv-software-src/riscv-perf-model +- RISC-V Organization Specifications + - https://riscv.org/technical/specifications/ +- An Introduction to Assembly Programming with RISC-V + - https://riscv-programming.org/book.html + +## TODOs +- Placeholder + +## Future features +- The default uarch methods could be extended using template semantics. Extending the methods through specialization of MachineInfo could also extend the syntax of FSL by some restructure of the grammar to treat ID's as possible known methods. + +---------------------------------------------------------------- +# Introduction to FSL + +Fusion/Fracture Specification Language (FSL) is an interpreted language. FSL is used to express properties, constraints and processes for transformation of microprocessor instructions sequences into alternative instruction sequences. + +The FSL interpreter is linked to the FSL API. The API is a c++/python interface that ties the language constructs with higher level systems, like performance models and RTL generation tools. The API is documented in FSL_API_USER_REF.pdf and also in doxygen form. These documents can be found at + +This document focuses on the structure of the domain specific language, FSL, and the expression of instruction sequence transformations. + +Generally, the transformation process converts an N-tuple of processor instructions to an M-tuple of processor instructions. + +When N > M holds, this is the marker for a fusion transformation. + +When N < M holds, this is the marker for a fracture transformation. + +When N = M holds, this is marker for binary translation. + +Informally, fusion converts simpler operations into more complex operations with the intent of improving execution attributes. Fracture commonly replaces more complex operations with simpler operations, with the same intent of improving execution attributes. + +Often N-tuple instructions are elements of a standardized ISA and the M-tuple are customizations of the N-tuple set. The M-tuple instructions are the result of transformation and are internal to the processor. + +FSL assists the expression of the properties of these transformations and takes advantage of the bounds of the domain to provide an efficient syntax for these expressions. + +## High Level Operation + +Each N to M tuple mapping is defined in a named FSL transform specification. The input to a transform is a sequence of instructions, and the output is a potentially transformed sequence. Whether a transformation occurs is determined by constraints expressed in FSL. + +An FSL transform operates in three phases: sequence matching, constraints evaluation, and conversion. These phases are represented by three clauses in an FSL transform specification: + +- Sequence Matching Phase + - Sequence Clause: + - Purpose: Declares the matching attributes to be applied to the input sequence. These attributes can be a list of instruction objects, either in assembly language or as a list of UIDs. + - Process: The sequence clause pattern matches the input sequence against the declared attributes. If a match is found, it updates its internal index and length fields to indicate the position and number of instructions to be transformed. + - Output: If a match is found, the sequence clause returns an index and a length. If no match is found, it returns fail. + - Action on Failure: If sequence matching fails control is returned to the FSL API, which continues processing and notifies the system as required. + +- Constraints Evaluation Phase + - Constraints Clause: + - Purpose: Evaluates the constraints on the matched sequence. + - Process: The constraints clause is applied to the indicated range from the sequence clause and returns a true or false indication. + - Output: If the constraints are satisfied, it returns true and passes the sequence indication to the conversion clause. If not, it returns false. + - Action on Failure: If the constraints clause returns false, control is again returned to the FSL API. + +- Conversion Phase + - Conversion Clause: + - Purpose: Applies the transformation to the input sequence. + - Process: If the conversion clause receives true, it transforms the input sequence starting at the specified index. The transformed sequence is then placed in an output sequence or modifies the input sequence in place, as directed by the syntax. + - Output: The modified or newly created sequence of instructions. + +- Summary of Phases + + - Sequence Clause: Identifies the instruction sequence to be transformed. + - Constraints Clause: Ensures the identified sequence meets the necessary conditions. + - Conversion Clause: Performs the actual transformation of the instruction sequence. + +The FSL API will continue to process all registered FSL transform specifications until the current instruction buffer has been fully transformed or all known transforms have been tested. + +## FSL Example + +An example of an FSL transform specification written in the encapsulated style is shown below. + +In the sample below, the three clauses, sequence, constraints and conversion, are preceded by the variables which declare the instruction set architecture, the micro-architecture of the processor and a sequence container reference. + +``` +transform uf10 +{ + // Prolog elements + isa rv64g // ISA definition object + uarch oly1 // Microarchitecture definition object + ioput iop1 // API interface object + + // Variables at transform scope + gpr g1,g2,g3,g4 + u5 c1 + s12 c2 + + // Example of an abstracted instruction sequence + sequence seq_uf10 { + sd g1,c1(g2) + sd g3,c2(g4) + } + + // Example of a constraints specification + constraints cns_uf10 { + g1 != g2 + g3 != g4 + g1 != g4 + } + + // Example of a conversion clause using abstract morphing + conversion cnv_uf10 { + instr instr_uf10 + instr_uf10.morph(seq_uf1) // merge sequence into 1 object + iop.input.replace(seq_uf10,instr_uf10) // update the input buffer +} +``` + +## Is/Is not + +- FSL is not a programming language + - FSL is a "transformation expression language" +- FSL's target domain is expression of binary transformation of processor instructions + - Within the domain, many aspects of general programming languages are not required or are made implicit +- FSL operates on stylized or symbolic microprocessor instructions +- The FSL syntax style is a reduced boilerplate style of C. e.g. braces are +used, no semi-colons, indentation is not a syntax element. +- There are no user defined functions. However see the `define element. +- There are a limited number of data types unique to FSL. + - Integer constant types are signed or unsigned and have an explicit bit width. + - This is no need for container types. + - Most other standard C native types are not required by the FSL syntax. + - Floating point types are not required by FSL +- FSL uses single assignment for variables. + - Compound assignment expressions and operations are not required +- There are no console or file I/O mechanisms. +- const'ness is not a feature of FSL. +- There is a support library called fsl, which provides utility functions. + - This is the only true namespace in FSL, "fsl.". + +# Language Description + +This is the language specification section. Discussion of usage follows in the Section. + +The (E)BNF for the language is in Section FSL BNF found in the Appendix. + +## Scope + +There is global scope for named tranforms and a local scoping +convention. Variable scoping is lexical. + +Anonymous block scoping, { ...scope... }, is not necessary for FSL operation. + +## Keywords + +The set of keywords is small. Some objects have process/method names +where legal use is indicated by context and are not keywords. + +``` +FIXME: RECREATE THE KEYWORD LIST +``` + +## Identifiers + +Legal variable names are conventional. + +``` +^[a-zA-Z_][a-zA-Z0-9_]*$ +``` + +## Literals + +Numeric literals are expressed as decimal, hexadecimal or the verilog style. + +``` +123 +0x456 +8'b10101010 +4'hF +``` + +For Verilog style constants the '?' value indicates a match all or +don't care element. The width of '?' is relative to the width of +native elements within the constant's base. + +``` + 8'b1010101? bit 0 is a don't care +12'h45? bits [3:0] are a don't care +``` + +String literal syntax is conventional using double quotes. + +``` +"spill_store_merge" +``` + +## FSL Native Types + +### Signed/unsigned numberic +The native integer type equivalents in FSL are signed and unsigned with an explicit width specified in the type name. + +``` +u10 varA //varA will hold unsigned values up to 10 bits in width +s10 varB //varB will hold signed values up to 9 bits + sign + +u3 varA = 0x7 // legal example +s3 varB = 0x17 // warning or exception +``` + +For math operations on these types the internal representation is uint64_t by default. A control is provided in the FSL API to select 32,64,128. uint64_t is the default. + +Assigning a value that will overflow the range of a variable will generate a warning or throw an Fsl::Exception, depending on the configuration of the FSL interpreter. See for interpreter controls. The default is to throw an exception. + +### GPR/CSR +In addition to the FSL integer types the language supports the gpr (General Purpose Register) and csr (Control/Status Register) types. Use of these types is unique to FSL. The contents of gpr or csr variable is the index of the respective register rather then a general value. +``` +gpr g1 = 2 // This specifies X2 in the RISC-V domain +csr s1 = 768 // This specifies the mstatus register in the RISC-V domain +``` + + +The range and boolean operators are not valid for the gpr and csr types. +``` +gpr g1 +gpr g2 = g1[1] // syntax error, range is not valie for gpr/csr +gpr g2 = ~g1 // syntax error, boolean ops are not valid for gpr/csr +``` + +### instr +The instr type declares an abstraction instruction object. These objects are the targets for transformations. + +The instr type has associated methods for assigning attributes. + +``` +.morph() // morphing performs the final transformation + // .morph() is a functor in the FSL API. with + // a default implementation which can be overloaded +.mnemonic(name) // modify the default mnemonic with name + // the default mnemonic is the name of the instr object +.dst({dst list}) // assign the destination fields from a list +.src({src list}) // assign the source fields from a list, the list can + // include numeric literals +.type(type name) // assign a type name, this arbitrary and user defined + // the FSL interpreter provides syntax, the FSL API + // populates the data member. See also the setof type. +.encoding() // explicitly set the encoding for the transformed instr + // object. +``` +### setof +The setof type is a generic collection type which holds lists of objects that have been gathered through attribute comparison. + +The example below scans the isa object rv64gc for the attributes rtype and logical. + +``` +isa rv64gc +setof r_bools = rv64gc.hasAttr(rtype).hasAttr(logical) +``` +In this example the ISA definition API object method .hasAttr() is called with two attributes specified. The FSL interpreter will call the hasAttr methods in right to left order. A list is formed of all ISA objects known to rv64gc with attribute logical. This list is further filtered for all objects that have the rtype attribute. + +The attributes rtype and logical are meaningful to the ISA definition object. The FSL API does not need to comprehend the meaning of rtype or logical. The FSL API calls the ISA definition object's hasAttr() method and places the final objects into the destination, in this case r_bool. + +### encoding +encoding is used when explicit definition is required for transformed instr objects. The encoding object has two methods, .opc() and .encode_order() method. Either of these methods are optional. + +Example usage below. Not shown is the surrounding syntax. + +``` + ... + gpr g1 + s12 c1 + u6 c2 + ... + instr myInstr + encoding myEnc + myEnc.opc(0xFFFF) + myEnc.encode_order({opc,g1,c2,c1}) + myInstr.encoding(myEnc) + ... +``` +When declaring an encoding variable and assigning it to a instr object, if the opc or encode_order fields are NULL the FSL API will treat the instr object as an abstract instruction. + + +## Operators + +The list of operators and their support in FSL is listed below. FSL adds +the range selection operators to the standard C style operators. The syntax is similar to Verilog. + +These operators are unnecessary in FSL: +- Divide, modulus, size_of, pointer operations, type conversions cast/implicit/explicit. + +Within the supported operators FSL uses conventional operator precedence. + +### Arithmetic + +``` + + (Addition) + - (Subtraction) + * (Multiplication) +``` +### Boolean + +``` + & (AND) + | (OR) + ^ (XOR) + ~ (Bitwise NOT) +``` +### Range + +``` + [M:N] (range select) + [M] (index) +``` +### Relational + +``` + == (Equal to) + != (Not equal to) + > (Greater than) + < (Less than) + >= (Greater than or equal to) + <= (Less than or equal to) +``` +### Logical + +``` + && (Logical AND) + || (Logical OR) + ! (Logical NOT) +``` + +### Assignment + +``` + = (Simple assignment) +``` + +### Concatenation + +Concatenation expressions use a style similar to verilog, {a,b,c}; + +``` + xyz = { 3'b00, 4'h3,8'd10 } + abc = { a, b, c } + +``` + +## Comments + +Comments use '//' for single line comments or '/*' and '*/' as +the delimiters for comment blocks. + +``` +// single line comment +/* my multi line + comment + end of ML comment */* +``` + +## Preprocessor Support + +The FSL parser uses a pre-processor with features similar to that found +in the C pre-processor. Within the constraints of the FSL language most +pre-processor operations found in C will be available in FSL with slight +changes for FSL syntax choices. + +Note that the typical # indicator, as in #include, is replaced with +'`' as in `include. + + +### Conditional Inclusion + +FSL supports a typical set of conditional inclusion directives. + +``` +`ifdef X +`ifndef X +`if X == Y +`if Z != 2 + +`endif +`endif +`endif +`endif +``` + +### Includes + +The include keyword declares external files. The parser handles included files by expanding them into the current position in the current translation unit. Include recursion is illegal. + +The syntax is: +``` +`include myfile.fh +``` +The .fh extension is preferred but not enforced by the parser. Quotes around the file name are not used. + +The single inclusion pragma is declared as: +``` +`once +``` +This pragma must be expressed before any other non-comment statement. + +### Defines + +Use of pre-processor defines is close to conventional, the pragma marker is the back tick and an explicit equal sign is required. + +``` +`define A = 7 +`define B = A+1 +``` +These are conventional text replacement macros. Syntax checking is done at the point of insertion within the translation unit. + +## Transform Structure + +FSL transform specifications are read at runtime. The FSL file list is passed to the FSL API constructor. The API invokes the FSL parser. + +A transform's internal structure consists of the sequence, constraints, and conversion clauses, along with a number elements in the prolog which specify the context of the fusion operation, ISA, microarchitecture and hooks into the performance model, and finally any local variables used by the principle clauses. + +## Transform Specification + +The transform statement is a top level structure. Each transform statement is named. The name must be unique across all translation units. + +The generic form is shown below. The order of the sections and clauses is arbitrary. What is shown is the recommended convention. + +The conceptual template for a transform specification is shown: + +``` +transform { + + + + +} +``` + +### Transform Methods + +The transform object has no internal methods accessible through FSL syntax Operations which use the transform element do so implicitly during FSL parsing. + +## Prolog Elements + +The prolog elements provide the necessary context for the transform operation and they are commonly referred to as a group. The common elements are shown: + +``` + isa myIsa + uarch myImplementation + ioput iop1 +``` + +During parsing the FSL interpreter uses the isa and uarch prolog elements to determine the pertinence of a given registered transform to the current context. Transform specifications which do not match the current context are ignored. + +The FSL API contains methods used to specify the current context to the FSL interpreter. This is discussed in the + +It is common to have many transforms for a given combination of ISA, micro-architectures and model interface. Syntax is provided to reduce redunant specification of isa, uarch and ioput. + +The prolog structure supports this improvment. Usage is shown below: + +``` +prolog plog1 +{ + isa myIsa + uarch myImplementation + ioput myIO +} + +transform prolog_example +{ + prolog plog1 + ...etc... +} +``` + +## isa Element + +The ISA description interface is declared with the FSL isa element. + +The ISA description interface is used by the FSL API to validate instruction references in the sequence clause of the transform specification. The API matches the isa element name with a reference registered with API. e.g. the API looks up the 'myIsa' string to find the associated object pointer. The FSL API will throw an exception if the named isa element does not have an associated object. + +Mavis is the instruction set description API provided in this release. Porting to other ISA interfaces is discussed in . + +### isa Methods + +The isa object has no internal methods accessible through FSL syntax. Operations which use the isa element do so implicitly during FSL parsing. + +## uarch Element + +The microarchitecture description interface is declared with the FSL uarch element. + +The microarchitecture description interface is used by the FSL API to validate implementation limits in the contraints clause of a transform specification. + +In the same way the FSL API matches ISA descriptions, the FSL API performs a name look up for the uarch element name against a registered microarchitecture description object. Similarly unmatched references cause an exception to be thrown. + +The microarchitecture description is expressed in the MachineInfo.hpp/cpp of the FSL API. Porting to other machines is discussed in the . + +### uarch methods + +The default uarch methods are documented in MachineInfo.hpp as part of the +FSL API doxygen documentation. + +The default uarch methods can be extended using template semantics. Extending the methods through specialization of MachineInfo also extends the syntax of FSL. + +This is discussed in the + +The syntax shown below is the syntax used in the constraints clause to access the microarchitecture methods. The methods below are the default methods provided by the base MachineInfo.hpp FSL API class. + +``` +.maxIntWrPorts() // returns the maximum available write ports as + // implemented in the machine and reported to + // the FSL runtime by the MachineInfo interface +.maxIntRdPorts() // max write ports for the integer register file +.maxFpWrPorts() // max write ports for the FP register file +.maxFpRdPorts() // max read ports for the FP register file +.maxVecWrPorts() // max write ports for the vector register file +.maxVecWrPorts() // max read ports for the vector register file +.maxIssueWidth() // maximum number of instructions issued per cycle +.maxDecodeWidth() // maximum number of instructions decoded per cycle +.maxFetchWidth() // maximum number of instructions fetched per cycle +``` + +Example usage: +``` +uarch cam +if (cam.maxIntWrPorts() < 4) +{ +...etc... +} +``` + +## ioput Element + +The FSL API links references to C++ buffers containing instruction representations to the FSL interpreter. This linkage is done through a name matching scheme as the other prolog elements. + +ioput is the keyword. Within ioput are two objects representing two instruction buffers, by name they are simply .input and .output. + +During construction the FSL API maps ioput.input and ioput.output to the appropriate performance model containers. 'input' and 'output' are indexes into a map containing references to the model's instruction buffers. + +The FSL API will throw an exception if it can not match the elements in ioput to iterable container objects. Using Olympia as an example, the FSL API will attempt to match the specified name, ioput.input, to a Fusion::InstQueue reference. + +Note: The FSL syntax implies a copy-on-write idiom. However by mapping the ioput.input and ioput.output objects to the same buffer a modification in-place idiom can be implemented. This isolates the style used in the conversion clause from these external mechanics. + +### ioput Methods + +ioput elements have these methods available. + +``` +.clear() empties the associated container +.input reference to the input instruction container +.output reference to the output instruction container +.erase(index,size) removes size elements begining with index, + size is inclusive of the index position. +.insert(index,instr) insert an instr object before index. + instr is an FSL type +.replace(sequence,instr) removes sequence.length objects beginning + at sequence.index, and inserts instr +``` + +## Sequence Clause + +The sequence clause is used to match the incoming instructions found in ioput.input to the current transform. + +A sequence clause is declared with the sequence keyword and optional name and arguments. + +The declaration styles can be either of: + +``` + sequence { //minimal form + + } + + sequence seq1(iop,myIsa) { //argument form + + } +``` + +Either style is valid. When the arguments are unspecified, as in the minimal form, the interpreter will attempt to find unambigous references to an ioput and isa object within the scope of the transform. If either reference fails to resolve the interpreter will issue an exception. + +Naming the sequence is optional when using sequence clause arguments are implicit. A sequence clause name is required when explicit arguments are used. + +``` + sequence (iop,myIsa) { // Invalid. The clause name must be provided when + // explicit arguments are also specified. + } +``` + +The ioput and isa objects are used by the sequence clause to access the instruction containers and known instruction definitions. This access is used for validation of the sequence and for matching. + +``` +ioput myIop +isa myISA + +sequence seq1(myIop,myISA) { + +} +``` + +The FSL parser uses the FSL API and access to the isa object to validate the instruction sequence. An exception is thrown if a problem is detected, for example if the FSL API is unable to determine the intended syntax from the abstract instruction in the sequence it will throw an exception. + +The specified sequence of instructions is pattern matched against the contents of the ioput container. If a match is detected, the sequence object seq1, will update its internal index field and length field. This information is passed to the constraints clause. On a match the sequence clause returns \_pass\_ to the FSL API. + +The index field is the zero-referenced position of the start of the match within ioput. The length is the number of instructions, inclusive of the starting and ending instruction. + +An instruction sequence can be expressed as a simple list of ISA description interface assigned unique identifiers, or as a set of assembly language instructions with abstracted operands. The choice is based on the constraints. + +### Abstract operands +An abstract operand is an FSL concept which specifies the type of an operand but not it's explicit value. Abstract operands are operands declared using FSL native types. For example an explicit three register add instruction might look like +``` +add x1,x2,x3 +``` +And the abstract form matching this instruction would be as shown +``` + gpr GA,GB,GC,GD //declare the sequence variables + +sequence { + add GA,GB,GC // A/B/C + add GA,GD,GD // A/D/D + +} +``` +In the example the gpr type operands are declared and the abstract form of the instruction uses those declarations. Subsequently the contraints clause can reference the variables, their positions within the sequence and apply constraints on the values expected in the ioput buffer. + +The sequence syntax for abstract instruction operands also provides for implicit or implied constraints. For example the FSL API will not match add gpr,gpr,gpr to an instruction that requires an immediate operand. Further the second add, A/D/D, has implicit contraints that the GD operands must be the same value, and that the destination registers, GA, in both instructions must be the same. This is an improvment on the amount of constraints clause statements that must be written. + +Further reductions in coding effort can be obtain in the cases were there are no operand specific constraints. In these cases a sequence can be fully specified with a simple UID list. + +If the target conversion of the transform does not require constraints on the operands and therefore has no need to refer to the operands by name and type, you can simply specify the UIDs as a list, one per line. + +Shown below are two instructions in a frequent sequence from compiled C. The comment is the Mavis unique identifier (UID) for each instruction. The Mavis UID is independent of the operands. +``` +c.slli x10,4 // 0xf +c.srli x10,4 // 0x13 +``` + + ``` +delete me +The UIDs are supplied by the ISA definition API. Note: sequences specified using UIDs will be specific to the ISA definition API. The UIDs listed in this documentation are Mavis assigned UIDs. There is a tradeoff between ease of specification and portability across ISA definition APIs. +``` +These can be represented as a simple UID list. + +``` +sequence { + 0xf + 0x13 +} +``` +With the UID sequence expression there are no operand specific constraints and therefore the conversion clause must handle any legal combinations of the two rd and two constants. + +This results in a transform to a generalized fusion op of shift-left followed by shift-right. + +If the constraints clause implements operand restrictions, the instruction sequence should be expressed using the abstract assembly syntax which allows the operands to be referenced by name. As shown in the GA/GB/GC example above. + +### Optional Instructions + +The example sequences above have an implied strict ordering. Another example is shown below. + +``` +sequence { + add g1, g2, g3 + _opt_ 2 + sub g4, g5, g5 + _req_ 1 + xori g1, g1, c1 +} +``` + +This is a contrived example to show the use of the sequence keywords, \_opt\_ and \_req\_. that can relax the strict ordering implied by previous examples. + +The optional keyword, \_opt\_, indicates that the match will not be rejected if there is an instruction or not in this position. A trailing integer can be used to specify up to N optional instructions. + +The required keyword, \_req\_, indicates that an unspecified instruction is required in that position. The \_req\_ case does not constrain what instruction can be present in the gap. A trailing integer can specify more than one required instruction, \_req\_ 3. + +Trailing integer forms: + +``` +_opt_ 2 indicates 0 - 2 instructions will match +_req_ 2 indicates there must be 2 instructions in this position + in the sequence. +``` + +The trailing integer is optional in the syntax: +``` +_opt_ and _opt_ 1 are equivalent +_req_ and _req_ 1 are equivalent +``` +Note: \_opt\_ and \_req\_ are also supported for the UID case. +Note: Mixing UID and abstract operand sequences is also supported. + +### Sequence Methods + +sequence objects have implicit data members, they are not directly assesible in the FSL syntax. + +``` +.state This is _pass_ or _fail_ match status +.length number of matching instructions, if non-zero this is + the number of UIDs or instruction object epxress in the + sequence. length is 0 if no match is found. + +.index if length is non-zero this index of the first matching + instruction +``` + +## Constraints Clause + +The constraints clause defines relationships between operands, the machine implementation and known transformable sequences. + +Like the other transform clauses, sequence, conversion, a constraints clause is declared with the constraints keyword and optional name and arguments. + +The declaration styles can be either of: + +``` + constraints { //minimal form + + } + + constraints cons1(mySeq,myIoput,myIsa, myUarch) { //argument form + + } +``` +Similar to the sequence clause, arguments to the constraints clause are optional. The FSL API will attempt to find unambiguous references for a sequence object, ioput object, uarch object and a uarch object. + +Similar to the sequence clause syntax rules, if the argument form is intended the constraints clause must be named. This is an illegal declaration: + +``` + contraints (mySeq,myIoput,myIsa, myUarch) { // Invalid. The clause name must + // be provided when explicit + //arguments are also specified. + } +``` +The sequence is used by the constraints clause to access the operand abstractions and UID list. The ioput object is used by the constraints clause to query the instructions in the input buffer to extract operand encodings. The isa object is used to validate the field widths, etc, using in constraints declarations. Finally the uarch object provides the constraints clause access to the machine implementation details. + +When the sequence object contains only UIDs there can be no operand specific constraints, and the constraints clause can simply return \_pass\_. + +``` +constraints { + _pass_ +} +``` + +This is a contrived example used in the explanation that follows. + +``` +prolog p1 +{ + ioput iop1 + isa rv64g + uarch oly1 +} + +transform t1 +{ + prolog p1 + + gpr g1,g2 + u6 c1,c2 + + sequence { + c.slli g1,c1 + c.srli g2,c2 + } + + constraints { + g1 != g2 + c1[0] == c2[1] + } + + ...snip... +} +``` +In this example a shared prolog object is declared and then referenced in transform t1. + +Variables are declared and referenced in the sequence and constraints clauses. g1 and g2 are variables of type gpr. c1 and c2 are variables of unsigned type with field width of 6 bit. + +A sequence clause consisting of two instructions is shown for reference. + +Using RISC-V nomenclature, the constraints clause specifies that, in order to match this transform in this contrived example, the destination register for the first (g1) and second instructions (g2) must not be the same. Further constants u6 contants c1 and c2 have a specific (contrived) limitation between bit 0 of c1 and bit 1 of c2. + +### Constraints Methods + +The constraints clause has a single method. This is not accessible to the FSL syntax. + +``` +.state This is _pass_ or _fail_ constraints status +``` + +In addition to the .state method, the constraints clause declarations +are made available without prefix to the conversion clause. This is +described in the next section. + +## Conversion Clause + +The conversion clause performs the instruction morphing operation(s) to create +the new instruction(s). Conversion syntax supports fracture or fusion, generally any binary translation to any encoding. + +Like the other transform clauses, sequence, constraints, a conversion clause is declared with the conversion keyword and optional name and arguments. + +The declaration styles can be either of: + +``` + conversion { //minimal form + + } + + conversion conv1(mySeq,myIoput,myCons) { //argument form + + } +``` +Similar to the other FSL clauses, arguments to the conversion clause are optional. The FSL API will attempt to find unambiguous references for a sequence object, ioput object, and a constraints object. + +Once again if the argument form is used the converion clause must be named. + +The conversion clause uses the sequence object for access to the named operands or for access to the UID lists. + +The conversion clause uses the ioput object for reading the input instruction list as a destination for converted instructions. + +The conversion clause uses the constraints object for access to operand relationships and types. + +Continuing the previous example, a conversion clause is added, and we add explicit names and arguments to the transform clauses. + +``` +prolog p1 +{ + ioput iop1 + isa rv64gc + uarch oly1 +} + +transform t1 +{ + prolog p1 + + gpr g1,g2 + u6 c1,c2 + + sequence seq_t1(p1.iop1,p1.rv64g) { + c.slli g1,c1 + c.srli g2,c2 + } + + constraints cons_t1(seq_t1,p1.iop1,p1.rv64gc,p1.oly) { + g1 != g2 + c1[0] == c2[1] + } + + conversion conv_t1(seq_t1,p1.iop1,cons_t1) { + instr fused_shift // #1 declaration + fused_shift.mnemonic(zero_ext) // #2 re-assign default mnemonic + + fused_shift.morph(seq_t1) // #3 enumerate the instr object from the + // sequence. + p1.iop.input.replace(seq_uf1,fused_shift) // #4 modify the input containiner + } +} +``` + +This example of a conversion clause introduces a new object, instr. instr objects are generalized instructions, which can be abstract, or have explicit encodings and functions. + +When declared, as in line #1, the instr object mnemonic attribute is assigned the name of the object, fused_shift. This can be modified as shown in #2. The mnemonic attribute has benefit during debug and development. + +Line #3 shows the syntax to create the morphed instruction. + +The FSL API defines a functor (function object) which performs a default morphing operation that combines the elements in the ioput corresponding to the sequence object into 1 abstract instruction. The default behavior described in the FSL API . This functor can be reassigned in the instantiation of the FSL API, and therefore does not require FSL syntax. + +Line #4 replaces the instruction tuple matched by the sequence object with the morphed instruction. In this case the input buffer is modified using .replace(). Depending on needs and implementation the other methods available in the ioput object provide alternative semantics. + +### Conversion Methods + +The conversion clause has a single method. + +``` +.state This is _pass_ or _fail_ conversion status. _fail_ of a conversion + can be ignored or tied to an exception in the FSL API. +``` + +# Example Use Cases +What follows are more detailed walk throughs of FSL uses cases. These are fusion cases in this version of the document. + +## Common Prolog +The examples that follow will share a common Prolog declaration. To reduce duplication this is documented here. This is a RISC-V specific prolog that assumes a super-scalar micro-architecture similar to Olympia or BOOM, and the RV64I-GC ISA extension set. + +``` +prolog plog1 +{ + isa rv64gc + uarch ua + ioput iop +} +``` + + +# Tools and Utilities + +A summary of tools and utilities useful for instruction transform work. + +## Condor FSL API and Interpreter + +FSL domain specific language is a component of a larger C++ API. With this API +it is possible to directly create instruction transforms in C++, or through +the FSL domain specific language or other ad hoc schemes. The API has +been tested with the Condor Performance Model and the Olympia +performance model. + +The FSL API and FSL Interpreter share a public GIT repo. https://github.com/Condor-Performance-Modeling/fsl + +The repo includes the available documentation in PDF, markdown and html form. Doxygen is used to create the html references. The repo also includes support collateral such VIM syntax highlighting files. + +## Olympia Performance Model + +Olympia is a performance model written in C++ for the RISC-V community as an +example of an Out-of-Order RISC-V CPU Performance Model based on the Sparta +Modeling Framework. + +The repository URL is https://github.com/riscv-software-src/riscv-perf-model/tree/master. + +## Mavis + +Mavis is a header only framework designed for decoding the RISC-V ISA into +custom instruction class types, along with custom extensions to those +class types. + +The repository URL is https://github.com/sparcians/mavis/tree/main. Doxygen +documentation is available for this API. + +A Mavis compatible MachineInfo header is supplied in main FSL repo. + +---------------------------------------------------------------- +# Appendix + +## FSL BNF +Included below is the FSL Interpreter grammar in BNF form converted from the native Bison form. + +``` + ::= | + + ::= | | + + ::= TRANSFORM '{' '}' | TRANSFORM '{' '}' + + ::= | + + ::= PROLOG | | | | | | | | + + ::= SETOF '=' '.' + + ::= '.' | + + ::= '(' ')' + + ::= /* empty */ | | | '{' '}' | '*' | '{' '}' + + ::= PROLOG '{' '}' | PROLOG '{' '}' + + ::= | + + ::= ISA | UARCH | IOPUT + + ::= ISA + + ::= UARCH + + ::= IOPUT + + ::= '=' | '=' '{' '}' + + ::= | + + ::= CONSTRAINTS '{' '}' | CONSTRAINTS '(' ')' '{' '}' + + ::= /* empty */ | + + ::= | + + ::= | | | LEFT_OP | '.' '.' | '.' | + + ::= LE_OP | GE_OP | EQ_OP | NE_OP + + ::= CONVERSION '{' '}' | CONVERSION '(' ')' '{' '}' + + ::= | + + ::= | | | | | | '.' | '.' REPLACE '(' ')' + + ::= | ',' + + ::= | | OPC | | '=' + + ::= /* empty */ | '.' + + ::= | ',' + + ::= '[' ']' | '[' ':' ']' | '[' ']' | '[' ':' ']' + + ::= | '.' + + ::= MNEMONIC | ENCODE_ORDER | WRITEPORTS | READPORTS | REQUIREDBITS | ENCODING | OPC | SRC | DST | RSX | IMM | TYPE | HASATTR | MORPH + + ::= INSTR + + ::= INSTR '(' ')' | INSTR '(' '{' '}' ')' | INSTR '(' '{' '}' ')' | INSTR '(' '.' '(' ')' ')' | INSTR '(' '(' ')' ')' + + ::= | ',' + + ::= '[' ']' '.' ENCODING + + ::= ENCODING + + ::= ENCODING '(' ')' | ENCODING '(' '{' '}' ')' + + ::= | ',' + + ::= '=' | '=' '{' '}' | '=' '{' '}' + + ::= PASS | FAIL + + ::= | | STRING_LITERAL | '(' ')' + + ::= | '[' ']' | '(' ')' | '.' | INC_OP | DEC_OP | '.' ENCODING '(' ')' + + ::= /* empty */ | + + ::= | ',' + + ::= | INC_OP | DEC_OP | + + ::= '&' | '*' | '+' | '-' | '~' | '!' + + ::= | '(' ')' + + ::= | '*' | '/' | '%' + + ::= | '+' | '-' + + ::= | LEFT_OP | RIGHT_OP + + ::= | '<' | '>' | LE_OP | GE_OP + + ::= | EQ_OP | NE_OP + + ::= | '&' + + ::= | '^' + + ::= | '|' + + ::= | AND_OP + + ::= | OR_OP + + ::= | '?' ':' + + ::= | + + ::= | ',' + + ::= '=' + + ::= ';' | ';' + + ::= | | | + + ::= | ',' + + ::= | '=' + + ::= EXTERN | AUTO + + ::= GPR | CSR | UN_CONST | S_CONST | STRING + + ::= + + ::= | '(' ')' | '[' '*' ']' | '[' ']' | '[' ':' ']' | '[' ']' | '(' ')' | '(' ')' | '(' ')' + + ::= | ',' + + ::= | + + ::= | ',' + + ::= + + ::= | + + ::= | '{' '}' | '{' ',' '}' + + ::= | ',' + + ::= | | | | + + ::= '{' '}' | '{' '}' + + ::= | + + ::= | + + ::= ';' | ';' + + ::= IF '(' ')' %prec NO_ELSE | IF '(' ')' ELSE + + ::= FOR '(' ')' | FOR '(' ')' | FOR '(' ')' | FOR '(' ')' + + ::= ID + + ::= CONSTANT | HEX_CONST | VLOG_CONST | QSTRING +``` + +## FSL Instruction Types + +Instruction types have a mapping to the ISA description API. The +lower case strings here are mapped to an equivalent type in the ISA description +API. When assigning a type to an FSL instr object use the lower +case strings below, without quotes. + +``` +"int" INT +"float" FLOAT +"arith" ARITH +"mul" MULTIPLY +"div" DIVIDE +"branch" BRANCH +"pc" PC +"cond" CONDITIONAL +"jal" JAL +"jalr" JALR +"load" LOAD +"store" STORE +"mac" MAC +"sqrt" SQRT +"convert" CONVERT +"compare" COMPARE +"move" MOVE +"classify" CLASSIFY +"vector" VECTOR +"maskable" MASKABLE +"unit_stride" UNIT_STRIDE +"stride" STRIDE +"ordered_indexed" ORDERED_INDEXED +"unordered_indexed" UNORDERED_INDEXED +"segment" SEGMENT +"faultfirst" FAULTFIRST +"whole" WHOLE +"mask" MASK +"widening" WIDENING +"hypervisor" HYPERVISOR +"crypto" CRYPTO +"prefetch" PREFETCH +"ntl" NTL +"hint" HINT +"cache" CACHE +"atomic" ATOMIC +"fence" FENCE +"system" SYSTEM +"csr" CSR +``` + + +1. References + +[1] Celio, Christopher, et al. "The renewed case for the reduced instruction + set computer: Avoiding isa bloat with macro-op fusion for risc-v." arXiv + preprint arXiv:1607.02318 (2016). diff --git a/fsl/docs/md/RISCV_ENCODING_FORMATS.md b/fsl/docs/md/RISCV_ENCODING_FORMATS.md new file mode 100644 index 00000000..f4af4942 --- /dev/null +++ b/fsl/docs/md/RISCV_ENCODING_FORMATS.md @@ -0,0 +1,142 @@ +``` + +R-type +|------------------------------------------------------------------------| +| 31 25|24 20|19 15|14 12|11 7|6 0| +|------------------------------------------------------------------------| +| funct7 | rs2 | rs1 | funct3 | rd | opcode | +|------------------------------------------------------------------------| +| 7 bits | 5 bits | 5 bits | 3 bits | 5 bits | 7 bits | +|------------------------------------------------------------------------| + + +I-type +|------------------------------------------------------------| +| 31 20|19 15|14 12|11 7|6 0| +|------------------------------------------------------------| +| immediate | rs1 | funct3 | rd | opcode | +|------------------------------------------------------------| +| 12 bits | 5 bits | 3 bits | 5 bits | 7 bits | +|------------------------------------------------------------| +immediate is S12 + +S-type +|---------------------------------------------------------------------| +| 31 25|24 20|19 15|14 12|11 7|6 0| +|---------------------------------------------------------------------| +| imm[11:5] | rs2 | rs1 | funct3 | imm[4:0] | opcode | +|---------------------------------------------------------------------| +| 7 bits | 5 bits | 5 bits | 3 bits | 5 bits | 7 bits | +|---------------------------------------------------------------------| + + +B-type +|------------------------------------------------------------------------| +| 31 |30 25|24 20|19 15|14 12| 11 |10 7|6 0| +|------------------------------------------------------------------------| +| imm[12] | imm[10:5] | rs2 | rs1 | funct3 | imm[11] | imm[4:1] | opcode | +|------------------------------------------------------------------------| +| 1b | 6b | 5b | 5b | 3b | 1b | 4b | 7b | +|------------------------------------------------------------------------| + + +U-type +|----------------------------------------------------| +|31 12|11 7|6 0| +|----------------------------------------------------| +| imm[31:12] | rd | opcode | +|----------------------------------------------------| +| 20 bits | 5 bits | 7 bits | +|----------------------------------------------------| + + +J-type +|------------------------------------------------------------------| +| 31 |30 21| 20 |19 12|11 7|6 0| +|------------------------------------------------------------------| +| imm[20] | imm[10:1] | imm[11] | imm[19:12] | rd | opcode | +|------------------------------------------------------------------| +| 1 bit | 10 bits | 1b | 8b | 5b | 6b | +|------------------------------------------------------------------| +immediate is S20 [20,10:1,11,19:12] + +CR +|------------------------------------------| +|15 12|11 7|6 2|1 0| +|------------------------------------------| +| func4 | rd_rs1 | rs2 | op | +|------------------------------------------| +| 4 bit | 5 bits | 5b | 2b | +|------------------------------------------| + + +CI +|---------------------------------------------| +|15 13| 12 |11 7|6 2|1 0| +|---------------------------------------------| +| funct3 | imm[5] | rd_rs1 | imm[4:0] | op | +|---------------------------------------------| +| 3 bit | 1b | 5b | 5b | 2b | +|---------------------------------------------| +immediate is S6 + + +CSS +|------------------------------------| +|15 13|12 7|6 2|1 0| +|------------------------------------| +| funct3 | imm[5:0] | rs2 | op | +|------------------------------------| +| 3b | 5b | 5b | 2b | +|------------------------------------| +immediate is U6 + + +CIW +|------------------------------------| +|15 13|12 5|4 2|1 0| +|------------------------------------| +| funct3 | imm[7:0] | rs2 | op | +|------------------------------------| +| 3b | 8b | 3b | 2b | +|------------------------------------| + + +CL +|-------------------------------------------------------| +|15 13|12 7|6 2|6 5|4 2|1 0| +|-------------------------------------------------------| +| funct3 | imm[4:2] | rs1' | imm[1:0] | rd' | op | +|-------------------------------------------------------| +| 3b | 3b | 3b | 2b | 3b | 2b | +|-------------------------------------------------------| + +CS +|-------------------------------------------------------| +|15 13|12 7|6 2|6 5|4 2|1 0| +|-------------------------------------------------------| +| funct3 | imm[4:2] | rs1' | imm[1:0] | rs1' | op | +|-------------------------------------------------------| +| 3b | 3b | 3b | 2b | 3b | 2b | +|-------------------------------------------------------| + +CB +|----------------------------------------------------------| +|15 13|12 10|9 7|6 2|1 0| +|----------------------------------------------------------| +| funct3 | offset[7:5] | rs1' | offset[4:0] | op | +|----------------------------------------------------------| +| 3b | 3b | 3b | 5b | 2b | +|----------------------------------------------------------| +immediate is S5 + +CJ +|----------------------------------------------------------| +|15 13|12 2|1 0| +|----------------------------------------------------------| +| funct3 | jumptarget[10:0] | op | +|----------------------------------------------------------| +| 3b | 11b | 2b | +|----------------------------------------------------------| + +``` diff --git a/fsl/fsl_api/CMakeLists.txt b/fsl/fsl_api/CMakeLists.txt new file mode 100644 index 00000000..83b72b90 --- /dev/null +++ b/fsl/fsl_api/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.10) +project(FslApi) + +# This is a header-only API at the moment diff --git a/fsl/fsl_api/FieldExtractor.h b/fsl/fsl_api/FieldExtractor.h new file mode 100644 index 00000000..419280fd --- /dev/null +++ b/fsl/fsl_api/FieldExtractor.h @@ -0,0 +1,280 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file FieldExtractor.h mavis shim, extract fields from encodings +#pragma once +#include "fsl_api/FusionExceptions.h" +#include "fsl_api/Instruction.h" +#include "fsl_api/uArchInfo.h" +#include "mavis/Mavis.h" + +#include +#include +#include +#include +using namespace std; + +//! \class FieldExtractor +//! +//! \brief example class for extracting field values from mavis encodings +//! +//! This implementation provides a shim between operations typically +//! used during fusion contraint checking and transformation and mavis. +//! +//! The intent is any alternative to FieldExtractor could be created +//! if compliant with the interface. This has not been tested. +//! +//! It would also be interesting to determine if more of this could be +//! delegated to existing methods in mavis. +class FieldExtractor +{ + public: + //! \brief Part of mechanism to extract named fields from encodings + //! + //! OperandFieldID has no entry for immediates + //! \note I am overloading RS_MAX when referencing immediate fields + using FieldName = mavis::InstMetaData::OperandFieldID; + //! \brief alias used to extract Special fields by enum + using SFieldName = mavis::ExtractorIF::SpecialField; + + //! \brief ... + using InstPtrType = Instruction::PtrType; + //! \brief ... + using InstPtrListType = std::vector::PtrType>; + //! \brief type for getXRegs operations from mavis + using MavisBitMaskType = mavis::DecodedInstructionInfo::BitMask; + //! \brief type for getXRegs operations from mavis + using RegsGetter = + MavisBitMaskType (Instruction::*)() const; + //! \brief duplicated arguments do not need to be explicitly expressed + using OptArg = std::optional; + + //! \brief compairson function primitives + enum FUNC + { + EQ, + LT + }; + + //! \brief extract value of named encoding field + //! + //! handles field name and immediate checking + //! \note RS_MAX is overloaded to identify get's for immediate fields + uint32_t getField(InstPtrType inst, FieldName field) const + { + bool isDest = false; + if (!checkInstHasField(inst, field, isDest)) + { + throw fusion::FieldExtUnknownField((uint32_t)field, + inst->dasmString()); + } + + if (field == FieldName::RS_MAX) + return getImmField(inst); + + return getFieldById(inst, field, isDest); + } + + //! \brief get the encoded value of a named special field from an + //! instptr + //! + //! This is simpler than getField, a return value of 0 from mavis + //! indicates the field does not exist so checkInstHasSField() + //! is redundant. getSFieldById() is also not necessary since + //! SpecialFields are not distinguished as a source or destination + //! operand and can be accessed from the same method. + uint32_t getSField(InstPtrType inst, SFieldName field) const + { + uint32_t value = inst->getSpecialField(field); + if (value == 0) + { + throw fusion::FieldExtUnknownSpecialField((uint32_t)field, + inst->dasmString()); + } + return value; + // return getSFieldById(inst, field); + } + + //! \brief get the encoded value of the full immediate field + //! + //! split immediate fields are (will be) ordered msb:lsb and + //! concatenated into one unsigned value + uint32_t getImmField(InstPtrType inst) const { return 0; } + + //! \brief helper function for getField, src/dst switch + //! + //! isDest is set previously by checkInstHasField() + uint32_t getFieldById(InstPtrType inst, FieldName field, bool isDest) const + { + if (isDest) + { + return inst->getDestOpInfo().getFieldValue(field); + } + return inst->getSourceOpInfo().getFieldValue(field); + } + + //! \brief Use mavis to determine if the FieldName exists in this inst + //! obj + //! + //! Special case check for immediates; + //! srcOp and dstOps have to be checked separately. + //! + //! This is legally marked const, it does not modify *this, + //! but it does modifies the argument isDest. + bool checkInstHasField(InstPtrType inst, FieldName field, + bool & isDest) const + { + if (inst->hasImmediate() && field == FieldName::RS_MAX) + { + return true; + } + + if (inst->getSourceOpInfo().hasFieldID(field) + && field != FieldName::RS_MAX) + { + return true; + } + + // FIXME: I do not see the reason but this if statement will fail + // with + // terminate called after throwing an instance of + // 'mavis::OperandInfoInvalidFieldID' + // what(): OperandInfo field ID '' is invalid + // + // if(inst->getDestOpInfo().hasFieldID(field) && field != + // FieldName::RS_MAX) + // { + // isDest = true; + // return true; + // } + // + // But doing this is fine... + bool idok = inst->getDestOpInfo().hasFieldID(field); + bool fok = field != FieldName::RS_MAX; + if (idok && fok) + { + isDest = true; + return true; + } + + // catch fall through + throw fusion::FieldExtUnknownField((uint32_t)field, + inst->dasmString()); + return false; ///... + } + + //! \brief equality + bool eq(const InstPtrListType & input, size_t a, size_t b, + const FieldName f1, const OptArg f2 = std::nullopt) const + { + return compare(input[a], input[b], f1, f2, EQ); + } + + //! \brief less than + bool lt(const InstPtrListType & input, size_t a, size_t b, + const FieldName f1, const OptArg f2 = std::nullopt) const + { + return compare(input[a], input[b], f1, f2, LT); + } + + //! \brief not equal + bool noteq(const InstPtrListType & input, size_t a, size_t b, + const FieldName f1, const OptArg f2 = std::nullopt) const + { + return !compare(input[a], input[b], f1, f2, EQ); + } + + //! \brief greater than + bool gt(const InstPtrListType & input, size_t a, size_t b, + const FieldName f1, const OptArg f2 = std::nullopt) const + { + return compare(input[b], input[a], f1, f2, LT); + } + + //! \brief less than or equal + bool lteq(const InstPtrListType & input, size_t a, size_t b, + const FieldName f1, const OptArg f2 = std::nullopt) const + { + return !compare(input[b], input[a], f1, f2, LT); + } + + //! \brief greater than or equal + bool gteq(const InstPtrListType & input, size_t a, size_t b, + const FieldName f1, const OptArg f2 = std::nullopt) const + { + return !compare(input[a], input[b], f1, f2, LT); + } + + //! \brief return the integer read ports used by the input fusion group + uint32_t getIntRdPorts(const InstPtrListType & input) const + { + return countPorts(input, + &Instruction::getIntSourceRegs); + } + + //! \brief return the integer write ports used by the input fusion + //! group + uint32_t getIntWrPorts(const InstPtrListType & input) const + { + return countPorts(input, &Instruction::getIntDestRegs); + } + + //! \brief return the float read ports used by the input fusion group + uint32_t getFloatRdPorts(const InstPtrListType & input) const + { + return countPorts(input, + &Instruction::getFloatSourceRegs); + } + + //! \brief return the float write ports used by the input fusion group + uint32_t getFloatWrPorts(const InstPtrListType & input) const + { + return countPorts(input, + &Instruction::getFloatDestRegs); + } + + //! \brief return the vector read ports used by the input fusion group + uint32_t getVecRdPorts(const InstPtrListType & input) const + { + return countPorts(input, + &Instruction::getVectorSourceRegs); + } + + //! \brief return the vector write ports used by the input fusion group + uint32_t getVecWrPorts(const InstPtrListType & input) const + { + return countPorts(input, + &Instruction::getVectorDestRegs); + } + + private: + //! \brief compare common method + bool compare(const InstPtrType LHS, const InstPtrType RHS, + const FieldName f1, const OptArg _f2, FUNC func) const + { + FieldName f2 = _f2.value_or(f1); + + auto lhs = getField(LHS, f1); + auto rhs = getField(RHS, f2); + + switch (func) + { + case FUNC::LT: { return lhs < rhs; } + case FUNC::EQ: { return lhs == rhs; } + default: { return false; } + } + } + + //! \brief count the number of read or write ports required by the + //! group + uint32_t countPorts(const InstPtrListType & input, + RegsGetter getRegs) const + { + mavis::DecodedInstructionInfo::BitMask mask; + for (const auto & i : input) + { + mask |= (i.get()->*getRegs)(); + } + return mask.count(); + } +}; diff --git a/fsl/fsl_api/Fusion.h b/fsl/fsl_api/Fusion.h new file mode 100644 index 00000000..cdd6dcd3 --- /dev/null +++ b/fsl/fsl_api/Fusion.h @@ -0,0 +1,427 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh, Condor Computing Corp. +// +//! \file Fusion.h top level fusion API +#pragma once +#include "json.hpp" +#include "fsl_api/FieldExtractor.h" +#include "fsl_api/FusionContext.h" +#include "fsl_api/FusionExceptions.h" +#include "fsl_api/FusionGroup.h" +#include "fsl_api/FusionTypes.h" +#include "fsl_api/MachineInfo.h" + +#include +#include +#include +#include +#include + +namespace fusion +{ + //! \class Fusion + //! + //! \brief top level fusion class + //! + //! In this implementation the allocators are placeholders + //! for more complex use cases. They are provided for future + //! extensions. + //! + //! Input needed to create a fusion 'context' can come + //! from explicitly construction of FusionGroups, construction + //! from the helper class FusionGroupCfg, and eventually + //! from the DSL or from Json. + //! + //! Both the DSL and JSON are future features. With the DSL + //! having a parser and a defined syntax. The JSON form has + //! no definition at the moment, the JSON form could be a simple + //! syntax variation of the DSL form. The linkage to the + //! transform function object needs to be defined for JSON. + //! + //! There is a single context assumed although there are + //! stubs for multiple context support. At the moment it + //! is not clear if multiple context are actually a + //! useful feature for fusion enabled instruction + //! decoders in the existing performance models. + //! + //! For usage see the testbench.cpp in fusion/test. For the + //! final PR there will more usage examples. + template , + typename MachineInfoTypeAlloc = + fusion::ShrPtrAlloc, + typename FieldExtractorTypeAlloc = + fusion::ShrPtrAlloc> + struct Fusion + { + //! \brief list of fusion groups + using FusionGroupListType = std::vector; + + //! \brief the fusion context container type + //! + //! \see FusionContext.h + using FusionGroupContainerType = + std::unordered_map; + + //! \brief group cfg is a ctor helper class + using FusionGroupCfgType = + fusion::FusionGroupCfg; + + //! \brief list of group cfg instances + using FusionGroupCfgListType = std::vector; + + //! \brief transformation function object type + //! + //! support for future feature + using TransformFuncType = bool (*)(FusionGroupType &, + InstPtrListType &, + InstPtrListType &); + //! \brief context type is based on fusion groups and instr ptrs + using FusionContextType + = fusion::FusionContext; + + //! \brief custom fusion operator signature type + using FusionFuncType = std::function; + + //! \brief list of fusion group match attributes + //! + //! Multiple matches may occur, not all will meet their + //! constraints. This list is sorted longest match to shorter. + //! Longest match that meets constraints is selected + using MatchInfoListType = std::vector ; + + //! \brief main ctor + Fusion(const FusionGroupListType & fusiongroup_list, + const FusionGroupCfgListType & fusiongroupcfg_list, + const FileNameListType & txt_file_list, + const FusionGroupTypeAlloc fusiongroup_alloc = + fusion::ShrPtrAlloc(), + const MachineInfoTypeAlloc machine_info_alloc = + fusion::ShrPtrAlloc(), + const FieldExtractorType field_extractor_alloc = + fusion::ShrPtrAlloc()) : + fusiongroup_alloc_(fusiongroup_alloc), + machine_info_alloc_(machine_info_alloc), + fusionOpr(defaultFusionOpr) + { + if (fusiongroup_list.size() > 0) + initialize(fusiongroup_list); + else if (fusiongroupcfg_list.size() > 0) + initialize(fusiongroupcfg_list); + else if (txt_file_list.size() > 0) + initialize(txt_file_list); + context_.makeContext("fbase", fusiongroup_list); + } + + //! \brief ctor from group list + Fusion(const FusionGroupListType & fusiongroup_list) : + Fusion(fusiongroup_list, {}, {}, FusionGroupTypeAlloc(), + MachineInfoTypeAlloc(), FieldExtractorType()) + { + } + + //! \brief ctor from cfg group list + Fusion(const FusionGroupCfgListType & fusiongroupcfg_list) : + Fusion({}, fusiongroupcfg_list, {}, FusionGroupTypeAlloc(), + MachineInfoTypeAlloc(), FieldExtractorType()) + { + } + + //! \brief ctor from txt file list + //! + //! Supports FSL or JSON, type is inferred from file extension + //! All files in the list must be one or the other. + Fusion(const FileNameListType &txt_file_list) : + Fusion({}, {}, txt_file_list, FusionGroupTypeAlloc(), + MachineInfoTypeAlloc(), FieldExtractorType()) + { + } + + //! \brief initialize state from a group list + void initialize(const FusionGroupListType & fusiongroup_list) + { + for (auto grp : fusiongroup_list) + { + registerGroup(grp); + } + } + //! \brief initialize from a group cfg list + void initialize(const FusionGroupCfgListType & grp_list) + { + for (auto cfg : grp_list) + { + FusionGroupType f(cfg); + registerGroup(f); + } + } + //! \brief initialize from a text file list + //! + //! For simplicity assume all files are the same type + //! as first file. I do not see a need at the moment + //! for mixing types. + //! + //! Future: JSON/DSL syntax is being created and reviewed. + void initialize(const FileNameListType &txt_file_list) + { + if (txt_file_list.size() == 0) return; + + //Uses file extension, relies parsing to capture + //cases the contents are not as indicated by the extension + //FIXME: in this draft version of the code only handling + //the first JSON file. + bool useJson = hasExtension(txt_file_list[0],".json"); + if (useJson) + { + FusionGroupCfgListType cfgGroups; + std::string fn = txt_file_list[0]; + parseJsonFusionGroups(txt_file_list[0],cfgGroups); + } + else + { + //Future feature + //fp.setInputFiles(txt_file_list); + //int ret = fp.parse(); + //if (ret) + //{ + // // Future feature - needs additional handling + // throw fusion::FslSyntaxError(fp.errMsg, fp.lineNo); + //} + throw fusion::FslSyntaxError("FSL parsing is not supported",0); + } + } + //! \brief populate a list of FusionGroups from a JSON file + void parseJsonFusionGroups(const std::string fn, + FusionGroupCfgListType &cfgGroups) + { + std::ifstream in(fn); + if(!in.is_open()) + { + throw JsonRuntimeError( + std::string("Could not open file '" + fn +"'")); + } + + nlohmann::json jparser; + + try + { + in >> jparser; + } + catch(const std::exception&) + { + throw JsonSyntaxError(); + } + + for(const auto& item : jparser["fusiongroups"]) + { + checkForJsonField(item,"name"); + checkForJsonField(item,"uids"); + checkForJsonField(item,"tx"); + + string grpName = item["name"]; + string txName = item["tx"]; + + FusionGroupCfgType fg { + .name = grpName, + .uids = std::nullopt, + .transformName = txName + }; + + InstUidListType uids; + for(const auto& uid_str : item["uids"]) + { + int uid = std::stoi(uid_str.get(), + nullptr,16); + uids.push_back((uint32_t) uid); + } + fg.uids = uids; + cfgGroups.push_back(std::move(fg)); + } + initialize(cfgGroups); + } + + //! \brief throw if field is missing + void checkForJsonField(const nlohmann::json& item, + const std::string& fieldName) const + { + if (!item.contains(fieldName)) + { + throw JsonRuntimeError("missing field "+fieldName); + } + } + + //! \brief check file extension + bool hasExtension(const std::string filePath, + const std::string ext) const + { + std::filesystem::path fPath(filePath); + return fPath.extension() == ext; + } + + //! \brief alias for context_.insertGroup() + void registerGroup(const FusionGroupType & grp) + { + context_.insertGroup(grp); + } + + //! \brief create a single context from a list of fusiongroups + //! + //! This is here to support generality but I have + //! not seen an immediate need for dynamic switching + //! between multiple fusion contexts in a simulation. + //! Something to consider for the future. + void makeContext(const std::string & name, + const FusionGroupListType & fusiongroup_list) + { + context_.makeContext(name, fusiongroup_list); + } + + //! \brief return a ref to current context + //! + //! There is support for multiple named contexts. There + //! is need for only one context in the current implementation. + //! + //! \see FusionContext.h + FusionContextType & getCurrentContext() const + { + return context_; + } + + //! \brief return a ref to the group container in the current context + //! + //! Consider friendship to skip a level of indirection, but + //! at the moment there is no indication this matters for speed. + //! And this is a cleaner form of encapsulation. + //! + //! \see FusionContext.h + FusionGroupContainerType& getFusionGroupContainer() + { + return context_.getFusionGroupContainer(); + } + + //! \brief interface to the fusion operation + //! + //! This is the principle interface to the fusion operation. + //! The operator can modify both input and output as needed. + //! The default operator appends in to out and clears in. + //! + //! fusionOpr can be assigned with a user function. + void fusionOperator(InstPtrListType & in, InstPtrListType & out) + { + fusionOpr(*this, in, out); + } + + //! \brief report fusion groups + //! + //! Dump the group info to a file + void reportGroups(const std::string reportFileName) const + { + std::ofstream out(reportFileName.c_str()); + if(!out.is_open()) throw fusion::FileIoError("open",reportFileName); + reportGroups(out); + out.close(); + } + + void reportGroups(std::ostream & os) const + { + os<<"Fusion groups: "<insert(grp); + // } + // + // typename FusionGroupType::PtrType makeFusionGroup( + // const std::string name, + // const InstUidListType &uidlist, + // TransformFuncType func) + // { + // FusionGroupType grp(name,uidlist,func); + // return context_.rtrie()->insert(grp); + // } + + //! \brief DSL parser + //! + //! At present this performs syntax checking of the input + //! files. The remaining operations have not been implemented + //! Future: DSL syntax is being redesigned + //FslParser fslParser; + + //! \brief default fusion operator appends in to out and clears + //! out. + static void defaultFusionOpr(Fusion & inst, InstPtrListType & in, + InstPtrListType & out) + { + out.insert(out.end(), in.begin(), in.end()); + in.clear(); + } + + //! \brief emit group container groups + void infoGroups(std::ostream &os, + const FusionGroupContainerType &fgroups) const + { + os<<"INFO fusionGroups "< +#include +#include +#include +#include + +namespace fusion +{ +// ---------------------------------------------------------------------- +//! \class FusionGroupMatchInfo +// +//! \brief fusion group match return structure +//! +//! Signed integer for startIdx is for no-match reporting without +//! increasing the ctor signature. +// ---------------------------------------------------------------------- +struct FusionGroupMatchInfo { + FusionGroupMatchInfo(std::string name_, + int32_t startIdx_, + uint32_t groupIdx_, + InstUidListType _matchedUids) + : name(name_), + startIdx(startIdx_), + groupIdx(groupIdx_), + matchedUids(_matchedUids) + { } + + //this is only kept for stats reporting, fgroup utilization maps, etc + std::string name = ""; + int32_t startIdx = -1; + int32_t groupIdx = -1; + size_t size() const { return matchedUids.size(); } + + InstUidListType matchedUids; + + friend std::ostream& operator<<(std::ostream& os, + const FusionGroupMatchInfo& matchInfo) + { + os << std::dec << std::setfill(' ') + << " name " << matchInfo.name + << " groupIdx " << std::setw(3) << matchInfo.groupIdx + << " startIdx " << std::setw(3) << matchInfo.startIdx + << " size " << std::setw(3) << matchInfo.size(); + return os; + } +}; +// ----------------------------------------------------------------------- +//! \class FusionContext +//! +//! +//! \brief Holds an searchable list of the current FusionGroups +//! +//! In this implementation the groups are held and searched +//! within a uo/map. There is a trie implementation but that +//! is not used currently. Before adding the trie if will be +//! useful to spend more time with large fusion group definitions +//! and see how the map performs vs the trie (or alternatives). +//! +//! Future abstration : typename container or typename tree: +//! typename FusionGroupContainerType = +//! std::unordered_map, +//! typename LookupType = fusion::ShrPtrAlloc +// ----------------------------------------------------------------------- +template +class FusionContext +{ + //! \brief for now this is a uo/map with uint key + using FusionGroupListType = std::vector; + //! \brief for now this is a uo/map with uint key + using FusionGroupContainerType = + std::unordered_map; + //! \brief return struct for matching groups during context search + using MatchInfoListType = std::vector; + //! \brief mavis assigned UID list type + using InstUidListType = fusion::InstUidListType; + + public: + FusionContext() = default; + + //! \brief basic ctor + //! + //! name_ member is assigned in makeContext + FusionContext(const std::string & name, + const FusionGroupListType & groups) + { + makeContext(name_, groups); + } + + //! \brief insert each group into the (only/current) context + void makeContext(const std::string & n, + const FusionGroupListType & groups) + { + name_ = n; + for (const auto & grp : groups) + { + insertGroup(grp); + } + } + + //! \brief insert each group w/ catch + void insertGroup(const FusionGroupType & group) + { + fusion::HashType hash = group.hash(); + if (hash == 0) + { + throw fusion::HashIllegalValueError(group.name(), + group.hash()); + } + + if (container_.find(hash) != container_.end()) + { + throw fusion::HashDuplicateError(group.name(), group.hash()); + } + + container_.insert(std::make_pair(hash, group)); + } + + //! \brief public function to get group list from container + FusionGroupContainerType& getFusionGroupContainer() + { + return container_; + } + + private: + //! \brief context name + //! + //! When this is used in (future) multi-context implementations + //! the name must be unique + std::string name_{""}; + //! \brief this is an alias for map in this version + FusionGroupContainerType container_; +}; + +} diff --git a/fsl/fsl_api/FusionExceptions.h b/fsl/fsl_api/FusionExceptions.h new file mode 100644 index 00000000..de40de6a --- /dev/null +++ b/fsl/fsl_api/FusionExceptions.h @@ -0,0 +1,235 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file FusionExceptions.h fusion defined exceptions +#pragma once +#include "fsl_api/FusionTypes.h" + +#include +#include +#include +#include + +//! \class ContextDuplicateError +//! \class FieldExtUnknownField +//! \class FieldExtUnknownSpecialField +//! \class FileIoError +//! \class FslRuntimeError +//! \class FslSyntaxError +//! \class FusionExceptionBase +//! \class FusionExceptionBase +//! \class FusionInitializationError +//! \class HashDuplicateError +//! \class HashIllegalValueError +//! \class JsonRuntimeError +//! \class JsonSyntaxError +//! \class JsonUnknownError + +namespace fusion +{ + + //! \brief exception base class for fusion operation exceptions + //! + //! There are a number of forward looking struct definitions. + //! In the final implementation I expect this set to be modified + class FusionExceptionBase : public std::exception + { + public: + //! \brief ... + const char* what() const noexcept override { return why_.c_str(); } + + protected: + //! \brief ... + std::string why_; + //! \brief ... + std::stringstream ss; + }; + + //! \brief report any issues during the Fusion context + //! + //! Fusion is initialized by a call from the Decoder ctor to + //! an initialization function. This handles default or + //! non-specific initialization failures. + struct FusionInitializationError : FusionExceptionBase + { + //! \brief ... + explicit FusionInitializationError(const std::string & cause) + { + ss << "Fusion intialization failed: " << cause; + why_ = ss.str(); + } + }; + + //! \brief hashes within a context can not overlap + //! + //! Each fusion group has a hash formed from the uids of the + //! in the group. The hash is the key into a uo/map. These hashes + //! are checked for uniqueness on construction + struct HashDuplicateError : FusionExceptionBase + { + //! \brief ... + explicit HashDuplicateError(const std::string & name, + const fusion::HashType & hash) + { + ss << "Duplicated hash detected, '" << name << "'" + << " 0x" << std::hex << hash; + why_ = ss.str(); + } + }; + + //! \brief illegal hash value cause this to be thrown + //! + //! At the moment 0 is a reserved/illegal hash value + struct HashIllegalValueError : FusionExceptionBase + { + //! \brief ... + explicit HashIllegalValueError(const std::string & name, + const fusion::HashType & hash) + { + ss << "Illegal hash value detected, '" << name << "'" + << " 0x" << std::hex << hash; + why_ = ss.str(); + } + }; + + //! \brief context name duplication was detected + //! + //! This supports (future feature) of multiple + //! contexts keyed off the context name string + struct ContextDuplicateError : FusionExceptionBase + { + //! \brief ... + explicit ContextDuplicateError(const std::string & name) + { + ss << "Duplicated context detected, '" << name << "'"; + why_ = ss.str(); + } + }; + + //! \brief QParser will throw this + //! + //! Throwing this from the parser has not been implemented + //! yet in this draft PR. + struct FslSyntaxError : FusionExceptionBase + { + //! \brief ... + explicit FslSyntaxError(const std::string & msg, + const int & lineno) + { + ss << "DSL syntax error '" << msg << "'" << std::endl + << " at line: " << lineno; + why_ = ss.str(); + } + }; + + //! \brief for errors discovered when using dsl values + struct FslRuntimeError : FusionExceptionBase + { + //! \brief ... + explicit FslRuntimeError(const std::string & msg) + { + ss << "FslRuntimeError placeholder: " << msg; + why_ = ss.str(); + } + }; + + //! \brief catch all from the DSL code + struct FslUnknownError : FusionExceptionBase + { + //! \brief ... + explicit FslUnknownError(const std::string & msg) + { + ss << "FslUnknownError placeholder: " << msg; + why_ = ss.str(); + } + }; + + //! \brief json syntax errors + //! + //! JSON support is planned but not implemented + //! + //! FIXME: check if nlohmann bombs out before + //! we get here. If so remove this. + struct JsonSyntaxError : FusionExceptionBase + { + //! \brief ... + explicit JsonSyntaxError(const int & lineno) + { + ss << "JSON syntax error line: " << lineno; + why_ = ss.str(); + } + //! \brief ... + explicit JsonSyntaxError() + { + ss << "JSON syntax error reported by nlohmann"; + why_ = ss.str(); + } + }; + + //! \brief for errors discovered when using json values + struct JsonRuntimeError : FusionExceptionBase + { + //! \brief ... + explicit JsonRuntimeError(const std::string & msg) + { + ss << "JsonRuntimeError: " << msg; + why_ = ss.str(); + } + }; + + //! \brief catch all from the JSON code + //! + //! JSON support is planned but not implemented + struct JsonUnknownError : FusionExceptionBase + { + //! \brief ... + explicit JsonUnknownError(const std::string & msg) + { + ss << "JsonUnknownError: " << msg; + why_ = ss.str(); + } + }; + + //! \brief field extractor unknown field name + //! + //! FIXME: should add a field enum to string func, + //! convert int to FieldName string + struct FieldExtUnknownField : FusionExceptionBase + { + //! \brief ... + explicit FieldExtUnknownField(uint32_t fn, std::string dasm) + { + ss << "Unknown field: " << fn << " in " << dasm; + why_ = ss.str(); + } + }; + + //! \brief field extractor unknown special field name + //! + //! FIXME: should add a field enum to string func, + //! convert int to SFieldName string + struct FieldExtUnknownSpecialField : FusionExceptionBase + { + //! \brief ... + explicit FieldExtUnknownSpecialField(uint32_t sfn, + std::string dasm) + { + ss << "Unknown special field: " << sfn << " in " << dasm; + why_ = ss.str(); + } + }; + + //! \brief file access exception + struct FileIoError : FusionExceptionBase + { + //! \brief ... + explicit FileIoError(std::string action, + std::string fileName) + { + ss << "File access error on '" << action + << "' for file " << fileName; + why_ = ss.str(); + } + }; + +} // namespace fusion diff --git a/fsl/fsl_api/FusionGroup.h b/fsl/fsl_api/FusionGroup.h new file mode 100644 index 00000000..c49b077e --- /dev/null +++ b/fsl/fsl_api/FusionGroup.h @@ -0,0 +1,333 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file FusionGroup.h holds fusion definitions and transforms +#pragma once +#include "fsl_api/FusionTypes.h" +#include "fsl_api/Instruction.h" +#include "mavis/Mavis.h" + +#include +#include +#include +#include +#include +#include +#include + +//! \class FusionGroupCfg + +namespace fusion +{ +// ---------------------------------------------------------------------- +// ---------------------------------------------------------------------- +//! \brief forward decl +template +class FusionGroup; +// --------------------------------------------------------------- +//! \brief FusionGroup ctor helper +//! +//! FusionGroupCfg helps construct FusionGroups from combinations +//! of ctor arguments. There is more work to do here. +//! +//! MachineInfoType provides access to implementation details of the machine +//! +//! FieldExtractor provides an interface to mavis and support functions +//! for boolean operations. +//! +//! (will) support: +//! UIDs implemented +//! opcodes not implemented, future feature +//! asm text not implemented, future feature +// --------------------------------------------------------------- +template +struct FusionGroupCfg +{ + //! \brief convenient group type + using FusionGroupType = + FusionGroup; + + //! \brief transform functor signature + using TransformFuncType = + bool (*)(FusionGroup &, + InstPtrListType &, InstPtrListType &); + + // Future feature + // uids can be derived from opcs, but not the other way + // if conversion from opcs to uids is required so is Mavis + // std::optional opcs; + // std::optional asms; + // fusion::MavisType *mavis{nullptr}; + + //! \brief default transform functor + //! + //! The default transform makes no changes to machine state, it + //! provides an argument signature for TransformFuncType. + static bool default_transform(FusionGroupType &, InstPtrListType & in, + InstPtrListType & out) + { + (void) in; + (void) out; + return true; + } + //! \brief convenient name string + const std::string name; + //! \brief list of UIDs representing the group + std::optional uids; + //! \brief string key look up for transformFunc mapping + //! + //! When used the transformName is the lookup key into an + //! external map containing function objects to perform transforms. + const std::string transformName; + //! \brief handle for the transform function + //! + //! In previous implementations constraints checking and + //! transformation were enforced as split operations. This is + //! no longer required. + std::optional transformFunc = default_transform; +}; +// --------------------------------------------------------------- +//! \brief FusionGroup parent +//! +//! opcs & asm statements are not supported yet, future +// --------------------------------------------------------------- +class FusionGroupBase +{ + public: + //! \brief save typing + using UidType = fusion::UidType; + //! \brief save typing + using HashType = fusion::HashType; + //! \brief save typing + using InstPtrListType = fusion::InstPtrListType; + //! \brief save typing + using InstUidListType = fusion::InstUidListType; + + //! \brief base ctor + FusionGroupBase(std::string n = "", + InstUidListType u = InstUidListType(), + HashType h = 0) : + name_(n), + uids_(u), + // Future feature + // opcs_(fusion::OpcodeListType()), + // asms_(fusion::AsmStmtListType()), + hash_(h) + { + } + + virtual ~FusionGroupBase() + { + } + + //! \brief capture the UIDs and create the hash key + virtual void setUids(InstUidListType & u) + { + uids_ = u; + initHash(); + } + + //! \brief uids accessor + virtual InstUidListType & uids() { return uids_; } + + // virtual OpcodeListType& opcs() { return opcs_; } + // virtual AsmStmtListType& asms() { return asms_; } + + //! \brief hash setter + virtual void setHash(HashType hash) { hash_ = hash; } + + //! \brief refresh the hash from uids_ + virtual void initHash() { hash_ = jenkins_1aat(uids_); } + + //! \brief hash accessor + virtual HashType hash() const { return hash_; } + + //! \brief convenience function + virtual void setName(std::string n) { name_ = n; } + + //! \brief name accessor + virtual std::string name() const { return name_; } + + //! \brief report fgroup state to stream + friend std::ostream& operator<<(std::ostream& os, + const FusionGroupBase& grp) + { + os << "X Name: " << grp.name(); + os << " Hash: " << std::hex << " " << grp.hash(); + os << " Uids: "; + for (auto u : grp.uids_) + { + os << " " << std::hex << std::setw(2) << std::setfill('0') << u; + } + return os; + } + + public: + //! \brief Method to calculate hash based on UIDs + //! + //! In future consider making this a user controlled functor. + //! In hardware the adds are not desirable. + static HashType jenkins_1aat(const std::vector & v) + { + HashType hash = 0; + + for (auto i : v) + { + hash += i; + hash += (hash << 10); + hash ^= (hash >> 6); + } + + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return hash; + } + + private: + //! \brief convenient name string + std::string name_{""}; + //! \brief the instruction UIDs known to mavis + InstUidListType uids_; + // Future feature + // OpcodeListType opcs_; + // AsmStmtListType asms_; + //! \brief uint32_t hash key + HashType hash_{0}; +}; + +// --------------------------------------------------------------- +//! \brief A fusion group is the basis for fusion detection and transformation +//! +//! A fusion group is a list of UIDs that represent data useful for +//! matching a group against incoming Inst::PtrTypes as well as +//! constraints checking. +//! +//! TransformFuncType transform_ is the functor handle. The default +//! is expected to be overridden externally. +// --------------------------------------------------------------- +template +class FusionGroup : public FusionGroupBase +{ + //! \brief convenient typedef + using FusionGroupType = + FusionGroup; + + //! \brief conform to convention used else where + using MavisType = Mavis, uArchInfo>; + + //! \brief convenient typedef + using FusionGroupCfgType = + FusionGroupCfg; + + //! \brief functor signature and typedef + using TransformFuncType = + bool (*)(FusionGroup &, + InstPtrListType &, InstPtrListType &); + + public: + //! \brief conform to convention used elsewhere + typedef typename std::shared_ptr< + FusionGroup> + PtrType; + + // -------------------------------------------------------------------- + //! \brief default ctor + FusionGroup(std::string n = "", InstUidListType u = InstUidListType(), + TransformFuncType t = nullptr) : + FusionGroupBase(n, u), + transform_(t) + { + initHash(); + } + + // -------------------------------------------------------------------- + //! \brief groupcfg ctor + FusionGroup(const FusionGroupCfgType & cfg) : + FusionGroupBase(cfg.name, + cfg.uids ? *cfg.uids : InstUidListType() //, + // cfg.opcs ? *cfg.opcs : OpcodeListType() + ), + transform_(cfg.transformFunc ? *cfg.transformFunc : nullptr) + { + if (uids().size() == 0) + { + throw std::invalid_argument( + "For " + cfg.name + + " uids are required in this implementation"); + } + initHash(); + } + + // Future support + // void opc2uid(const OpcodeListType &opcs, + // const fusion::MavisType *mavis, + // InstUidListType &uid_vec) + //{ + // } + + // Future support + // void asm2uid(const AsmStmtListType &asm, + // const fusion::MavisType *mavis, + // InstUidListType &uid_vec) + //{ + // } + + //! \brief transform elements of input to append to output + //! + //! transform() is called when a fusiongroup is selected by + //! Fusion (fusion.h). The return value returns true if + //! the transform function met the criterion. False if not. + //! On false Fusion continues to search the context. + //! + //! The transform operation is expected to modify in if fusion + //! occurs and also to append to out with the transformation + //! results. All combinations of true/false, modifying/not modifying + //! input and output are valid. + bool transform(InstPtrListType & in, InstPtrListType & out) + { + if (transform_) + return transform_(*this, in, out); + return false; + } + + //! \brief default transform functor + //! + //! The group is not fused, input is appended to out. input is cleared. + static bool default_transform(FusionGroupType &, InstPtrListType & in, + InstPtrListType & out) + { + out.insert(std::end(out), std::begin(in), std::end(in)); + in.clear(); + return true; + } + + //! \brief user method for changing the default transform functor + void setTransform(TransformFuncType func) { transform_ = func; } + + //! \brief tranform handle accessor + TransformFuncType getTransform() { return transform_; } + + //! \brief machine info handle accessor + MachineInfoType & mi() { return mi_; } + + //! \brief machine info handle accessor + MachineInfoType & machineInfo() { return mi(); } + + //! \brief field extractor handle accessor + FieldExtractorType & fe() { return fe_; } + + //! \brief field extractor handle accessor + FieldExtractorType & fieldExtractor() { return fe(); } + + private: + //! \brief MachineInfo provides access to uarch details + MachineInfoType mi_; + //! \brief FieldExtractor provides field access methods + FieldExtractorType fe_; + //! \brief handle to transform functor + TransformFuncType transform_ = default_transform; +}; + +} // namespace fusion diff --git a/fsl/fsl_api/FusionTypes.h b/fsl/fsl_api/FusionTypes.h new file mode 100644 index 00000000..f01b0cf9 --- /dev/null +++ b/fsl/fsl_api/FusionTypes.h @@ -0,0 +1,57 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file FusionTypes.h marshalled types used by fusion +#pragma once +#include "fsl_api/Instruction.h" +#include "fsl_api/uArchInfo.h" +#include "mavis/DecoderTypes.h" +#include "mavis/Mavis.h" + +#include +#include +#include + +namespace fusion +{ +//! \brief ... +using MavisType = Mavis, uArchInfo>; +//! \brief ... +using FileNameListType = std::vector; +//! \brief ... +using UidType = mavis::InstructionUniqueID; +//! \brief ... +using InstUidListType = std::vector; +//! \brief ... +using FieldName = mavis::InstMetaData::OperandFieldID; +//! \brief ... +using SFieldName = mavis::ExtractorIF::SpecialField; +//! \brief ... +using Opcode = mavis::Opcode; +//! \brief ... +using OpcodeListType = std::vector; +//! \brief ... +using AsmStmtListType = std::vector; +//! \brief ... +using InstPtrType = Instruction::PtrType; +//! \brief ... +using InstPtrListType = std::vector::PtrType>; +//! \brief ... +using HashType = uint32_t; +//! \brief ... +using HashListType = std::vector; + +//! \brief This is provided but has limited use currently +template struct ShrPtrAlloc +{ + //! \brief ... + using Tptr = std::shared_ptr; + + //! \brief ... + template Tptr operator()(Args &&... args) + { + return std::make_shared(std::forward(args)...); + } +}; + +} diff --git a/fsl/fsl_api/HCache.h b/fsl/fsl_api/HCache.h new file mode 100644 index 00000000..a1ff5bde --- /dev/null +++ b/fsl/fsl_api/HCache.h @@ -0,0 +1,164 @@ +// Header placeholder +// contact jeff at condor +//! \file Hcache.h +#pragma once +//TODO: do general performance tests for map, uo_map, array etc. +//TODO: template +#include "fsl_api/FusionTypes.h" + +#include +#include +#include + +namespace fusion +{ + +//! \class HCache +//! +//! \brief Length indexed fusion group hash lookup structure +//! +//! HCache provides performance benefit to the model's execution when +//! there are a large number of FusionGroups to compare UID sequences +//! against. +struct HCache +{ + //! \brief 'words' in the $ 'line' are pairs, length and resulting hash + using HashPair = pair; + //! \brief value type for cache + using HashPairListType = std::vector; + //! \brief type used by the 'cache' array + using HCacheType = std::map; + //! \brief non-const iterator + using HCacheItrType = HCacheType::iterator; + //! \brief function object type + using HashFuncType + = fusion::HashType (*)(const std::vector&); + //! \brief ctor with hash function object argument + HCache(HashFuncType func = nullptr) + : hashFunc(func) + {} + + // ------------------------------------------------------------------ + //! \brief create an entry in the cache + //! + // Create a size-indexed entry for a hash of inputUid fragments of + // length grpSize. This entry is added to the hashCache. + // + // On entry into this function a walking hash is created for the + // fusion group size. e.g. if grpSize is three, and the input is + // length 5, three hashes will be created. + // + // a b c d e input + // F F F hash 1 + // F F F hash 2 + // F F F hash 3 + // + // These hashes are cached, indexed by length. + // + // A cache line is a list of pairs, a list of + // The cache is a map of cachelines, indexed by size, + // + // ------------------------------------------------------------------ + void buildHashCacheEntry(const InstUidListType &inputUids,size_t grpSize) + { + //create the sub-divisions of length grpSize + vector fragments; + subDivideUids(fragments,inputUids,grpSize); + + //this will be the 'cacheline' of hcache, calculate the + //hash of each fragment. pair.first is the index into fragments + HashPairListType cacheLine; + + size_t i=0; + for(auto & uidVec : fragments) { + fusion::HashType hash = hashFunc(uidVec); + cacheLine.push_back(make_pair(i++,hash)); + } + + hcache.insert(make_pair(grpSize,cacheLine)); + } + + // ------------------------------------------------------------------ + //! \brief prepare a vector of uids for the hash operation + //! + //! Uids groups based on the length of the input. The hash will + //! be formed for each sub-division + // ------------------------------------------------------------------ + void subDivideUids(std::vector &output, + const InstUidListType &inputUids,size_t length) + { + if(length == 0 || inputUids.size() == 0) return; + + output.clear(); + + // Calculate how many vectors of reference's length can be generated + size_t numVectors = inputUids.size() - length + 1; + + for (size_t i = 0; i < numVectors; ++i) { + InstUidListType temp; + + // Extract elements from input starting at index i, + // with the same length as reference + for (size_t j = 0; j < length; ++j) { + temp.push_back(inputUids[i + j]); + } + + output.push_back(temp); + } + } + + // ------------------------------------------------------------------ + //! \brief output cache entries to a stream + // ------------------------------------------------------------------ + void infoHCache(std::ostream &os) + { + os<<"INFO hcache"; + for(auto & hc : hcache) + { + os<<" "<second; + } + +private: + //! \brief function object for hash creation + HashFuncType hashFunc; + + //! \brief future feature: support for template version of HCache + std::map hcache; +}; + +} diff --git a/fsl/fsl_api/Instruction.h b/fsl/fsl_api/Instruction.h new file mode 100644 index 00000000..8584dcb3 --- /dev/null +++ b/fsl/fsl_api/Instruction.h @@ -0,0 +1,146 @@ +// +// Created by David Murrell on 11/7/19. +// +// JN: original file name was Inst.h + +#ifndef DTABLEPROTO03_INST_H +#define DTABLEPROTO03_INST_H + +#include +#include +#include "mavis/OpcodeInfo.h" +#include "mavis/Extractor.h" + +/** + * EXAMPLE Instruction + */ +template class Instruction { +public: + typedef typename std::shared_ptr> PtrType; + +public: + // Instruction(const mavis::DecodedInstructionInfo::PtrType& dii, const + // uint64_t icode, const mavis::ExtractorIF::PtrType& extractor, const + // typename AnnotationType::PtrType& ui) : + Instruction(const mavis::OpcodeInfo::PtrType &dinfo, + const typename AnnotationType::PtrType &ui, uint32_t dummy) + : dinfo_(dinfo), uinfo_(ui) {} + + // Copy construction (needed for cloning) + Instruction(const Instruction &) = default; + + // Morph into a different instruction (new mavis info) + void morph(const typename mavis::OpcodeInfo::PtrType &new_dinfo, + const typename AnnotationType::PtrType &new_ui) { + // dinfo_.reset(new_dinfo); + dinfo_ = new_dinfo; + // uinfo_.reset(new_ui); + uinfo_ = new_ui; + + // TBD: Instruction user may need to reset any information cached with this + // instruction + } + + /** + * User code to "recycle" an instruction (which DTable has cached and is + * attempting to reuse) + */ + void recycle() {} + + typename mavis::OpcodeInfo::PtrType getOpInfo() const { return dinfo_; } + + std::string getMnemonic() const { return dinfo_->getMnemonic(); } + + std::string dasmString() const { return dinfo_->dasmString(); } + + bool isInstType(mavis::InstMetaData::InstructionTypes itype) const { + return dinfo_->isInstType(itype); + } + + bool + isExtInstType(mavis::DecodedInstructionInfo::ExtractedInstTypes itype) const { + return dinfo_->isExtractedInstType(itype); + } + + int64_t getSignedOffset() const { return dinfo_->getSignedOffset(); } + + mavis::DecodedInstructionInfo::BitMask getSourceAddressRegs() const { + return dinfo_->getSourceAddressRegs(); + } + + mavis::DecodedInstructionInfo::BitMask getSourceDataRegs() const { + return dinfo_->getSourceDataRegs(); + } + + mavis::DecodedInstructionInfo::BitMask getIntSourceRegs() const { + return dinfo_->getIntSourceRegs(); + } + + mavis::DecodedInstructionInfo::BitMask getFloatSourceRegs() const { + return dinfo_->getFloatSourceRegs(); + } + + mavis::DecodedInstructionInfo::BitMask getVectorSourceRegs() const { + return dinfo_->getVectorSourceRegs(); + } + + mavis::DecodedInstructionInfo::BitMask getIntDestRegs() const { + return dinfo_->getIntDestRegs(); + } + + mavis::DecodedInstructionInfo::BitMask getFloatDestRegs() const { + return dinfo_->getFloatDestRegs(); + } + + mavis::DecodedInstructionInfo::BitMask getVectorDestRegs() const { + return dinfo_->getVectorDestRegs(); + } + + uint64_t getSpecialField(mavis::OpcodeInfo::SpecialField sfid) const { + return dinfo_->getSpecialField(sfid); + } + + const mavis::OperandInfo &getSourceOpInfo() const { + return dinfo_->getSourceOpInfo(); + } + + const mavis::OperandInfo &getDestOpInfo() const { + return dinfo_->getDestOpInfo(); + } + + mavis::InstructionUniqueID getUID() const { + return dinfo_->getInstructionUniqueID(); + } + + bool hasImmediate() const { return dinfo_->hasImmediate(); } + + const typename AnnotationType::PtrType &getuArchInfo() const { + return uinfo_; + } + +//private: + typename mavis::OpcodeInfo::PtrType dinfo_; + typename AnnotationType::PtrType uinfo_; + + void print(std::ostream &os) const { + std::ios_base::fmtflags os_state(os.flags()); + os << dinfo_->getMnemonic() << ", src[" << dinfo_->numSourceRegs() + << "]: " << dinfo_->getSourceRegs() + << " (addr: " << dinfo_->getSourceAddressRegs() << ")" + << ", dst: " << dinfo_->getDestRegs() << ", data size: " << std::dec + << dinfo_->getDataSize(); + if (uinfo_ != nullptr) { + os << ", uInfo: " << *uinfo_; + } + os.flags(os_state); + } + +public: + friend std::ostream &operator<<(std::ostream &os, + const Instruction &i) { + i.print(os); + return os; + } +}; + +#endif // DTABLEPROTO03_INST_H diff --git a/fsl/fsl_api/MachineInfo.h b/fsl/fsl_api/MachineInfo.h new file mode 100644 index 00000000..adf85f15 --- /dev/null +++ b/fsl/fsl_api/MachineInfo.h @@ -0,0 +1,77 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file MachineInfo.h processor implementation details +#pragma once +#include +#include +#include +#include + +//! \brief Placeholder for uarch and implementation details +//! +//! I have not followed up on the discussion on using +//! extension.core_extensions from the yaml for this information. +//! This is future work. +struct MachineInfo +{ + //! \brief there is only a default constructor provided + MachineInfo() {} + + //! \brief access number of implemented integer write ports + uint32_t maxIntWrPorts() const { return maxIntWrPorts_; } + + //! \brief access number of implemented float write ports + uint32_t maxFpWrPorts() const { return maxFpWrPorts_; } + + //! \brief access number of implemented vector write ports + uint32_t maxVecWrPorts() const { return maxVecWrPorts_; } + + //! \brief access number of implemented integer read ports + uint32_t maxIntRdPorts() const { return maxIntRdPorts_; } + + //! \brief access number of implemented float read ports + uint32_t maxFpRdPorts() const { return maxFpRdPorts_; } + + //! \brief access number of implemented vector read ports + uint32_t maxVecRdPorts() const { return maxVecRdPorts_; } + + //! \brief Is there a location available to execute a fused operator? + //! + //! Obviously, a placeholder. This would be a debug function + //! trap dispatch to execute pipes that do not implement the fused opr. + bool compSiteImplemented(uint32_t magic) const { return true; } + + //! \brief how many cycles to wait for the InstrQueue to fill + //! + //! Since fusion operates on 1 or more opcodes there are cases + //! where the InstrQueue may not have enough opcodes to validate + //! fusion groups. This is more of an issue for N-tuples > 2. + //! At some point the cycles saved by fusion are spent waiting + //! for fusable opportunities. This limits the impact. + uint32_t allowedLatency() const { return allowedLatency_; } + + //! \brief ... + void setName(std::string n) { name_ = n; } + + //! \brief ... + std::string name() const { return name_; } + + private: + //! \brief arbitrary name + std::string name_{"noname"}; + //! \brief ... + uint32_t maxIntWrPorts_{2}; + //! \brief ... + uint32_t maxFpWrPorts_{2}; + //! \brief ... + uint32_t maxVecWrPorts_{2}; + //! \brief ... + uint32_t maxIntRdPorts_{4}; + //! \brief ... + uint32_t maxFpRdPorts_{4}; + //! \brief ... + uint32_t maxVecRdPorts_{4}; + //! \brief ... + uint32_t allowedLatency_{1}; +}; diff --git a/fsl/fsl_api/Makefile b/fsl/fsl_api/Makefile new file mode 100644 index 00000000..53b59d37 --- /dev/null +++ b/fsl/fsl_api/Makefile @@ -0,0 +1,4 @@ +# Placeholder, this is a header only API at the moment +.PHONY: clean +clean: + diff --git a/fsl/fsl_api/RadixTrie.h b/fsl/fsl_api/RadixTrie.h new file mode 100644 index 00000000..71c915a3 --- /dev/null +++ b/fsl/fsl_api/RadixTrie.h @@ -0,0 +1,120 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file RadixTrie.h space optimized search tree(trie) +#pragma once +#include +#include +#include +#include +#include +#include +#include + +//! \brief Node for uint32_t radix trie +//! +template class RadixTrieNode +{ + public: + //! \brief ... + bool isEndOfWord; + //! \brief ... + std::vector> children; + + //! \brief ... + RadixTrieNode() : isEndOfWord(false) + { + children.resize(1 << BIT_WIDTH); + for (auto & child : children) + { + child = nullptr; + } + } +}; + +//! \brief RadixTrie with element width as template parameter +//! +//! This is self explanatory. 4 bits seems to be the most performant, +//! for state sizes of 1024*1024. +//! +//! This is not used in the current implementation. It is provided +//! in the DPR for comment on future use and because I am comparing +//! performance against real sets of fusion groups. There is little +//! to no protection against 'bad' input. That will come later. +//! +//! 1 1024*1024 +//! Time taken for insertion: 7.31112 seconds +//! Time taken for searching: 1.26558 seconds +//! 2 1024*1024 +//! Time taken for insertion: 4.85911 seconds +//! Time taken for searching: 0.691898 seconds +//! 4 1024*1024 +//! Time taken for insertion: 4.77562 seconds <=== 4 bits +//! Time taken for searching: 0.43249 seconds +//! 8 1024*1024 +//! Time taken for insertion: 25.8369 seconds +//! Time taken for searching: 0.319623 seconds +template class RadixTrie +{ + public: + //! \brief per convention used elsewhere + typedef std::shared_ptr PtrType; + + //! \brief default ctor + RadixTrie() : root(std::make_unique>()) {} + + //! \brief insert... + void insert(uint32_t key) { insertRecursive(root, key, 0); } + + //! \brief find... + bool search(uint32_t key) const + { + return searchRecursive(root, key, 0); + } + + private: + //! \brief ... + void insertRecursive(std::unique_ptr> & node, + uint32_t key, uint32_t depth) + { + if (!node) + { + node = std::make_unique>(); + } + + if (depth == MAX_DEPTH) + { + node->isEndOfWord = true; + return; + } + + uint32_t index = (key >> (BIT_WIDTH * (MAX_DEPTH - depth - 1))) + & ((1 << BIT_WIDTH) - 1); + insertRecursive(node->children[index], key, depth + 1); + } + + //! \brief ... + bool + searchRecursive(const std::unique_ptr> & node, + uint32_t key, uint32_t depth) const + { + if (!node) + { + return false; + } + if (depth == MAX_DEPTH) + { + return node->isEndOfWord; + } + uint32_t index = (key >> (BIT_WIDTH * (MAX_DEPTH - depth - 1))) + & ((1 << BIT_WIDTH) - 1); + return searchRecursive(node->children[index], key, depth + 1); + } + + //! \brief top of the trie + std::unique_ptr> root; + + //! \brief keep a limit on depth based on the template parameter + static constexpr uint32_t MAX_DEPTH = + std::numeric_limits::digits / BIT_WIDTH; +}; diff --git a/fsl/fsl_api/uArchInfo.h b/fsl/fsl_api/uArchInfo.h new file mode 100644 index 00000000..adf4518f --- /dev/null +++ b/fsl/fsl_api/uArchInfo.h @@ -0,0 +1,191 @@ +// +// Created by David Murrell on 12/2/19. +// +#pragma once +#include "json.hpp" +#include "fsl_api/uArchInfoExceptions.h" +#include "mavis/DecoderExceptions.h" +#include "mavis/DecoderTypes.h" + +#include +#include +#include +#include + +/** + * uArchInfo: encapsulates "static" u-arch specific information + */ +class uArchInfo { +public: + typedef std::shared_ptr PtrType; + + // TODO: flesh this out + enum class UnitSet : uint64_t { + AGU = 1ull << 0, + INT = 1ull << 1, + FLOAT = 1ull << 2, + MULTIPLY = 1ull << 3, + DIVIDE = 1ull << 4, + BRANCH = 1ull << 5, + LOAD = 1ull << 6, + STORE = 1ull << 7, + SYSTEM = 1ull << 8, + VECTOR = 1ull << 9, + }; + + // BEGIN: Stuff imported from the old StaticInstructionData object + enum RegFile { INTEGER, FLOAT, INVALID, N_REGFILES = INVALID }; + + static inline const char *const regfile_names[] = {"integer", "float"}; + + // TODO: resolve this against the UnitSet + enum IssueTarget : std::uint16_t { + IEX, + FEX, + BR, + LSU, + ROB, // Instructions that go right to retire + N_ISSUE_TARGETS + }; + + static constexpr uint32_t MAX_ARCH_REGS = 5; + // END: Stuff imported from the old StaticInstructionData object + +private: + // Map unit names to unit ID's + static inline std::map umap_ = { + {"agu", UnitSet::AGU}, {"int", UnitSet::INT}, + {"float", UnitSet::FLOAT}, {"mul", UnitSet::MULTIPLY}, + {"div", UnitSet::DIVIDE}, {"branch", UnitSet::BRANCH}, + {"load", UnitSet::LOAD}, {"store", UnitSet::STORE}, + {"system", UnitSet::SYSTEM}, {"vector", UnitSet::VECTOR}, + }; + + // TEMPORARY: map unit names to TargetUnit for back-level compatibility + static inline std::map issue_target_map_ = { + {"int", IssueTarget::IEX}, {"float", IssueTarget::FEX}, + {"branch", IssueTarget::BR}, {"load", IssueTarget::LSU}, + {"store", IssueTarget::LSU}, {"system", IssueTarget::ROB}, // TEMPORARY! + {"vector", IssueTarget::FEX}, // TEMPORARY! + {"rob", IssueTarget::ROB}, // TEMPORARY! + }; + +public: + /** + * \brief This object encapsulates all the micro-architectural information + * that depends on the instruction type. It is "static" and cached by Mavis in + * the instruction factories. Mavis will pass the nlohmann::json object to + * this constructor so that the user can parse any of the desired fields from + * the u-arch JSON file supplied to Mavis \param jobj nlohmann::json object + * for the given instruction + */ + explicit uArchInfo(const nlohmann::json &jobj) { parse_(jobj); } + + uArchInfo() = default; + uArchInfo(const uArchInfo &) = delete; + + void update(const nlohmann::json &jobj) { + // TODO: identical to constructor(jobj) for now, but we may want to provide + // update restrictions + parse_(jobj); + } + + bool isUnit(UnitSet u) const { + return (static_cast(u) & units_) != 0; + } + + IssueTarget getIssueTarget() const { return issue_target_; } + + uint32_t getLatency() const { return latency_; } + + bool isPipelined() const { return pipelined_; } + + bool isSerialized() const { return serialize_; } + + bool isROBGrpStart() const { return rob_grp_start_; } + + bool isROBGrpEnd() const { return rob_grp_end_; } + +private: + uint64_t units_ = 0; ///< Bit mask of target execution units (from UnitSet) + IssueTarget issue_target_ = IssueTarget::N_ISSUE_TARGETS; ///< Issue target + uint32_t latency_ = 0; ///< Execution latency + bool pipelined_ = true; ///< Pipelined execution (non-blocking)? + bool serialize_ = false; ///< Serializes execution? + bool rob_grp_start_ = false; ///< Starts a new ROB group? + bool rob_grp_end_ = false; ///< Ends a ROB group? + +private: + friend std::ostream &operator<<(std::ostream &os, const uArchInfo &ui); + void print(std::ostream &os) const { + os << "{units: 0x" << std::hex << units_ << ", lat: " << std::dec + << latency_ << ", piped: " << pipelined_ << ", serialize: " << serialize_ + << ", ROB group begin: " << rob_grp_start_ + << ", ROB group end: " << rob_grp_end_ << "}"; + } + + /** + * \brief Parse the JSON file + * \param jobj + */ + void parse_(const nlohmann::json &jobj) { + // Issue target (from IssueTarget) + if (jobj.find("issue") != jobj.end()) { + const auto itr = issue_target_map_.find(jobj["issue"]); + if (itr == issue_target_map_.end()) { + throw uArchInfoUnknownIssueTarget(jobj["mnemonic"], jobj["issue"]); + } + issue_target_ = itr->second; + } + + // Target execution unit (from UnitSet) -- bit mask allows multiple targets + if (jobj.find("unit") != jobj.end()) { + mavis::UnitNameListType ulist = + jobj["unit"].get(); + for (const auto &u : ulist) { + const auto itr = umap_.find(u); + if (itr == umap_.end()) { + throw uArchInfoUnknownUnit(jobj["mnemonic"], u); + } + units_ |= static_cast(itr->second); + } + } + + // Instruction latency + if (jobj.find("latency") != jobj.end()) { + latency_ = jobj["latency"]; + } + + // Whether the instruction is piplined (non-blocking) + if (jobj.find("pipelined") != jobj.end()) { + pipelined_ = jobj["pipelined"]; + } + + // Whether the instruction serializes execution + if (jobj.find("serialize") != jobj.end()) { + serialize_ = jobj["serialize"]; + } + + // Whether the instruction starts a new ROB group + if (jobj.find("rob_group") != jobj.end()) { + mavis::StringListType slist = + jobj["rob_group"].get(); + for (const auto &str : slist) { + if (str == "begin") { + rob_grp_start_ = true; + } else if (str == "end") { + rob_grp_end_ = true; + } else { + throw uArchInfoROBGroupParseError(jobj["mnemonic"], str); + } + } + } + + std::cout << "uArchInfo: " << jobj["mnemonic"] << std::endl; + } +}; + +inline std::ostream &operator<<(std::ostream &os, const uArchInfo &ui) { + ui.print(os); + return os; +} diff --git a/fsl/fsl_api/uArchInfoExceptions.h b/fsl/fsl_api/uArchInfoExceptions.h new file mode 100644 index 00000000..625f33c5 --- /dev/null +++ b/fsl/fsl_api/uArchInfoExceptions.h @@ -0,0 +1,89 @@ +// +// Created by David Murrell on 2/19/20. +// +#pragma once + +#include +#include +#include + +/** + * Decoder exceptions base class + */ +class uArchInfoBaseException : public std::exception +{ + public: + virtual const char* what() const noexcept { return why_.c_str(); } + + protected: + std::string why_; +}; + +/** + * uArchInfo parse error: the given unit for the instruction was not found by + * the uArchInfo object. + * + * This can happen from a mis-spelling of the unit in the JSON, or from a need + * to update the uArchInfo's list of supported units + */ +class uArchInfoUnknownUnit : public uArchInfoBaseException +{ + public: + uArchInfoUnknownUnit(const std::string & mnemonic, const std::string & unit_name) : + uArchInfoBaseException() + { + std::stringstream ss; + ss << "Instruction '" << mnemonic << "': " + << " unit '" << unit_name << "' " + << "is not known (uArchInfo object). Could be a mis-spelling in the " + "JSON file"; + why_ = ss.str(); + } +}; + +/** + * uArchInfo parse error: the given issue target for the instruction was not + * found by the uArchInfo object. + * + * This can happen from a mis-spelling of the issue target in the JSON, or from + * a need to update the uArchInfo's list of supported units + */ +class uArchInfoUnknownIssueTarget : public uArchInfoBaseException +{ + public: + uArchInfoUnknownIssueTarget(const std::string & mnemonic, const std::string & target_name) : + uArchInfoBaseException() + { + std::stringstream ss; + ss << "Instruction '" << mnemonic << "': " + << " issue target '" << target_name << "' " + << "is not known (uArchInfo object). Could be a mis-spelling in the " + "JSON file"; + why_ = ss.str(); + } +}; + +/** + * uArchInfo parsing error: the given ROB group begin/end stanza in the JSON is + * malformed + * + * This can happen from a mis-spelling of the rob_group key in the JSON. The + * form should be one of the following: + * + * "rob_group" : ["begin"] + * "rob_group" : ["end"] + * "rob_group" : ["begin", "end"] + */ +class uArchInfoROBGroupParseError : public uArchInfoBaseException +{ + public: + uArchInfoROBGroupParseError(const std::string & mnemonic, const std::string & bad_string) : + uArchInfoBaseException() + { + std::stringstream ss; + ss << "Instruction '" << mnemonic << "': " + << " rob_group element '" << bad_string << "'" + << " is not valid. Needs to be one of 'begin' or 'end'"; + why_ = ss.str(); + } +}; diff --git a/fsl/fsl_interp/CMakeLists.txt b/fsl/fsl_interp/CMakeLists.txt new file mode 100644 index 00000000..5a8217da --- /dev/null +++ b/fsl/fsl_interp/CMakeLists.txt @@ -0,0 +1,179 @@ +cmake_minimum_required(VERSION 3.10) + +# Project name +project(fsl_interp) + +# Set output directories +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +# Include directories +include_directories(inc ${CMAKE_CURRENT_BINARY_DIR}) + +# Find Boost +find_package(Boost REQUIRED COMPONENTS program_options) +include_directories(${Boost_INCLUDE_DIRS}) + +# Bison and Flex files +set(BISON_SRC src/fsl.y) +set(FLEX_SRC src/fsl.l) +set(BISON_OUT ${CMAKE_CURRENT_BINARY_DIR}/yy.tab.cpp) +set(BISON_H ${CMAKE_CURRENT_BINARY_DIR}/yy.tab.hpp) +set(FLEX_OUT ${CMAKE_CURRENT_BINARY_DIR}/lex.yy.cpp) + +# Bison and Flex targets +find_package(BISON REQUIRED) +find_package(FLEX REQUIRED) + +BISON_TARGET(Parser ${BISON_SRC} ${BISON_OUT} DEFINES_FILE ${BISON_H}) +FLEX_TARGET(Lexer ${FLEX_SRC} ${FLEX_OUT}) +ADD_FLEX_BISON_DEPENDENCY(Lexer Parser) + +# Source files +file(GLOB ALL_SRC "src/*.cpp") +list(REMOVE_ITEM ALL_SRC ${BISON_SRC} ${FLEX_SRC}) # Exclude .l and .y from source list + +# Library target +add_library(fslinterp STATIC ${ALL_SRC} ${BISON_OUT} ${FLEX_OUT}) + +# Set the output name for the library +set_target_properties(fslinterp PROPERTIES OUTPUT_NAME "fsl_interp") + +# Executable target +add_executable(fsl_interp ${ALL_SRC} ${BISON_OUT} ${FLEX_OUT}) +target_link_libraries(fsl_interp fslinterp ${Boost_LIBRARIES}) + +# Custom target for cleaning +add_custom_target(clean-all + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/bin + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/lib + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/CMakeFiles + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/CMakeCache.txt + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/Makefile + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/cmake_install.cmake + COMMENT "Cleaning all generated files" +) + +# Add dependencies for the executable +add_dependencies(fsl_interp fslinterp) + + +#cmake_minimum_required(VERSION 3.10) +# +## Project name +#project(fsl_interp) +# +## Set output directories +#set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +#set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +# +## Include directories +#include_directories(inc ${CMAKE_CURRENT_BINARY_DIR}) +# +## Find Boost +#find_package(Boost REQUIRED COMPONENTS program_options) +#include_directories(${Boost_INCLUDE_DIRS}) +# +## Bison and Flex files +#set(BISON_SRC src/fsl.y) +#set(FLEX_SRC src/fsl.l) +#set(BISON_OUT ${CMAKE_CURRENT_BINARY_DIR}/yy.tab.cpp) +#set(BISON_H ${CMAKE_CURRENT_BINARY_DIR}/yy.tab.hpp) +#set(FLEX_OUT ${CMAKE_CURRENT_BINARY_DIR}/lex.yy.cpp) +# +## Bison and Flex targets +#find_package(BISON REQUIRED) +#find_package(FLEX REQUIRED) +# +#BISON_TARGET(Parser ${BISON_SRC} ${BISON_OUT} DEFINES_FILE ${BISON_H}) +#FLEX_TARGET(Lexer ${FLEX_SRC} ${FLEX_OUT}) +#ADD_FLEX_BISON_DEPENDENCY(Lexer Parser) +# +## Source files +#file(GLOB ALL_SRC "src/*.cpp") +#list(REMOVE_ITEM ALL_SRC ${BISON_SRC} ${FLEX_SRC}) # Exclude .l and .y from source list +# +## Library target +#add_library(fslinterp STATIC ${ALL_SRC} ${BISON_OUT} ${FLEX_OUT}) +# +## Set the output name for the library +#set_target_properties(fslinterp PROPERTIES OUTPUT_NAME "fsl_interp") +# +## Executable target +#add_executable(fslinterp_exe ${ALL_SRC} ${BISON_OUT} ${FLEX_OUT}) +#target_link_libraries(fslinterp_exe fslinterp ${Boost_LIBRARIES}) +# +## Custom target for cleaning +#add_custom_target(clean-all +# COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/bin +# COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/lib +# COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/CMakeFiles +# COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/CMakeCache.txt +# COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/Makefile +# COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/cmake_install.cmake +# COMMENT "Cleaning all generated files" +#) +# +## Add dependencies for the executable +#add_dependencies(fslinterp_exe fslinterp) +# +# +##cmake_minimum_required(VERSION 3.10) +## +### Project name +##project(fsl_interp) +## +### Set output directories +##set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +##set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +##set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +## +### Include directories +##include_directories(inc ${CMAKE_CURRENT_BINARY_DIR}) +## +### Find Boost +##find_package(Boost REQUIRED COMPONENTS program_options) +##include_directories(${Boost_INCLUDE_DIRS}) +## +### Bison and Flex files +##set(BISON_SRC src/fsl.y) +##set(FLEX_SRC src/fsl.l) +##set(BISON_OUT ${CMAKE_CURRENT_BINARY_DIR}/yy.tab.cpp) +##set(BISON_H ${CMAKE_CURRENT_BINARY_DIR}/yy.tab.hpp) +##set(FLEX_OUT ${CMAKE_CURRENT_BINARY_DIR}/lex.yy.cpp) +## +### Bison and Flex targets +##find_package(BISON REQUIRED) +##find_package(FLEX REQUIRED) +## +##BISON_TARGET(Parser ${BISON_SRC} ${BISON_OUT} DEFINES_FILE ${BISON_H}) +##FLEX_TARGET(Lexer ${FLEX_SRC} ${FLEX_OUT}) +##ADD_FLEX_BISON_DEPENDENCY(Lexer Parser) +## +### Source files +##file(GLOB ALL_SRC "src/*.cpp") +##list(REMOVE_ITEM ALL_SRC ${BISON_SRC} ${FLEX_SRC}) # Exclude .l and .y from source list +## +### Library target +##add_library(fslinterp STATIC ${ALL_SRC} ${BISON_OUT} ${FLEX_OUT}) +## +### Executable target +##add_executable(fslinterp_exe ${ALL_SRC} ${BISON_OUT} ${FLEX_OUT}) +##target_link_libraries(fslinterp_exe fslinterp ${Boost_LIBRARIES}) +## +### Custom target for cleaning +##add_custom_target(clean-all +## COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/bin +## COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/lib +## COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/CMakeFiles +## COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/CMakeCache.txt +## COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/Makefile +## COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/cmake_install.cmake +## COMMENT "Cleaning all generated files" +##) +## +### Add dependencies for the executable +##add_dependencies(fslinterp_exe fslinterp) +## diff --git a/fsl/fsl_interp/Makefile.sav b/fsl/fsl_interp/Makefile.sav new file mode 100644 index 00000000..f7acdbbb --- /dev/null +++ b/fsl/fsl_interp/Makefile.sav @@ -0,0 +1,78 @@ +.PHONY: clean default lib_only interp_only + +include ../Vars.mk + +ALL_SRC = $(wildcard src/*.cpp) +SRC_OBJ = $(subst src,obj,$(ALL_SRC:.cpp=.o)) +LIB_OBJ = obj/FslParser.o obj/lex.yy.o obj/Options.o obj/yy.tab.o + +# Files +BISON_SRC = src/fsl.y +FLEX_SRC = src/fsl.l +BISON_OUT = obj/yy.tab.cpp +BISON_H = obj/yy.tab.hpp +FLEX_OUT = obj/lex.yy.cpp +INTERP_TARGET = bin/fslinterp +LIB_TARGET = lib/libfslinterp.a + +PARSE_OBJ = $(BISON_OUT:.cpp=.o) $(FLEX_OUT:.cpp=.o) + +ALL_OBJ = $(SRC_OBJ) $(PARSE_OBJ) + +INC = -I./inc -I./obj $(BOOST_INC) +LIBS = $(BOOST_LIB) -lboost_program_options + +INP_FILES = -i syntax_tests/_1_syntax_test.fsl \ + -i syntax_tests/_2_syntax_test.fsl \ + -i syntax_tests/sample1.fsl + +OUT_FILE = -o output.txt + +CFLAGS = $(INC) +LDFLAGS = + +default: lib_only interp_only +only: lib_only interp_only + +lib_only: $(LIB_TARGET) +interp_only: $(INTERP_TARGET) + +$(INTERP_TARGET): $(ALL_OBJ) + @mkdir -p bin + $(CXX) $(LDFLAGS) $^ -o $@ $(LIBS) + +$(LIB_TARGET): $(LIB_OBJ) + @mkdir -p lib + ar rcs $(LIB_TARGET) $^ + +obj/%.o : src/%.cpp + $(CXX) -c $(CFLAGS) $< -o $@ + +obj/yy.tab.o: $(BISON_OUT) + $(CXX) -c $(CFLAGS) $< -o $@ + +obj/lex.yy.o: $(FLEX_OUT) + $(CXX) -c $(CFLAGS) $< -o $@ + +# Bison build rule, generating both .c and .h files +$(BISON_OUT) $(BISON_H): $(BISON_SRC) + @mkdir -p obj + $(BISON) $(BISONFLAGS) $(BISON_SRC) -o $(BISON_OUT) + +# Flex build rule, depends on Bison header +$(FLEX_OUT): $(FLEX_SRC) $(BISON_H) + @mkdir -p obj + $(FLEX) -o $(FLEX_OUT) $(FLEX_SRC) + +##TRACE=--trace_en +#run: $(TARGET) +# $(TARGET) --verbose $(INP_FILES) $(OUT_FILE) $(TRACE) + +help-%: + @echo $* = $($*) + +# Clean build files +clean: + rm -f ./bin/* ./obj/* + + diff --git a/fsl/fsl_interp/fsl.l b/fsl/fsl_interp/fsl.l new file mode 100644 index 00000000..a5744b1d --- /dev/null +++ b/fsl/fsl_interp/fsl.l @@ -0,0 +1,290 @@ +%{ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file Fsl.l flex scanner for FSL +// ---------------------------------------------------------------- +// Simple lexer derived from the original QParser +// Future: complete wrapping into FP, location info, api variants +// ---------------------------------------------------------------- +#include +#include +#include +#include +#include "fslparser.h" +#include "yy.tab.hpp" +using namespace std; + +extern FslParser *FP; + +extern void comment(void); +extern int check_type(void); +extern void count(void); +int column = 0; +// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +#define YY_DECL extern int yylex() +#define E(s) if(FP->TRACE_EN) cout<lineNo<<": "<{ + "*/" { BEGIN(INITIAL); } + [^*\n]+ { /* Ignore non-newline and non-asterisk characters */ } + "*" { /* Ignore standalone asterisk characters */ } + "\n" { E("C") ++FP->lineNo; } +} + +\/\/[^\n]* { E("COMMENT") } + +"sequence" { BEGIN(SEQUENCE); } +{ + "}" { BEGIN(INITIAL); } + [^}\n]+ { /* Ignore non-newline/non-brace characters */ } + "\n" { E("SEQ") ++FP->lineNo; } +} + +_fail_ { CAPT(FAIL); } +_pass_ { CAPT(PASS); } +constraints { CAPT(CONSTRAINTS); } +conversion { CAPT(CONVERSION); } +csr { CAPT(CSR); } +dst { CAPT(DST); } +emit { CAPT(EMIT); } +encode_order { CAPT(ENCODE_ORDER); } +encoding { CAPT(ENCODING); } +false { CAPT(FALSE); } +fusion { CAPT(FUSION); } +gpr { CAPT(GPR); } +if { CAPT(IF); } +instr { CAPT(INSTR); } +ioput { CAPT(IOPUT); } +isa { CAPT(ISA); } +mnemonic { CAPT(MNEMONIC); } +morph { CAPT(MORPH); } +opc { CAPT(OPC); } +prolog { CAPT(PROLOG); } +rdx { CAPT(RDX); } +replace { CAPT(REPLACE); } +rsx { CAPT(RSX); } +s0 { CAPT(S0); } +s1 { CAPT(S1); } +transform { CAPT(TRANSFORM); } +true { CAPT(TRUE); } +type { CAPT(TYPE); } +uarch { CAPT(UARCH); } + +_req_ { /* get a unique ID for _req_ symbols and add to symtab */ + std::string symName = FP->newReqSymbol(); + FslSymbol sym(symName,FP->lineNo,FP->currentFile,"REQ_TYPE"); + FP->insertSymbol(symName,sym); + CAPT(REQ_TOKEN); + } + +_opt_ { /* get a unique ID for _opt_ symbols and add to symtab */ + std::string symName = FP->newOptSymbol(); + FslSymbol sym(symName,FP->lineNo,FP->currentFile,"OPT_TYPE"); + FP->insertSymbol(symName,sym); + CAPT(OPT_TOKEN); + } + +"_Bool" { CAPT(BOOL); } +"break" { CAPT(BREAK); } +"case" { CAPT(CASE); } +"char" { CAPT(CHAR); } +"_Complex" { CAPT(COMPLEX); } +"const" { CAPT(CONST); } +"continue" { CAPT(CONTINUE); } +"default" { CAPT(DEFAULT); } +"do" { CAPT(DO); } +"double" { CAPT(DOUBLE); } +"else" { CAPT(ELSE); } +"enum" { CAPT(ENUM); } +"extern" { CAPT(EXTERN); } +"float" { CAPT(FLOAT); } +"for" { CAPT(FOR); } +"goto" { CAPT(GOTO); } +"_Imaginary" { CAPT(IMAGINARY); } +"imm" { CAPT(IMM); } +"inline" { CAPT(INLINE); } +"int" { CAPT(INT); } +"long" { CAPT(LONG); } +"register" { CAPT(REGISTER); } +"restrict" { CAPT(RESTRICT); } +"short" { CAPT(SHORT); } +"signed" { CAPT(SIGNED); } +"sizeof" { CAPT(SIZEOF); } +"src" { CAPT(SRC); } +"static" { CAPT(STATIC); } +"struct" { CAPT(STRUCT); } +"switch" { CAPT(SWITCH); } +"typedef" { CAPT(TYPEDEF); } +"union" { CAPT(UNION); } +"unsigned" { CAPT(UNSIGNED); } +"void" { CAPT(VOID); } +"volatile" { CAPT(VOLATILE); } +"while" { CAPT(WHILE); } + +{UNSIGNED_CONST} { count(); GET_STR; CAPT(UN_CONST); } +{SIGNED_CONST} { count(); GET_STR; CAPT(S_CONST); } +{HEX_CONST} { CAPT(HEX_CONST); } +{VLOG_BIN} { CAPT(VLOG_CONST); } +{VLOG_OCT} { CAPT(VLOG_CONST); } +{VLOG_DEC} { CAPT(VLOG_CONST); } +{VLOG_HEX} { CAPT(VLOG_CONST); } + +\"([^"\\]|\\(.|\n))*\" { yylval.sval = strdup(yytext); RET(QSTRING); } + +{L}({L}|{D})* { count(); return(check_type()); } +0[xX]{H}+{IS}? { count(); return(CONSTANT); } +0[0-7]*{IS}? { count(); return(CONSTANT); } +[1-9]{D}*{IS}? { count(); return(CONSTANT); } +L?'(\\.|[^\\'\n])+' { count(); return(CONSTANT); } + +{D}+{E}{FS}? { count(); return(CONSTANT); } +{D}*"."{D}+{E}?{FS}? { count(); return(CONSTANT); } +{D}+"."{D}*{E}?{FS}? { count(); return(CONSTANT); } +0[xX]{H}+{P}{FS}? { count(); return(CONSTANT); } +0[xX]{H}*"."{H}+{P}?{FS}? { count(); return(CONSTANT); } +0[xX]{H}+"."{H}*{P}?{FS}? { count(); return(CONSTANT); } + + +L?\"(\\.|[^\\"\n])*\" { count(); return(STRING_LITERAL); } + +"..." { count(); return(ELLIPSIS); } +">>=" { count(); return(RIGHT_ASSIGN); } +"<<=" { count(); return(LEFT_ASSIGN); } +"+=" { count(); return(ADD_ASSIGN); } +"-=" { count(); return(SUB_ASSIGN); } +"*=" { count(); return(MUL_ASSIGN); } +"/=" { count(); return(DIV_ASSIGN); } +"%=" { count(); return(MOD_ASSIGN); } +"&=" { count(); return(AND_ASSIGN); } +"^=" { count(); return(XOR_ASSIGN); } +"|=" { count(); return(OR_ASSIGN); } +">>" { count(); return(RIGHT_OP); } +"<<" { count(); return(LEFT_OP); } +"++" { count(); return(INC_OP); } +"--" { count(); return(DEC_OP); } +"->" { count(); return(PTR_OP); } +"&&" { count(); return(AND_OP); } +"||" { count(); return(OR_OP); } +"<=" { count(); return(LE_OP); } +">=" { count(); return(GE_OP); } +"==" { count(); return(EQ_OP); } +"!=" { count(); return(NE_OP); } +";" { count(); return(';'); } +("{"|"<%") { count(); return('{'); } +("}"|"%>") { count(); return('}'); } +"," { count(); return(','); } +":" { count(); return(':'); } +"=" { count(); return('='); } +"(" { count(); return('('); } +")" { count(); return(')'); } +("["|"<:") { count(); return('['); } +("]"|":>") { count(); return(']'); } +"." { E(".") count(); return('.'); } +"&" { count(); return('&'); } +"!" { count(); return('!'); } +"~" { count(); return('~'); } +"-" { count(); return('-'); } +"+" { count(); return('+'); } +"*" { count(); return('*'); } +"/" { count(); return('/'); } +"%" { count(); return('%'); } +"<" { count(); return('<'); } +">" { count(); return('>'); } +"^" { count(); return('^'); } +"|" { count(); return('|'); } +"?" { count(); return('?'); } + +[\n] { FP->lineNo += 1; count(); } +[ \t] { /* */ } +. { E(yytext[0]) RET(yytext[0]); } + +%% + +//Future pragma support +void comment(void) { } +//void comment(void) +//{ +// char c, prev = 0; +// +// while ((c = input()) != 0) /* (EOF maps to 0) */ +// { +// if (c == '/' && prev == '*') +// return; +// prev = c; +// } +// yyerror("unterminated comment"); +//} + +void count(void) +{ +// int i; + +// for (i = 0; yytext[i] != '\0'; i++) +// if (yytext[i] == '\n') +// column = 0; +// else if (yytext[i] == '\t') +// column += 8 - (column % 8); +// else +// column++; +// ECHO; +} + + +int check_type(void) +{ +/* +* pseudo code --- this is what it should check +* +* if (yytext == type_name) +* return TYPE_NAME; +* +* return ID; +*/ + +/* +* it actually will only return ID +*/ + E(yytext) + return ID; +} +// ------------------------------------------------------------------ +// ------------------------------------------------------------------ +void yyerror(const char *s) { + std::cout << "-E: "<currentFile<<": " + << s <<" " << yytext <<", line " + <lineNo< +#include +#include +#include +#include +#include +using namespace std; + +extern FslParser *FP; + +extern int column; +extern int yylex(); +extern int yyparse(); +extern FILE *yyin; +extern char *yytext; +extern void yyerror(const char *s); +//std::vector sequence_lines; + +%} + +%union { + int ival; + float fval; + char *sval; + std::string *str; +} + +%token CONSTRAINTS +%token CONVERSION +%token EMIT +%token ENCODE_ORDER +%token ENCODING +%token FAIL +%token FUSION +%token CSR +%token GPR +%token IF +%token INPUT_SEQ +%token INSTR +%token IOPUT +%token ISA +%token MNEMONIC +%token REPLACE +%token REQUIREDBITS +%token OPC +%token SRC +%token DST +%token RSX +%token RDX +%token IMM +%token TYPE +%token MORPH +%token OPT_TOKEN +%token PASS +%token PROLOG +%token REQ_TOKEN +%token RET +%token S0 S1 +%token SEQUENCE +%token TRANSFORM +%token UARCH +%token UN_CONST +%token S_CONST +%token UID +%token TRUE +%token FALSE +%token WRITEPORTS +%token READPORTS + +%token QSTRING ID CONSTANT STRING_LITERAL SIZEOF +%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP +%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN +%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN +%token XOR_ASSIGN OR_ASSIGN TYPE_NAME + +%token TYPEDEF EXTERN STATIC AUTO REGISTER INLINE RESTRICT +%token CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE CONST VOLATILE VOID +%token BOOL COMPLEX IMAGINARY +%token STRUCT UNION ENUM ELLIPSIS + +%token CASE DEFAULT ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN + +%token HEX_CONST +%token VLOG_CONST + +%nonassoc NO_ELSE +%nonassoc ELSE + +%start top + +%% + +top: + source_line + | top source_line + ; + +source_line: + transform_definition + | prolog_definition + | function_definition + | declaration + ; + +transform_definition: + TRANSFORM id '{' '}' + | TRANSFORM id '{' transform_statements '}' + ; + +transform_statements: + transform_statement + | transform_statements transform_statement + ; + +transform_statement: + PROLOG id + | isa_decl + | uarch_decl + | ioput_decl + | variable_decl + | selection_statement + | constraints_definition + | conversion_definition + ; + +prolog_definition: + PROLOG id '{' '}' + | PROLOG id '{' prolog_statements '}' + ; + +prolog_statements: + prolog_statement + | prolog_statements prolog_statement + ; + +prolog_statement: + ISA id + | UARCH id + | IOPUT id + ; + +isa_decl: ISA id ; +uarch_decl: UARCH id ; +ioput_decl: IOPUT id ; + +variable_definition: + variable_type id '=' assignment_expression + | variable_type id '=' '{' concatenate_list '}' + ; + +variable_decl: + variable_type arg_expr_list + | variable_definition + ; + +variable_type: + GPR + | CSR + | UN_CONST + | S_CONST + ; + +constraints_definition: + CONSTRAINTS id '{' constraints_statements '}' + | CONSTRAINTS id '(' arg_expr_list ')' '{' '}' + | CONSTRAINTS id '(' arg_expr_list ')' '{' constraints_statements '}' + ; + +constraints_statements: + constraints_statement + | constraints_statements constraints_statement + ; + +//expr: +// ID +// | expr '.' ID +// | expr '.' WRITEPORTS '(' ')' +// | expr '.' READPORTS '(' ')' +// | expr LE_OP expr +// | expr GE_OP expr +// ; + +constraints_statement: + pass_fail_statement + | chained_id_list comparison_operator chained_id_list + | chained_id_list comparison_operator constant + | chained_id_list comparison_operator chained_id_list LEFT_OP constant + | chained_id_list '.' known_method '(' ')' comparison_operator + chained_id_list '.' known_method '(' ')' + | chained_id_list '.' known_method '(' id ')' comparison_operator constant + | selection_statement + ; + +comparison_operator: + LE_OP + | GE_OP + | EQ_OP + | NE_OP + ; + +conversion_definition: + CONVERSION '{' conversion_statements '}' + | CONVERSION id '{' conversion_statements '}' + | CONVERSION id '(' arg_expr_list ')' '{' '}' + | CONVERSION id '(' arg_expr_list ')' '{' conversion_statements '}' + ; + +conversion_statements: + conversion_statement + | conversion_statements conversion_statement + ; + +conversion_statement: + pass_fail_statement + | variable_decl + | encoding_decl + | encoding_definition + | instr_decl + | instr_definition + | chained_id_list '.' known_method '(' id ')' + | chained_id_list '.' known_method '(' constant ')' + | chained_id_list '.' known_method '(' qstring ')' + | chained_id_list '.' known_method '(' '*' ')' + | chained_id_list '.' known_method '(' '{' concatenate_list '}' ')' + | chained_id_list '.' REPLACE '(' comma_sep_list ')' + ; + +concatenate_list: + concatenate_elem + | concatenate_list ',' concatenate_elem + ; + +concatenate_elem: + id + | select_elem + | OPC + | constant + | known_method '=' constant + ; + +comma_sep_list: + id + | comma_sep_list ',' id + ; + +select_elem: + id '[' constant ']' + ; + +chained_id_list: + id + | chained_id_list '.' id + ; + +known_method: + MNEMONIC + | ENCODE_ORDER + | WRITEPORTS + | READPORTS + | REQUIREDBITS + | ENCODING + | OPC + | SRC + | DST + | RSX + | IMM + | TYPE + | MORPH + ; + +instr_decl: + INSTR id + ; + +instr_definition: + INSTR id '(' arg_assignment_list ')' + | INSTR id '(' '{' concatenate_list '}' ')' + | INSTR id '(' '{' encode_list '}' ')' + | INSTR id '(' known_method '(' id ')' ')' + ; + +encode_list: + encode_elem + | encode_list ',' encode_elem + ; + +encode_elem: + id '[' constant ']' '.' ENCODING + ; + +encoding_decl: + ENCODING id + ; + +encoding_definition: + ENCODING id '(' arg_assignment_list ')' + ; + +arg_assignment_list: + arg_assignment + | arg_assignment_list ',' arg_assignment + ; + +arg_assignment: + known_method '=' qstring + | known_method '=' constant + | known_method '=' '{' arg_expr_list '}' + | id '=' '{' arg_expr_list '}' + ; + + +pass_fail_statement: + PASS + | FAIL + ; + +primary_expression + : id + | constant + | STRING_LITERAL + | '(' expression ')' + ; + +postfix_expression + : primary_expression + | postfix_expression '[' expression ']' + | postfix_expression '(' ')' + | postfix_expression '(' arg_expr_list ')' + | postfix_expression '.' id + | postfix_expression PTR_OP id + | postfix_expression INC_OP + | postfix_expression DEC_OP + | postfix_expression '.' ENCODING '(' ')' +// | '(' type_name ')' '{' initializer_list '}' +// | '(' type_name ')' '{' initializer_list ',' '}' + ; + +arg_expr_list: + assignment_expression + | arg_expr_list ',' assignment_expression + ; + +unary_expression + : postfix_expression + | INC_OP unary_expression + | DEC_OP unary_expression + | unary_operator cast_expression + | SIZEOF unary_expression + | SIZEOF '(' type_name ')' + ; + +unary_operator + : '&' + | '*' + | '+' + | '-' + | '~' + | '!' + ; + +cast_expression + : unary_expression + | '(' type_name ')' cast_expression + ; + +multiplicative_expression + : cast_expression + | multiplicative_expression '*' cast_expression + | multiplicative_expression '/' cast_expression + | multiplicative_expression '%' cast_expression + ; + +additive_expression + : multiplicative_expression + | additive_expression '+' multiplicative_expression + | additive_expression '-' multiplicative_expression + ; + +shift_expression + : additive_expression + | shift_expression LEFT_OP additive_expression + | shift_expression RIGHT_OP additive_expression + ; + +relational_expression + : shift_expression + | relational_expression '<' shift_expression + | relational_expression '>' shift_expression + | relational_expression LE_OP shift_expression + | relational_expression GE_OP shift_expression + ; + +equality_expression + : relational_expression + | equality_expression EQ_OP relational_expression + | equality_expression NE_OP relational_expression + ; + +and_expression + : equality_expression + | and_expression '&' equality_expression + ; + +exclusive_or_expression + : and_expression + | exclusive_or_expression '^' and_expression + ; + +inclusive_or_expression + : exclusive_or_expression + | inclusive_or_expression '|' exclusive_or_expression + ; + +logical_and_expression + : inclusive_or_expression + | logical_and_expression AND_OP inclusive_or_expression + ; + +logical_or_expression + : logical_and_expression + | logical_or_expression OR_OP logical_and_expression + ; + +conditional_expression + : logical_or_expression + | logical_or_expression '?' expression ':' conditional_expression + ; + +assignment_expression + : conditional_expression + | unary_expression assignment_operator assignment_expression + ; + +assignment_operator + : '=' + | MUL_ASSIGN + | DIV_ASSIGN + | MOD_ASSIGN + | ADD_ASSIGN + | SUB_ASSIGN + | LEFT_ASSIGN + | RIGHT_ASSIGN + | AND_ASSIGN + | XOR_ASSIGN + | OR_ASSIGN + ; + +expression: + assignment_expression + | expression ',' assignment_expression + ; + +constant_expression + : conditional_expression + ; + +declaration + : declaration_specifiers ';' + | declaration_specifiers init_declarator_list ';' + ; + +declaration_specifiers + : storage_class_specifier + | storage_class_specifier declaration_specifiers + | type_specifier + | type_specifier declaration_specifiers + | type_qualifier + | type_qualifier declaration_specifiers + | function_specifier + | function_specifier declaration_specifiers + ; + +init_declarator_list + : init_declarator + | init_declarator_list ',' init_declarator + ; + +init_declarator + : declarator + | declarator '=' initializer + ; + +storage_class_specifier + : TYPEDEF + | EXTERN + | STATIC + | AUTO + | REGISTER + ; + +type_specifier + : VOID + | CHAR + | SHORT + | INT + | LONG + | FLOAT + | DOUBLE + | SIGNED + | UNSIGNED + | BOOL + | COMPLEX + | IMAGINARY + | struct_or_union_specifier + | enum_specifier + | TYPE_NAME + ; + +struct_or_union_specifier + : struct_or_union id '{' struct_declaration_list '}' + | struct_or_union '{' struct_declaration_list '}' + | struct_or_union id + ; + +struct_or_union + : STRUCT + | UNION + ; + +struct_declaration_list + : struct_declaration + | struct_declaration_list struct_declaration + ; + +struct_declaration + : specifier_qualifier_list struct_declarator_list ';' + ; + +specifier_qualifier_list + : type_specifier specifier_qualifier_list + | type_specifier + | type_qualifier specifier_qualifier_list + | type_qualifier + ; + +struct_declarator_list + : struct_declarator + | struct_declarator_list ',' struct_declarator + ; + +struct_declarator + : declarator + | ':' constant_expression + | declarator ':' constant_expression + ; + +enum_specifier + : ENUM '{' enumerator_list '}' + | ENUM id '{' enumerator_list '}' + | ENUM '{' enumerator_list ',' '}' + | ENUM id '{' enumerator_list ',' '}' + | ENUM id + ; + +enumerator_list + : enumerator + | enumerator_list ',' enumerator + ; + +enumerator + : id + | id '=' constant_expression + ; + +type_qualifier + : CONST + | RESTRICT + | VOLATILE + ; + +function_specifier + : INLINE + ; + +declarator + : pointer direct_declarator + | direct_declarator + ; + +direct_declarator + : id + | '(' declarator ')' + | direct_declarator '[' type_qualifier_list assignment_expression ']' + | direct_declarator '[' type_qualifier_list ']' + | direct_declarator '[' assignment_expression ']' + | direct_declarator '[' STATIC type_qualifier_list assignment_expression ']' + | direct_declarator '[' type_qualifier_list STATIC assignment_expression ']' + | direct_declarator '[' type_qualifier_list '*' ']' + | direct_declarator '[' '*' ']' + | direct_declarator '[' ']' + | direct_declarator '(' parameter_type_list ')' + | direct_declarator '(' identifier_list ')' + | direct_declarator '(' ')' + ; + +pointer + : '*' + | '*' type_qualifier_list + | '*' pointer + | '*' type_qualifier_list pointer + ; + +type_qualifier_list + : type_qualifier + | type_qualifier_list type_qualifier + ; + + +parameter_type_list + : parameter_list + | parameter_list ',' ELLIPSIS + ; + +parameter_list + : parameter_declaration + | parameter_list ',' parameter_declaration + ; + +parameter_declaration + : declaration_specifiers declarator + | declaration_specifiers abstract_declarator + | declaration_specifiers + ; + +identifier_list + : id + | identifier_list ',' id + ; + +type_name + : specifier_qualifier_list + | specifier_qualifier_list abstract_declarator + ; + +abstract_declarator + : pointer + | direct_abstract_declarator + | pointer direct_abstract_declarator + ; + +direct_abstract_declarator + : '(' abstract_declarator ')' + | '[' ']' + | '[' assignment_expression ']' + | direct_abstract_declarator '[' ']' + | direct_abstract_declarator '[' assignment_expression ']' + | '[' '*' ']' + | direct_abstract_declarator '[' '*' ']' + | '(' ')' + | '(' parameter_type_list ')' + | direct_abstract_declarator '(' ')' + | direct_abstract_declarator '(' parameter_type_list ')' + ; + +initializer + : assignment_expression + | '{' initializer_list '}' + | '{' initializer_list ',' '}' + ; + +initializer_list + : initializer + | designation initializer + | initializer_list ',' initializer + | initializer_list ',' designation initializer + ; + +designation + : designator_list '=' + ; + +designator_list + : designator + | designator_list designator + ; + +designator + : '[' constant_expression ']' + | '.' id + ; + +statement: + labeled_statement + | pass_fail_statement + | compound_statement + | expression_statement + | selection_statement + | iteration_statement + | jump_statement + ; + +labeled_statement + : id ':' statement + | CASE constant_expression ':' statement + | DEFAULT ':' statement + ; + +compound_statement + : '{' '}' + | '{' block_item_list '}' + ; + +block_item_list + : block_item + | block_item_list block_item + ; + +block_item + : declaration + | statement + ; + +expression_statement + : ';' + | expression ';' + ; + +selection_statement: + IF '(' expression ')' statement %prec NO_ELSE + | IF '(' expression ')' statement ELSE statement + | SWITCH '(' expression ')' statement + ; + +iteration_statement + : WHILE '(' expression ')' statement + | DO statement WHILE '(' expression ')' ';' + | FOR '(' expression_statement expression_statement ')' statement + | FOR '(' expression_statement expression_statement expression ')' statement + | FOR '(' declaration expression_statement ')' statement + | FOR '(' declaration expression_statement expression ')' statement + ; + +jump_statement + : GOTO id ';' + | CONTINUE ';' + | BREAK ';' + | RETURN ';' + | RETURN expression ';' + ; + +function_definition + : declaration_specifiers declarator declaration_list compound_statement + | declaration_specifiers declarator compound_statement + ; + +declaration_list + : declaration + | declaration_list declaration + ; + +id: + ID + ; + +qstring: + QSTRING + ; + +constant: + CONSTANT + | HEX_CONST + | VLOG_CONST + ; +%% diff --git a/fsl/fsl_interp/inc/FslParser.h b/fsl/fsl_interp/inc/FslParser.h new file mode 100644 index 00000000..3b46e0cc --- /dev/null +++ b/fsl/fsl_interp/inc/FslParser.h @@ -0,0 +1,251 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file FslParser.hpp wrapper around parser state machine(s) +#pragma once +#include +#include +#include +#include +#include +#include + +// ---------------------------------------------------------------- +//! \brief FSL symbol table entry +// ---------------------------------------------------------------- +struct FslSymbol +{ + //! \brief ... + FslSymbol(const std::string _n, + const uint32_t _ln = 0, + const std::string _fn = "", + const std::string _ty = "UNKNOWN") + : name(_n), + lineNo(_ln), + srcFile(_fn), + type(_ty) + { + } + + //! \brief symbol name + std::string name; + + //! \brief line no of decl in source file + uint32_t lineNo; + + //! \brief source file + std::string srcFile; + + //! \brief symbol type + //! + //! FIXME: to be an enum + std::string type; +}; + +// ---------------------------------------------------------------- +//! \brief FSL symbol table type +// ---------------------------------------------------------------- +struct SymbolTable +{ + //! \brief symbol table iterator + using TableItrType = std::unordered_map::iterator; + + //! \brief look up name in table + bool hasSymbol(const std::string name) const + { + if (table.find(name) != table.end()) + return true; + return false; + } + + //! \brief if not already in symtab, insert it + void insertSymbol(const std::string name,const FslSymbol s) + { + if (!hasSymbol(name)) + table.insert(make_pair(name, s)); + } + + //! \brief ... + void setType(const std::string name,const std::string type) + { + TableItrType itr = table.find(name); + if (itr != table.end()) + { + itr->second.type = type; + } + } + + //! \brief ... + void clear() { table.clear(); } + + //! \brief symbol info to stream + //! + //! FIXME: consider using operator<<, handle shortPath arg + void info(std::ostream & os, bool shortPath = false) const; + + //! \brief the symbol table + std::unordered_map table; +}; + +// ---------------------------------------------------------------- +//! \brief FslParser support for flex/bison +//! +// ---------------------------------------------------------------- +struct FslParser +{ + //! \brief ... + FslParser(); + + //! \brief ... + ~FslParser() {} + + //! \brief initialize parser state between code bases + void coldReset() + { + warmReset(); + reqId = 0; + optId = 0; + symtab.clear(); + } + + //! \brief initialize parser state between files + void warmReset() + { + lineNo = 1; + curCol = 1; + currentFile = ""; + errMsg = ""; + } + + //! \brief set the inputFile vector when isInLine + void setInputFiles(const std::vector & fv) + { + inputFiles = fv; + } + + //! \brief parse all input files + //! + //! not const, eventually currentFile is modified + bool parse() + { + return parseFiles(); + } + + //! \brief parse all input files + //! + //! not const, eventually currentFile is modified + bool parseFiles(); + + //! \brief parse one file + //! + //! not const, currentFile is modified + bool parse(const std::string&); + + //! \brief remove the Msg dependency for FslParser + void emsg(const std::string m) const + { + std::cout << "-E:QP: " << m << std::endl; + } + + // -------------------------------------------------------------- + // Symbol table shim + // -------------------------------------------------------------- + //! \brief look up string in symbol table + bool hasSymbol(const std::string name) const + { + return symtab.hasSymbol(name); + } + + //! \brief look up const/char in symbol table + bool hasSymbol(const char* name) const + { + return symtab.hasSymbol(std::string(name)); + } + + //! \brief insert string symbol name into table if not duplicated + void insertSymbol(const std::string sym, FslSymbol s) + { + symtab.insertSymbol(sym, s); + } + + //! \brief insert const/char symbol name into table if not duplicated + void insertSymbol(const char* sym, FslSymbol s) + { + symtab.insertSymbol(std::string(sym), s); + } + + //! \brief set type field of symbol using string name + void setSymType(const std::string sym, std::string typ) + { + symtab.setType(sym, typ); + } + + //! \brief set type field of symbol using const/char name + void setSymType(const char* sym, std::string typ) + { + symtab.setType(std::string(sym), typ); + } + + //! \brief create a unique string id for a _req_ symbol + //! + //! _reg + string(reqId++) + std::string newReqSymbol() + { + return std::string("_req" + std::to_string(reqId++)); + } + + //! \brief create a unique id for a _opt_ symbol + //! + //! _opt + string(optId++) + std::string newOptSymbol() + { + return std::string("_opt" + std::to_string(optId++)); + } + + // -------------------------------------------------------------- + // utils + // -------------------------------------------------------------- + + //! \brief single quote helper function + std::string tq(std::string s) { return "'"+s+"'"; } + + // -------------------------------------------------------------- + // parser controls + // -------------------------------------------------------------- + + //! \brief verbose lexer console output + uint32_t TRACE_EN{false}; + + //! \brief lineNo of current file + uint32_t lineNo{1}; + + //! \brief current column location + //! + //! Future feature - locations in yyerror reports + uint32_t curCol{1}; + + //! \brief file being parsed + std::string currentFile{""}; + + //! \brief default syntax name is always fsl in this version + std::string syntaxName{"fsl"}; + + //! \brief last error + std::string errMsg{""}; + + //! \brief unique ID counter for _req_ objects + uint32_t reqId{0}; + + //! \brief unique ID counter for _opt_ objects + uint32_t optId{0}; + + //! \brief list of files + //! + //! This is the only case so far where this could be a fusion + //! type as in FileNameListType. Standard FslParser does not know + //! about those types of course. + std::vector inputFiles; + + //! \brief FSL symbol table + SymbolTable symtab; +}; diff --git a/fsl/fsl_interp/inc/Msg.h b/fsl/fsl_interp/inc/Msg.h new file mode 100644 index 00000000..55f548e3 --- /dev/null +++ b/fsl/fsl_interp/inc/Msg.h @@ -0,0 +1,130 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file Msg.hpp header for simple uniform messages +#pragma once +#include +#include +#include +#include + +//! \brief singleton for standardized messages +//! +//! I use this to standardize local output. +//! +//! I'm using an ad hoc test bench, a compliant testbench +//! would be part of a fusion capable Sparta unit. In that +//! case this would be replaced with the mechanism found +//! in the unit benches. +struct Msg +{ + //! \brief get the singleton instance + static Msg* getInstance() + { + if (instance == nullptr) + { + instance = new Msg; + } + return instance; + } + + ~Msg() = default; + + //! \brief this adds an identifier prefix to messages + //! + //! Example -I:MYUNIT: {message} + void setWho(const std::string & _w) { w = _w + ": "; } + + //! \brief shared message method + void mmsg(const std::string &p, const std::string &m) const //NOLINT + { std::cout << p << w << m << std::endl; } + + //! \brief debug messages + void dmsg(std::string m = "", int v = 4) const //NOLINT + { if (v <= verbose) { mmsg("-D: ", m); } } + + //! \brief error messages + void emsg(std::string m = "", int v = 1) const //NOLINT + { if (v <= verbose) { mmsg("-E: ", m); } } + + //! \brief info messages + void imsg(std::string m = "", int v = 3) const //NOLINT + { if (v <= verbose) { mmsg("-I: ", m); } } + + //! \brief warining messages + void wmsg(std::string m = "", int v = 2) const //NOLINT + { if (v <= verbose) { mmsg("-W: ", m); } } + + //! \brief warining messages + void mmsg(std::ostream & o, std::string p, std::string m) const //NOLINT + { o << p << w << m << std::endl; } + + // ---------------------------------------------------------------- + //! \brief dmsg should be v level 4 + void dmsg(std::ostream & o, std::string m = "", int v = 4) const //NOLINT + { mmsg(o, "-D: ", std::move(m)); } + + //! \brief ... + void emsg(std::ostream & o, std::string m = "", int v = 1) const //NOLINT + { mmsg(o, "-E: ", std::move(m)); } + + //! \brief ... + void imsg(std::ostream & o, std::string m = "", int v = 3) const //NOLINT + { mmsg(o, "-I: ", std::move(m)); } + + //! \brief ... + void wmsg(std::ostream & o, std::string m = "", int v = 2) const //NOLINT + { mmsg(o, "-W: ", std::move(m)); } + + //! \brief ... + void msg(std::string m) const { std::cout << m << std::endl; } //NOLINT + + // ---------------------------------------------------------------- + //! \brief helper to show potentially empty strings + std::string tq(std::string s) const { return "'" + s + "'"; } //NOLINT + + //! \brief ... + std::string w; //NOLINT + /** + * \brief verbosity setting + * + * \verbatim + * verbose 0 - silent + * 1 - errors + * 2 - errors,warnings + * 3 - errors,warnings,info + * >= 4 - errors,warnings,info,debug4 + * - debug messages can be a various levels, debugN + * \endverbatim + */ + + //! \brief ... + int verbose{3}; + + //! \brief ... + static Msg* instance; + + private: + //! \brief ... + Msg() + { + w = ""; + verbose = 3; + } + + // ------------------------------------------------------------------- + // Msg(std::string _who="",int _verbose=3) + // : w(_who+": "), + // verbose(_verbose) + // {} + // ------------------------------------------------------------------- + //! \brief ...copy + Msg(const Msg &) = delete; //NOLINT + //! \brief ...move + Msg(Msg &&) = delete; //NOLINT + //! \brief ...assign + Msg & operator=(const Msg &) = delete; //NOLINT +}; + +//! \brief ... +extern std::unique_ptr msg; diff --git a/fsl/fsl_interp/inc/Options.h b/fsl/fsl_interp/inc/Options.h new file mode 100644 index 00000000..ea3e6ddc --- /dev/null +++ b/fsl/fsl_interp/inc/Options.h @@ -0,0 +1,75 @@ +#pragma once +#include +#include +#include +#include +namespace po = boost::program_options; + +//! \brief container for boost program option settings +struct Options +{ + // ---------------------------------------------------------------- + //! \brief singleton + // ---------------------------------------------------------------- + static Options* getInstance() + { + if (instance == nullptr) { instance = new Options(); } + return instance; + } + + // ---------------------------------------------------------------- + // support methods + // ---------------------------------------------------------------- + //! \brief ... + void buildOptions(po::options_description &); + + //! \brief ... + static bool checkOptions(po::variables_map &, + po::options_description &,bool); + + //! \brief ... + void setupOptions(int, char**); + + //! \brief ... + static void usage(po::options_description & opt) + { + std::cout << opt << std::endl; + } + + //! \brief ... + static void version(); + + // ---------------------------------------------------------------- + //! \brief ... + std::string output_file; + //! \brief ... + std::vector input_files; + //! \brief ... + bool trace_en{false}; + //! \brief ... + bool verbose{false}; + // ---------------------------------------------------------------- + // ---------------------------------------------------------------- + //! \brief ... + bool notify_error{false}; + //! \brief placeholder + bool _query_options{false}; + //! \brief ... + po::variables_map vm; + //! \brief ... + static Options* instance; + + private: + //! \brief ... + Options() = default; + + //! \brief ... + Options(const Options &) = delete; //NOLINT + //! \brief ... + Options(Options &&) = delete; //NOLINT + //! \brief ... + Options & operator=(const Options &) = delete; //NOLINT +}; + +//! \brief ... +extern std::shared_ptr opts; diff --git a/fsl/fsl_interp/src/FslParser.cpp b/fsl/fsl_interp/src/FslParser.cpp new file mode 100644 index 00000000..973f0678 --- /dev/null +++ b/fsl/fsl_interp/src/FslParser.cpp @@ -0,0 +1,138 @@ +//! \file fslparser.cpp wrapper around parser state machine(s) +#include "FslParser.h" +#include "Msg.h" +#include "Options.h" +#include +#include +using namespace std; + +extern FILE* yyin; +extern int yyparse(); +extern FslParser* FP; + +// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +FslParser::FslParser() + : TRACE_EN(0), + lineNo(1), + curCol(1), + currentFile(""), + syntaxName(""), + inputFiles() +{ + FP = this; +} + +// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +bool FslParser::parse(const string &fn) +{ + currentFile = fn; + + FILE* file = fopen(currentFile.c_str(), "r"); + + if (!file) + { + emsg("Can not open file '" + currentFile + "'"); + return false; + } + + int fail = 0; + + yyin = file; + fail = yyparse(); + + fclose(file); + + if (fail) + { + // yyerror() reports the error + return false; + } + + return true; +} + +// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +bool FslParser::parseFiles() +{ + if(opts->input_files.empty()) { + msg->emsg("No input files."); + return false; + } + + for(const auto & fn : opts->input_files) { + if(opts->verbose) msg->imsg("Parsing "+tq(fn)); + + if (!parse(fn)) { + // parse() emits the error message + return false; + } + warmReset(); + } + + return true; +} + +// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +void SymbolTable::info(ostream & os, bool justFileName) const +{ + size_t maxNameLen = 0, maxTypeLen = 0, maxFileLen = 0; + + for (const auto & pair : table) + { + const FslSymbol & symbol = pair.second; + + size_t srcFileLength = symbol.srcFile.length(); + //Get the max length of the path or just file name+ext + if(justFileName) + { + filesystem::path path(symbol.srcFile); + string baseName = path.filename().string(); + string extension = path.extension().string(); + srcFileLength = string(baseName+"."+extension).length(); + } + + maxNameLen = max(maxNameLen, symbol.name.length()); + maxTypeLen = max(maxTypeLen, symbol.type.length()); + maxFileLen = max(maxFileLen, srcFileLength); + } + + size_t totalLen = maxNameLen + maxTypeLen + maxFileLen; + + os << endl; + + os << string(totalLen + 10, '-') << "\n"; + os << "Symbol table\n"; + + os << left << setw(maxNameLen) << "Name" + << " " << setw(maxTypeLen) << "Type" + << " " << setw(8) << "Line" + << " " << setw(maxFileLen) << "File" + << "\n"; + + os << string(totalLen + 10, '-') << "\n"; + + for (const auto & pair : table) + { + const FslSymbol & symbol = pair.second; + + string srcFile = symbol.srcFile; + + if(justFileName) + { + filesystem::path path(srcFile); + srcFile = string(path.filename().string()); + } + + os << left << setw(maxNameLen) << symbol.name << " " + << setw(maxTypeLen) << symbol.type << " " << setw(7) + << symbol.lineNo << " " << setw(maxFileLen) << srcFile << "\n"; + } + + os << "\n"; + os << "Symbol table total entries " << table.size() << "\n"; + os << endl; +} diff --git a/fsl/fsl_interp/src/Options.cpp b/fsl/fsl_interp/src/Options.cpp new file mode 100644 index 00000000..cc8efbfc --- /dev/null +++ b/fsl/fsl_interp/src/Options.cpp @@ -0,0 +1,105 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh, Condor Computing Corp. +// +#include "Msg.h" +#include "Options.h" +#include +using namespace std; + +// -------------------------------------------------------------------- +// Build the option set and check the options +// -------------------------------------------------------------------- +void Options::setupOptions(int ac, char** av) +{ + notify_error = false; + + po::options_description visibleOpts( + "\nFusion API test\n " + "Usage:: test [--help|-h|--version|-v] { options }"); + + po::options_description stdOpts("Standard options"); + buildOptions(stdOpts); + + try + { + po::store(po::command_line_parser(ac, av).options(stdOpts).run(), + vm); + + // Without positional option po::parse_command_line can be used + // po::store(po::parse_command_line(ac, av, allOpts), vm); + } + catch (boost::program_options::error & e) + { + msg->msg(""); + msg->emsg("1st pass command line option parsing failed"); + msg->emsg("What: " + string(e.what())); + usage(stdOpts); + exit(1); + } + + po::notify(vm); + if (!checkOptions(vm, stdOpts, true)) + { + exit(1); + } +} + +// -------------------------------------------------------------------- +// Construct the std, hidden and positional option descriptions +// -------------------------------------------------------------------- +// clang-format off +void Options::buildOptions(po::options_description & stdOpts) +{ + stdOpts.add_options() + + ("help,h", "...") + + ("version,v", "report version and exit") + + ("output,o", po::value(&output_file), + "Output file") + + ("input_file,i", po::value>(&input_files), + "Multiple --input_file accepted") + + ("trace_en", po::bool_switch(&trace_en) ->default_value(false), + "Parser trace enable") + + ("verbose", po::bool_switch(&verbose) ->default_value(false), + "Verbose message control") + ; +} +// clang-format on +// -------------------------------------------------------------------- +// Check sanity on the options, handle --help, --version +// -------------------------------------------------------------------- +bool Options::checkOptions(po::variables_map & vm, + po::options_description & stdOpts, + bool firstPass) +{ + if (firstPass) + { + if (vm.count("help") != 0u) + { + usage(stdOpts); + return false; + } + if (vm.count("version") != 0u) + { + version(); + return false; + } + } + + return true; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +void Options::version() +{ + msg->imsg(""); + msg->imsg("Fusion api tester"); + msg->imsg("Slack jeff w/any questions"); + msg->imsg(""); +} diff --git a/fsl/fsl_interp/src/c99.l b/fsl/fsl_interp/src/c99.l new file mode 100644 index 00000000..cf38dc49 --- /dev/null +++ b/fsl/fsl_interp/src/c99.l @@ -0,0 +1,212 @@ +%{ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file Fsl.l flex scanner for FSL +// ---------------------------------------------------------------- +// Simple lexer derived from the original QParser +// Future: complete wrapping into FP, location info, api variants +// ---------------------------------------------------------------- +#include +#include +#include +#include +#include "fslparser.h" +#include "yy.tab.hpp" +using namespace std; + +extern FslParser *FP; + +extern void comment(void); +extern int check_type(void); +extern void count(void); + +int column = 0; +// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +#define YY_DECL extern int yylex() +#define E(s) if(FP->TRACE_EN) cout<lineNo<<": "<>=" { count(); return(RIGHT_ASSIGN); } +"<<=" { count(); return(LEFT_ASSIGN); } +"+=" { count(); return(ADD_ASSIGN); } +"-=" { count(); return(SUB_ASSIGN); } +"*=" { count(); return(MUL_ASSIGN); } +"/=" { count(); return(DIV_ASSIGN); } +"%=" { count(); return(MOD_ASSIGN); } +"&=" { count(); return(AND_ASSIGN); } +"^=" { count(); return(XOR_ASSIGN); } +"|=" { count(); return(OR_ASSIGN); } +">>" { count(); return(RIGHT_OP); } +"<<" { count(); return(LEFT_OP); } +"++" { count(); return(INC_OP); } +"--" { count(); return(DEC_OP); } +"->" { count(); return(PTR_OP); } +"&&" { count(); return(AND_OP); } +"||" { count(); return(OR_OP); } +"<=" { count(); return(LE_OP); } +">=" { count(); return(GE_OP); } +"==" { count(); return(EQ_OP); } +"!=" { count(); return(NE_OP); } +";" { count(); return(';'); } +("{"|"<%") { count(); return('{'); } +("}"|"%>") { count(); return('}'); } +"," { count(); return(','); } +":" { count(); return(':'); } +"=" { count(); return('='); } +"(" { count(); return('('); } +")" { count(); return(')'); } +("["|"<:") { count(); return('['); } +("]"|":>") { count(); return(']'); } +"." { count(); return('.'); } +"&" { count(); return('&'); } +"!" { count(); return('!'); } +"~" { count(); return('~'); } +"-" { count(); return('-'); } +"+" { count(); return('+'); } +"*" { count(); return('*'); } +"/" { count(); return('/'); } +"%" { count(); return('%'); } +"<" { count(); return('<'); } +">" { count(); return('>'); } +"^" { count(); return('^'); } +"|" { count(); return('|'); } +"?" { count(); return('?'); } + +[ \t\v\n\f] { count(); } +. { /* Add code to complain about unmatched characters */ } + +%% + +void comment(void) { } +//void comment(void) +//{ +// char c, prev = 0; +// +// while ((c = input()) != 0) /* (EOF maps to 0) */ +// { +// if (c == '/' && prev == '*') +// return; +// prev = c; +// } +// yyerror("unterminated comment"); +//} + +void count(void) +{ + int i; + + for (i = 0; yytext[i] != '\0'; i++) + if (yytext[i] == '\n') + column = 0; + else if (yytext[i] == '\t') + column += 8 - (column % 8); + else + column++; + + ECHO; +} + + +int check_type(void) +{ +/* +* pseudo code --- this is what it should check +* +* if (yytext == type_name) +* return TYPE_NAME; +* +* return IDENTIFIER; +*/ + +/* +* it actually will only return IDENTIFIER +*/ + + return IDENTIFIER; +} +// ------------------------------------------------------------------ +// ------------------------------------------------------------------ +void yyerror(const char *s) { + std::cout << "-E: "<currentFile<<": " + << s <<" line "<lineNo< +#include +#include +#include +#include +#include +using namespace std; + +extern FslParser *FP; + +extern int column; +extern int yylex(); +extern int yyparse(); +extern FILE *yyin; +extern char *yytext; +extern void yyerror(const char *s); +//std::vector sequence_lines; + +%} +%token IDENTIFIER CONSTANT STRING_LITERAL SIZEOF +%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP +%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN +%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN +%token XOR_ASSIGN OR_ASSIGN TYPE_NAME + +%token TYPEDEF EXTERN STATIC AUTO REGISTER INLINE RESTRICT +%token CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE CONST VOLATILE VOID +%token BOOL COMPLEX IMAGINARY +%token STRUCT UNION ENUM ELLIPSIS + +%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN + +%start translation_unit +%% + +primary_expression + : IDENTIFIER + | CONSTANT + | STRING_LITERAL + | '(' expression ')' + ; + +postfix_expression + : primary_expression + | postfix_expression '[' expression ']' + | postfix_expression '(' ')' + | postfix_expression '(' argument_expression_list ')' + | postfix_expression '.' IDENTIFIER + | postfix_expression PTR_OP IDENTIFIER + | postfix_expression INC_OP + | postfix_expression DEC_OP + | '(' type_name ')' '{' initializer_list '}' + | '(' type_name ')' '{' initializer_list ',' '}' + ; + +argument_expression_list + : assignment_expression + | argument_expression_list ',' assignment_expression + ; + +unary_expression + : postfix_expression + | INC_OP unary_expression + | DEC_OP unary_expression + | unary_operator cast_expression + | SIZEOF unary_expression + | SIZEOF '(' type_name ')' + ; + +unary_operator + : '&' + | '*' + | '+' + | '-' + | '~' + | '!' + ; + +cast_expression + : unary_expression + | '(' type_name ')' cast_expression + ; + +multiplicative_expression + : cast_expression + | multiplicative_expression '*' cast_expression + | multiplicative_expression '/' cast_expression + | multiplicative_expression '%' cast_expression + ; + +additive_expression + : multiplicative_expression + | additive_expression '+' multiplicative_expression + | additive_expression '-' multiplicative_expression + ; + +shift_expression + : additive_expression + | shift_expression LEFT_OP additive_expression + | shift_expression RIGHT_OP additive_expression + ; + +relational_expression + : shift_expression + | relational_expression '<' shift_expression + | relational_expression '>' shift_expression + | relational_expression LE_OP shift_expression + | relational_expression GE_OP shift_expression + ; + +equality_expression + : relational_expression + | equality_expression EQ_OP relational_expression + | equality_expression NE_OP relational_expression + ; + +and_expression + : equality_expression + | and_expression '&' equality_expression + ; + +exclusive_or_expression + : and_expression + | exclusive_or_expression '^' and_expression + ; + +inclusive_or_expression + : exclusive_or_expression + | inclusive_or_expression '|' exclusive_or_expression + ; + +logical_and_expression + : inclusive_or_expression + | logical_and_expression AND_OP inclusive_or_expression + ; + +logical_or_expression + : logical_and_expression + | logical_or_expression OR_OP logical_and_expression + ; + +conditional_expression + : logical_or_expression + | logical_or_expression '?' expression ':' conditional_expression + ; + +assignment_expression + : conditional_expression + | unary_expression assignment_operator assignment_expression + ; + +assignment_operator + : '=' + | MUL_ASSIGN + | DIV_ASSIGN + | MOD_ASSIGN + | ADD_ASSIGN + | SUB_ASSIGN + | LEFT_ASSIGN + | RIGHT_ASSIGN + | AND_ASSIGN + | XOR_ASSIGN + | OR_ASSIGN + ; + +expression + : assignment_expression + | expression ',' assignment_expression + ; + +constant_expression + : conditional_expression + ; + +declaration + : declaration_specifiers ';' + | declaration_specifiers init_declarator_list ';' + ; + +declaration_specifiers + : storage_class_specifier + | storage_class_specifier declaration_specifiers + | type_specifier + | type_specifier declaration_specifiers + | type_qualifier + | type_qualifier declaration_specifiers + | function_specifier + | function_specifier declaration_specifiers + ; + +init_declarator_list + : init_declarator + | init_declarator_list ',' init_declarator + ; + +init_declarator + : declarator + | declarator '=' initializer + ; + +storage_class_specifier + : TYPEDEF + | EXTERN + | STATIC + | AUTO + | REGISTER + ; + +type_specifier + : VOID + | CHAR + | SHORT + | INT + | LONG + | FLOAT + | DOUBLE + | SIGNED + | UNSIGNED + | BOOL + | COMPLEX + | IMAGINARY + | struct_or_union_specifier + | enum_specifier + | TYPE_NAME + ; + +struct_or_union_specifier + : struct_or_union IDENTIFIER '{' struct_declaration_list '}' + | struct_or_union '{' struct_declaration_list '}' + | struct_or_union IDENTIFIER + ; + +struct_or_union + : STRUCT + | UNION + ; + +struct_declaration_list + : struct_declaration + | struct_declaration_list struct_declaration + ; + +struct_declaration + : specifier_qualifier_list struct_declarator_list ';' + ; + +specifier_qualifier_list + : type_specifier specifier_qualifier_list + | type_specifier + | type_qualifier specifier_qualifier_list + | type_qualifier + ; + +struct_declarator_list + : struct_declarator + | struct_declarator_list ',' struct_declarator + ; + +struct_declarator + : declarator + | ':' constant_expression + | declarator ':' constant_expression + ; + +enum_specifier + : ENUM '{' enumerator_list '}' + | ENUM IDENTIFIER '{' enumerator_list '}' + | ENUM '{' enumerator_list ',' '}' + | ENUM IDENTIFIER '{' enumerator_list ',' '}' + | ENUM IDENTIFIER + ; + +enumerator_list + : enumerator + | enumerator_list ',' enumerator + ; + +enumerator + : IDENTIFIER + | IDENTIFIER '=' constant_expression + ; + +type_qualifier + : CONST + | RESTRICT + | VOLATILE + ; + +function_specifier + : INLINE + ; + +declarator + : pointer direct_declarator + | direct_declarator + ; + + +direct_declarator + : IDENTIFIER + | '(' declarator ')' + | direct_declarator '[' type_qualifier_list assignment_expression ']' + | direct_declarator '[' type_qualifier_list ']' + | direct_declarator '[' assignment_expression ']' + | direct_declarator '[' STATIC type_qualifier_list assignment_expression ']' + | direct_declarator '[' type_qualifier_list STATIC assignment_expression ']' + | direct_declarator '[' type_qualifier_list '*' ']' + | direct_declarator '[' '*' ']' + | direct_declarator '[' ']' + | direct_declarator '(' parameter_type_list ')' + | direct_declarator '(' identifier_list ')' + | direct_declarator '(' ')' + ; + +pointer + : '*' + | '*' type_qualifier_list + | '*' pointer + | '*' type_qualifier_list pointer + ; + +type_qualifier_list + : type_qualifier + | type_qualifier_list type_qualifier + ; + + +parameter_type_list + : parameter_list + | parameter_list ',' ELLIPSIS + ; + +parameter_list + : parameter_declaration + | parameter_list ',' parameter_declaration + ; + +parameter_declaration + : declaration_specifiers declarator + | declaration_specifiers abstract_declarator + | declaration_specifiers + ; + +identifier_list + : IDENTIFIER + | identifier_list ',' IDENTIFIER + ; + +type_name + : specifier_qualifier_list + | specifier_qualifier_list abstract_declarator + ; + +abstract_declarator + : pointer + | direct_abstract_declarator + | pointer direct_abstract_declarator + ; + +direct_abstract_declarator + : '(' abstract_declarator ')' + | '[' ']' + | '[' assignment_expression ']' + | direct_abstract_declarator '[' ']' + | direct_abstract_declarator '[' assignment_expression ']' + | '[' '*' ']' + | direct_abstract_declarator '[' '*' ']' + | '(' ')' + | '(' parameter_type_list ')' + | direct_abstract_declarator '(' ')' + | direct_abstract_declarator '(' parameter_type_list ')' + ; + +initializer + : assignment_expression + | '{' initializer_list '}' + | '{' initializer_list ',' '}' + ; + +initializer_list + : initializer + | designation initializer + | initializer_list ',' initializer + | initializer_list ',' designation initializer + ; + +designation + : designator_list '=' + ; + +designator_list + : designator + | designator_list designator + ; + +designator + : '[' constant_expression ']' + | '.' IDENTIFIER + ; + +statement + : labeled_statement + | compound_statement + | expression_statement + | selection_statement + | iteration_statement + | jump_statement + ; + +labeled_statement + : IDENTIFIER ':' statement + | CASE constant_expression ':' statement + | DEFAULT ':' statement + ; + +compound_statement + : '{' '}' + | '{' block_item_list '}' + ; + +block_item_list + : block_item + | block_item_list block_item + ; + +block_item + : declaration + | statement + ; + +expression_statement + : ';' + | expression ';' + ; + +selection_statement + : IF '(' expression ')' statement + | IF '(' expression ')' statement ELSE statement + | SWITCH '(' expression ')' statement + ; + +iteration_statement + : WHILE '(' expression ')' statement + | DO statement WHILE '(' expression ')' ';' + | FOR '(' expression_statement expression_statement ')' statement + | FOR '(' expression_statement expression_statement expression ')' statement + | FOR '(' declaration expression_statement ')' statement + | FOR '(' declaration expression_statement expression ')' statement + ; + +jump_statement + : GOTO IDENTIFIER ';' + | CONTINUE ';' + | BREAK ';' + | RETURN ';' + | RETURN expression ';' + ; + +translation_unit + : external_declaration + | translation_unit external_declaration + ; + +external_declaration + : function_definition + | declaration + ; + +function_definition + : declaration_specifiers declarator declaration_list compound_statement + | declaration_specifiers declarator compound_statement + ; + +declaration_list + : declaration + | declaration_list declaration + ; + +%% diff --git a/fsl/fsl_interp/src/fsl.l b/fsl/fsl_interp/src/fsl.l new file mode 100644 index 00000000..5a60e512 --- /dev/null +++ b/fsl/fsl_interp/src/fsl.l @@ -0,0 +1,265 @@ +%{ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file Fsl.l flex scanner for FSL +// ---------------------------------------------------------------- +// Simple lexer derived from the original QParser +// Future: complete wrapping into FP, location info, api variants +// ---------------------------------------------------------------- +#include +#include +#include +#include +#include "FslParser.h" +#include "yy.tab.hpp" +using namespace std; + +extern FslParser *FP; + +extern void comment(void); +extern int check_type(void); +extern void count(void); +int column = 0; +// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +#define YY_DECL extern int yylex() + +#ifndef E +#define E(s) if(FP->TRACE_EN) cout<lineNo<<": "<{ + "*/" { BEGIN(INITIAL); } + [^*\n]+ { /* Ignore non-newline and non-asterisk characters */ } + "*" { /* Ignore standalone asterisk characters */ } + "\n" { E("C") ++FP->lineNo; } +} + +\/\/[^\n]* { E("COMMENT") } + +"sequence" { BEGIN(SEQUENCE); } +{ + "}" { BEGIN(INITIAL); } + [^}\n]+ { /* Ignore non-newline/non-brace characters */ } + "\n" { E("SEQ") ++FP->lineNo; } +} + +_fail_ { CAPT(FAIL); } +_pass_ { CAPT(PASS); } +constraints { CAPT(CONSTRAINTS); } +conversion { CAPT(CONVERSION); } +csr { CAPT(CSR); } +dst { CAPT(DST); } +emit { CAPT(EMIT); } +encode_order { CAPT(ENCODE_ORDER); } +encoding { CAPT(ENCODING); } +false { CAPT(FALSE); } +fusion { CAPT(FUSION); } +gpr { CAPT(GPR); } +hasAttr { CAPT(HASATTR); } +if { CAPT(IF); } +instr { CAPT(INSTR); } +ioput { CAPT(IOPUT); } +isa { CAPT(ISA); } +mnemonic { CAPT(MNEMONIC); } +morph { CAPT(MORPH); } +opc { CAPT(OPC); } +prolog { CAPT(PROLOG); } +rdx { CAPT(RDX); } +replace { CAPT(REPLACE); } +rsx { CAPT(RSX); } +s0 { CAPT(S0); } +s1 { CAPT(S1); } +setof { CAPT(SETOF); } +string { CAPT(STRING); } +transform { CAPT(TRANSFORM); } +true { CAPT(TRUE); } +type { CAPT(TYPE); } +uarch { CAPT(UARCH); } +writePorts { CAPT(WRITEPORTS); } +readPorts { CAPT(READPORTS); } +requiredBits { CAPT(REQUIREDBITS); } + +_req_ { /* get a unique ID for _req_ symbols and add to symtab */ + std::string symName = FP->newReqSymbol(); + FslSymbol sym(symName,FP->lineNo,FP->currentFile,"REQ_TYPE"); + FP->insertSymbol(symName,sym); + CAPT(REQ_TOKEN); + } + +_opt_ { /* get a unique ID for _opt_ symbols and add to symtab */ + std::string symName = FP->newOptSymbol(); + FslSymbol sym(symName,FP->lineNo,FP->currentFile,"OPT_TYPE"); + FP->insertSymbol(symName,sym); + CAPT(OPT_TOKEN); + } + +"else" { CAPT(ELSE); } +"extern" { CAPT(EXTERN); } +"for" { CAPT(FOR); } +"imm" { CAPT(IMM); } +"src" { CAPT(SRC); } + + +{UNSIGNED_CONST} { count(); GET_STR; CAPT(UN_CONST); } +{SIGNED_CONST} { count(); GET_STR; CAPT(S_CONST); } +{HEX_CONST} { CAPT(HEX_CONST); } +{VLOG_BIN} { CAPT(VLOG_CONST); } +{VLOG_OCT} { CAPT(VLOG_CONST); } +{VLOG_DEC} { CAPT(VLOG_CONST); } +{VLOG_HEX} { CAPT(VLOG_CONST); } + +\"([^"\\]|\\(.|\n))*\" { yylval.sval = strdup(yytext); _RET(QSTRING); } + +{L}({L}|{D})* { count(); return(check_type()); } +0[xX]{H}+{IS}? { count(); return(CONSTANT); } +0[0-7]*{IS}? { count(); return(CONSTANT); } +[1-9]{D}*{IS}? { count(); return(CONSTANT); } +L?'(\\.|[^\\'\n])+' { count(); return(CONSTANT); } + +{D}+{E}{FS}? { count(); return(CONSTANT); } +{D}*"."{D}+{E}?{FS}? { count(); return(CONSTANT); } +{D}+"."{D}*{E}?{FS}? { count(); return(CONSTANT); } +0[xX]{H}+{P}{FS}? { count(); return(CONSTANT); } +0[xX]{H}*"."{H}+{P}?{FS}? { count(); return(CONSTANT); } +0[xX]{H}+"."{H}*{P}?{FS}? { count(); return(CONSTANT); } + + +L?\"(\\.|[^\\"\n])*\" { count(); return(STRING_LITERAL); } + +">>" { count(); return(RIGHT_OP); } +"<<" { count(); return(LEFT_OP); } +"++" { count(); return(INC_OP); } +"--" { count(); return(DEC_OP); } +"&&" { count(); return(AND_OP); } +"||" { count(); return(OR_OP); } +"<=" { count(); return(LE_OP); } +">=" { count(); return(GE_OP); } +"==" { count(); return(EQ_OP); } +"!=" { count(); return(NE_OP); } +";" { count(); return(';'); } +("{"|"<%") { count(); return('{'); } +("}"|"%>") { count(); return('}'); } +"," { count(); return(','); } +":" { count(); return(':'); } +"=" { count(); return('='); } +"(" { count(); return('('); } +")" { count(); return(')'); } +("["|"<:") { count(); return('['); } +("]"|":>") { count(); return(']'); } +"." { E(".") count(); return('.'); } +"&" { count(); return('&'); } +"!" { count(); return('!'); } +"~" { count(); return('~'); } +"-" { count(); return('-'); } +"+" { count(); return('+'); } +"*" { count(); return('*'); } +"/" { count(); return('/'); } +"%" { count(); return('%'); } +"<" { count(); return('<'); } +">" { count(); return('>'); } +"^" { count(); return('^'); } +"|" { count(); return('|'); } +"?" { count(); return('?'); } + +[\n] { FP->lineNo += 1; count(); } +[ \t] { /* */ } +. { E(yytext[0]) _RET(yytext[0]); } + +%% + +//Future pragma support +void comment(void) { } +//void comment(void) +//{ +// char c, prev = 0; +// +// while ((c = input()) != 0) /* (EOF maps to 0) */ +// { +// if (c == '/' && prev == '*') +// return; +// prev = c; +// } +// yyerror("unterminated comment"); +//} + +void count(void) +{ +// int i; + +// for (i = 0; yytext[i] != '\0'; i++) +// if (yytext[i] == '\n') +// column = 0; +// else if (yytext[i] == '\t') +// column += 8 - (column % 8); +// else +// column++; +// ECHO; +} + + +int check_type(void) +{ +/* +* pseudo code --- this is what it should check +* +* if (yytext == type_name) +* return TYPE_NAME; +* +* return ID; +*/ + +/* +* it actually will only return ID +*/ + E(yytext) + return ID; +} +// ------------------------------------------------------------------ +// ------------------------------------------------------------------ +void yyerror(const char *s) { + std::cout << "-E: "<currentFile<<": " + << s <<" " << yytext <<", line " + <lineNo< +#include +#include +#include +#include "fslparser.h" +#include "yy.tab.hpp" +using namespace std; + +extern FslParser *FP; +// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +#define YY_DECL extern int yylex() + +#define E(s) if(FP->TRACE_EN) cout<lineNo<<": "<=" +GE "<=" + +UNSIGNED_CONST u[0-9]+[0-9]* +SIGNED_CONST s[0-9]+[0-9]* +UID "0x"[0-9a-fA-F]{1,2} +DEC_NUM [+-]*[0-9]+[0-9]* +HEX_CONST "0x"[0-9a-fA-F]+ + +%x COMMENT + +%option nounput +%option noyywrap + +%% + +"/*" { BEGIN(COMMENT); } + +{ + "*/" { BEGIN(INITIAL); } + [^*\n]+ { /* Ignore non-newline and non-asterisk characters */ } + "*" { /* Ignore standalone asterisk characters */ } + "\n" { ++FP->lineNo; } // Increment line count on newline +} + +\/\/[^\n]* { E("COMMENT") } + +_fail_ { E("_FAIL_") RET(FAIL); } +_pass_ { E("_PASS_") RET(PASS); } +constraints { E("CONSTRAINTS") RET(CONSTRAINTS); } +conversion { E("CONVERSION") RET(CONVERSION); } +emit { E("EMIT") RET(EMIT); } +encode_order { E("ENCODE_ORDER") RET(ENCODE_ORDER); } +encoding { E("ENCODING") RET(ENCODING); } +fusion { E("FUSION") RET(FUSION); } +gpr { E("GPR") RET(GPR); } +if { E("IF") RET(IF); } +instr { E("INSTR") RET(INSTR); } +ioput { E("IOPUT") RET(IOPUT); } +isa { E("ISA") RET(ISA); } +prolog { E("PROLOG") RET(PROLOG); } +s0 { E("S0") RET(S0); } +s1 { E("S1") RET(S1); } +sequence { E("SEQUENCE") RET(SEQUENCE); } +transform { E("TRANSFORM") RET(TRANSFORM); } +uarch { E("UARCH") RET(UARCH); } +true { E("TRUE") RET(TRUE); } +false { E("FALSE") RET(FALSE); } + + + +_req_ { /* get a unique ID for _req_ symbols and add to symtab */ + E("REQ") + std::string symName = FP->newReqSymbol(); + FslSymbol sym(symName,FP->lineNo,FP->currentFile,"REQ_TYPE"); + FP->insertSymbol(symName,sym); + RET(REQ_TOKEN); + } + +_opt_ { /* get a unique ID for _opt_ symbols and add to symtab */ + E("OPT") + std::string symName = FP->newOptSymbol(); + FslSymbol sym(symName,FP->lineNo,FP->currentFile,"OPT_TYPE"); + FP->insertSymbol(symName,sym); + RET(OPT_TOKEN); + } + +{UID} { E("UID") RET(UID); } +{UNSIGNED_CONST} { E("UN_CONST") GET_STR; RET(UN_CONST); } +{SIGNED_CONST} { E("S_CONST") GET_STR; RET(S_CONST); } +{HEX_CONST} { E("HEX_CONST") RET(HEX_CONST); } +{DEC_NUM} { E("DEC_NUM") RET(DEC_NUM); } + +\"([^"\\]|\\(.|\n))*\" { + yylval.sval = strdup(yytext); + RET(QSTRING); + } + +{NEQ} { E("NEQ") RET(NEQ); } +{EQ} { E("EQ") RET(EQ); } +{LE} { E("LE") RET(LE); } +{GE} { E("GE") RET(GE); } + +[\.]*[_a-z\.A-Z0-9]+ { + //E("ID") + yylval.sval = strdup(yytext); + E(yytext) + FslSymbol sym(yytext,FP->lineNo,FP->currentFile); + FP->insertSymbol(yytext,sym); + RET(ID); + return ID; + } + +[\n] { ++FP->lineNo; FP->curCol=1; } +[ \t] { /* this does not handle col position yet */; } +. { ++FP->curCol; E(yytext[0]) RET(yytext[0]); } +%% +// ------------------------------------------------------------------ +// ------------------------------------------------------------------ +void yyerror(const char *s) { + std::cout << "-E: "<currentFile<<": " + << s <<" line "<lineNo< +#include +#include +#include +#include +#include +using namespace std; + +extern FslParser *FP; +extern int column; +extern int yylex(); +extern int yyparse(); +extern FILE *yyin; +extern char *yytext; +extern void yyerror(const char *s); +%} + +%union { + int ival; + float fval; + char *sval; + std::string *str; +} + +%token CONSTRAINTS CONVERSION EMIT ENCODE_ORDER ENCODING FAIL FUSION CSR GPR HASATTR IF INPUT_SEQ INSTR IOPUT ISA MNEMONIC REPLACE REQUIREDBITS OPC SRC DST RSX RDX IMM TYPE MORPH OPT_TOKEN PASS PROLOG REQ_TOKEN RET S0 S1 SEQUENCE TRANSFORM UARCH UN_CONST S_CONST STRING UID TRUE FALSE WRITEPORTS READPORTS SETOF QSTRING ID CONSTANT STRING_LITERAL INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN TYPE_NAME EXTERN AUTO ELSE FOR HEX_CONST VLOG_CONST + +%nonassoc NO_ELSE +%nonassoc ELSE +%nonassoc '=' +%left '{' +%right '}' + +%start top + +%% + +top: + /* */ + | top source_line + ; + +source_line: + transform_definition + | prolog_definition + | declaration + ; + +transform_definition: + TRANSFORM id '{' '}' + | TRANSFORM id '{' transform_statements '}' + ; + +transform_statements: + transform_statement + | transform_statements transform_statement + ; + +transform_statement: + PROLOG id + | isa_decl + | uarch_decl + | ioput_decl + | variable_decl + | selection_statement + | constraints_definition + | conversion_definition + | setof_definition + ; + +setof_definition: + SETOF id '=' chained_id_list '.' chained_method_list + ; + +chained_method_list: + chained_method_list '.' known_method_decl + | known_method_decl + ; + +known_method_decl: + known_method '(' opt_arg ')' + ; + +opt_arg: + /* empty */ + | id + | constant + | '{' '}' + | '*' + | '{' concatenate_list '}' + ; + +prolog_definition: + PROLOG id '{' '}' + | PROLOG id '{' prolog_statements '}' + ; + +prolog_statements: + prolog_statement + | prolog_statements prolog_statement + ; + +prolog_statement: + ISA id + | UARCH id + | IOPUT id + ; + +isa_decl: ISA id ; +uarch_decl: UARCH id ; +ioput_decl: IOPUT id ; + +variable_definition: + type_specifier id '=' assignment_expression + | type_specifier id '=' '{' concatenate_list '}' + ; + +variable_decl: + type_specifier arg_expr_list + | variable_definition + ; + +constraints_definition: + CONSTRAINTS opt_id '{' constraints_statements '}' + | CONSTRAINTS id '(' arg_expr_list ')' '{' constraints_statements '}' + ; + +opt_id: + /* empty */ + | id + ; + +constraints_statements: + constraints_statement + | constraints_statements constraints_statement + ; + +constraints_statement: + pass_fail_statement + | chained_id_list comparison_operator chained_id_list + | chained_id_list comparison_operator constant + | chained_id_list comparison_operator chained_id_list LEFT_OP constant + | chained_id_list '.' known_method_decl comparison_operator chained_id_list '.' known_method_decl + | chained_id_list '.' known_method_decl comparison_operator constant + | selection_statement + ; + +comparison_operator: + LE_OP + | GE_OP + | EQ_OP + | NE_OP + ; + +conversion_definition: + CONVERSION opt_id '{' conversion_statements '}' + | CONVERSION id '(' arg_expr_list ')' '{' conversion_statements '}' + ; + +conversion_statements: + conversion_statement + | conversion_statements conversion_statement + ; + +conversion_statement: + pass_fail_statement + | variable_decl + | encoding_decl + | encoding_definition + | instr_decl + | instr_definition + | chained_id_list '.' known_method_decl + | chained_id_list '.' REPLACE '(' comma_sep_list ')' + ; + +concatenate_list: + concatenate_elem + | concatenate_list ',' concatenate_elem + ; + +concatenate_elem: + id + | id range_list opt_dot_id + | OPC + | constant + | known_method '=' constant + ; + +opt_dot_id: + /* empty */ + | '.' id + ; + +comma_sep_list: + id + | comma_sep_list ',' id + ; + +range_list: + '[' constant ']' + | '[' constant ':' constant ']' + | range_list '[' constant ']' + | range_list '[' constant ':' constant ']' + ; + +chained_id_list: + id + | chained_id_list '.' id + ; + +known_method: + MNEMONIC + | ENCODE_ORDER + | WRITEPORTS + | READPORTS + | REQUIREDBITS + | ENCODING + | OPC + | SRC + | DST + | RSX + | IMM + | TYPE + | HASATTR + | MORPH + ; + +instr_decl: INSTR id ; + +instr_definition: + INSTR id '(' arg_assignment_list ')' + | INSTR id '(' '{' concatenate_list '}' ')' + | INSTR id '(' '{' encode_list '}' ')' + | INSTR id '(' chained_id_list '.' known_method '(' id ')' ')' + | INSTR id '(' known_method '(' id ')' ')' + ; + +encode_list: + encode_elem + | encode_list ',' encode_elem + ; + +encode_elem: + id '[' constant ']' '.' ENCODING + ; + +encoding_decl: ENCODING id ; + +encoding_definition: + ENCODING id '(' arg_assignment_list ')' + | ENCODING id '(' '{' concatenate_list '}' ')' + ; + +arg_assignment_list: + arg_assignment + | arg_assignment_list ',' arg_assignment + ; + +arg_assignment: + known_method '=' constant + | known_method '=' '{' arg_expr_list '}' + | id '=' '{' arg_expr_list '}' + ; + +pass_fail_statement: + PASS + | FAIL + ; + +primary_expression: + id + | constant + | STRING_LITERAL + | '(' expression ')' + ; + +postfix_expression: + primary_expression + | postfix_expression '[' expression ']' + | postfix_expression '(' opt_arg_expr_list ')' + | postfix_expression '.' id + | postfix_expression INC_OP + | postfix_expression DEC_OP + | postfix_expression '.' ENCODING '(' ')' + ; + +opt_arg_expr_list: + /* empty */ + | arg_expr_list + ; + +arg_expr_list: + assignment_expression + | arg_expr_list ',' assignment_expression + ; + +unary_expression: + postfix_expression + | INC_OP unary_expression + | DEC_OP unary_expression + | unary_operator cast_expression + ; + +unary_operator: + '&' + | '*' + | '+' + | '-' + | '~' + | '!' + ; + +cast_expression: + unary_expression + | '(' type_name ')' cast_expression + ; + +multiplicative_expression: + cast_expression + | multiplicative_expression '*' cast_expression + | multiplicative_expression '/' cast_expression + | multiplicative_expression '%' cast_expression + ; + +additive_expression: + multiplicative_expression + | additive_expression '+' multiplicative_expression + | additive_expression '-' multiplicative_expression + ; + +shift_expression: + additive_expression + | shift_expression LEFT_OP additive_expression + | shift_expression RIGHT_OP additive_expression + ; + +relational_expression: + shift_expression + | relational_expression '<' shift_expression + | relational_expression '>' shift_expression + | relational_expression LE_OP shift_expression + | relational_expression GE_OP shift_expression + ; + +equality_expression: + relational_expression + | equality_expression EQ_OP relational_expression + | equality_expression NE_OP relational_expression + ; + +and_expression: + equality_expression + | and_expression '&' equality_expression + ; + +exclusive_or_expression: + and_expression + | exclusive_or_expression '^' and_expression + ; + +inclusive_or_expression: + exclusive_or_expression + | inclusive_or_expression '|' exclusive_or_expression + ; + +logical_and_expression: + inclusive_or_expression + | logical_and_expression AND_OP inclusive_or_expression + ; + +logical_or_expression: + logical_and_expression + | logical_or_expression OR_OP logical_and_expression + ; + +conditional_expression: + logical_or_expression + | logical_or_expression '?' expression ':' conditional_expression + ; + +assignment_expression: + conditional_expression + | unary_expression assignment_operator assignment_expression + ; + +expression: + assignment_expression + | expression ',' assignment_expression + ; + +assignment_operator: + '=' + ; + +declaration: + declaration_specifiers ';' + | declaration_specifiers init_declarator_list ';' + ; + +declaration_specifiers: + storage_class_specifier + | storage_class_specifier declaration_specifiers + | type_specifier + | type_specifier declaration_specifiers + ; + +init_declarator_list: + init_declarator + | init_declarator_list ',' init_declarator + ; + +init_declarator: + declarator + | declarator '=' initializer + ; + +storage_class_specifier: + EXTERN + | AUTO + ; + +type_specifier: + GPR + | CSR + | UN_CONST + | S_CONST + | STRING + ; + +declarator: + direct_declarator + ; + +direct_declarator: + id + | '(' declarator ')' + | direct_declarator '[' '*' ']' + | direct_declarator '[' constant ']' + | direct_declarator '[' constant ':' constant ']' + | direct_declarator '[' ']' + | direct_declarator '(' parameter_list ')' + | direct_declarator '(' identifier_list ')' + | direct_declarator '(' ')' + ; + +parameter_list: + parameter_declaration + | parameter_list ',' parameter_declaration + ; + +parameter_declaration: + declaration_specifiers declarator + | declaration_specifiers + ; + +identifier_list: + id + | identifier_list ',' id + ; + +type_name: + specifier_qualifier_list + ; + +specifier_qualifier_list: + type_specifier + | type_specifier specifier_qualifier_list + ; + +initializer: + assignment_expression + | '{' initializer_list '}' + | '{' initializer_list ',' '}' + ; + +initializer_list: + initializer + | initializer_list ',' initializer + ; + +statement: + pass_fail_statement + | compound_statement + | expression_statement + | selection_statement + | iteration_statement + ; + +compound_statement: + '{' '}' + | '{' block_item_list '}' + ; + +block_item_list: + block_item + | block_item_list block_item + ; + +block_item: + declaration + | statement + ; + +expression_statement: + ';' + | expression ';' + ; + +selection_statement: + IF '(' expression ')' statement %prec NO_ELSE + | IF '(' expression ')' statement ELSE statement + ; + +iteration_statement: + FOR '(' expression_statement expression_statement ')' statement + | FOR '(' expression_statement expression_statement expression ')' statement + | FOR '(' declaration expression_statement ')' statement + | FOR '(' declaration expression_statement expression ')' statement + ; + +id: + ID + ; + +constant: + CONSTANT + | HEX_CONST + | VLOG_CONST + | QSTRING + ; +%% + + diff --git a/fsl/fsl_interp/src/fsl.y.2 b/fsl/fsl_interp/src/fsl.y.2 new file mode 100644 index 00000000..1c32c6be --- /dev/null +++ b/fsl/fsl_interp/src/fsl.y.2 @@ -0,0 +1,803 @@ +%{ +#include "fslparser.h" + +#include +#include +#include +#include +#include +#include +using namespace std; + +extern FslParser *FP; + +extern int column; +extern int yylex(); +extern int yyparse(); +extern FILE *yyin; +extern char *yytext; +extern void yyerror(const char *s); +//std::vector sequence_lines; + +%} + +%union { + int ival; + float fval; + char *sval; + std::string *str; +} + +%token CONSTRAINTS +%token CONVERSION +%token EMIT +%token ENCODE_ORDER +%token ENCODING +%token FAIL +%token FUSION +%token CSR +%token GPR +%token HASATTR +%token IF +%token INPUT_SEQ +%token INSTR +%token IOPUT +%token ISA +%token MNEMONIC +%token REPLACE +%token REQUIREDBITS +%token OPC +%token SRC +%token DST +%token RSX +%token RDX +%token IMM +%token TYPE +%token MORPH +%token OPT_TOKEN +%token PASS +%token PROLOG +%token REQ_TOKEN +%token RET +%token S0 S1 +%token SEQUENCE +%token TRANSFORM +%token UARCH +%token UN_CONST +%token S_CONST +%token STRING +%token UID +%token TRUE +%token FALSE +%token WRITEPORTS +%token READPORTS +%token SETOF + +%token QSTRING ID CONSTANT STRING_LITERAL +%token INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP +%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN +%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN +%token XOR_ASSIGN OR_ASSIGN TYPE_NAME + +%token EXTERN AUTO + +%token ELSE FOR + +%token HEX_CONST +%token VLOG_CONST + +%nonassoc NO_ELSE +%nonassoc ELSE +%nonassoc '=' +%left '{' +%right '}' + +%start top + +%% + +top: + source_line + | top source_line + ; + +source_line: + transform_definition + | prolog_definition +// | function_definition + | declaration + ; + +transform_definition: + TRANSFORM id '{' '}' + | TRANSFORM id '{' transform_statements '}' + ; + +transform_statements: + transform_statement + | transform_statements transform_statement + ; + +transform_statement: + PROLOG id + | isa_decl + | uarch_decl + | ioput_decl + | variable_decl + | selection_statement + | constraints_definition + | conversion_definition + | setof_definition + ; + +setof_definition: + SETOF id '=' chained_id_list '.' chained_method_list + ; + +chained_method_list: + known_method_decl + | chained_method_list '.' known_method_decl + +known_method_decl: + known_method '(' ')' + | known_method '(' id ')' + | known_method '(' constant ')' + | known_method '(' '{' '}' ')' + | known_method '(' '*' ')' + | known_method '(' '{' concatenate_list '}' ')' + ; + +prolog_definition: + PROLOG id '{' '}' + | PROLOG id '{' prolog_statements '}' + ; + +prolog_statements: + prolog_statement + | prolog_statements prolog_statement + ; + +prolog_statement: + ISA id + | UARCH id + | IOPUT id + ; + +isa_decl: ISA id ; +uarch_decl: UARCH id ; +ioput_decl: IOPUT id ; + +//variable_definition: +// variable_type id '=' assignment_expression +// | variable_type id '=' '{' concatenate_list '}' + ; + +variable_definition: + type_specifier id '=' assignment_expression + | type_specifier id '=' '{' concatenate_list '}' + ; + +variable_decl: + type_specifier arg_expr_list + | variable_definition + ; + +constraints_definition: + CONSTRAINTS id_opt '{' constraints_statements '}' + | CONSTRAINTS id '(' arg_expr_list ')' '{' '}' + | CONSTRAINTS id '(' arg_expr_list ')' '{' constraints_statements '}' + ; + +id_opt: + /* */ + | id + ; +constraints_statements: + constraints_statement + | constraints_statements constraints_statement + ; + + +constraints_statement: + pass_fail_statement + | chained_id_list comparison_operator chained_id_list + | chained_id_list comparison_operator constant + | chained_id_list comparison_operator chained_id_list LEFT_OP constant + | chained_id_list '.' known_method_decl comparison_operator + chained_id_list '.' known_method_decl + | chained_id_list '.' known_method_decl comparison_operator constant + | selection_statement + ; + +comparison_operator: + LE_OP + | GE_OP + | EQ_OP + | NE_OP + ; + +conversion_definition: + CONVERSION '{' conversion_statements '}' + | CONVERSION id '{' conversion_statements '}' + | CONVERSION id '(' arg_expr_list ')' '{' '}' + | CONVERSION id '(' arg_expr_list ')' '{' conversion_statements '}' + ; + +conversion_statements: + conversion_statement + | conversion_statements conversion_statement + ; + +conversion_statement: + pass_fail_statement + | variable_decl + | encoding_decl + | encoding_definition + | instr_decl + | instr_definition + | chained_id_list '.' known_method_decl + | chained_id_list '.' REPLACE '(' comma_sep_list ')' + ; + +concatenate_list: + concatenate_elem + | concatenate_list ',' concatenate_elem + ; + +concatenate_elem: + id +// | select_elem + | id range_list opt_dot_id + | OPC + | constant + | known_method '=' constant + ; + +opt_dot_id: + /* */ + | '.' id + ; + +comma_sep_list: + id + | comma_sep_list ',' id + ; + +range_list: + '[' constant ']' + | '[' constant ':' constant ']' + | range_list '[' constant ']' + | range_list '[' constant ':' constant ']' + ; +//select_elem: +// id bit_range +//select_elem: +// id '[' constant ']' +// | id '[' constant ':' constant ']' +// ; + +chained_id_list: + id + | chained_id_list '.' id + ; + +known_method: + MNEMONIC + | ENCODE_ORDER + | WRITEPORTS + | READPORTS + | REQUIREDBITS + | ENCODING + | OPC + | SRC + | DST + | RSX + | IMM + | TYPE + | HASATTR + | MORPH + ; + +instr_decl: + INSTR id + ; + +instr_definition: + INSTR id '(' arg_assignment_list ')' + | INSTR id '(' '{' concatenate_list '}' ')' + | INSTR id '(' '{' encode_list '}' ')' + | INSTR id '(' chained_id_list '.' known_method '(' id ')' ')' + | INSTR id '(' known_method '(' id ')' ')' + ; + +encode_list: + encode_elem + | encode_list ',' encode_elem + ; + +encode_elem: + id '[' constant ']' '.' ENCODING + ; + +encoding_decl: + ENCODING id + ; + +encoding_definition: + ENCODING id '(' arg_assignment_list ')' + | ENCODING id '(' '{' concatenate_list '}' ')' + ; + +arg_assignment_list: + arg_assignment + | arg_assignment_list ',' arg_assignment + ; + +arg_assignment: + known_method '=' constant + | known_method '=' '{' arg_expr_list '}' + | id '=' '{' arg_expr_list '}' + ; + + +pass_fail_statement: + PASS + | FAIL + ; + +primary_expression + : id + | constant + | STRING_LITERAL + | '(' expression ')' + ; + +postfix_expression + : primary_expression + | postfix_expression '[' expression ']' + | postfix_expression '(' ')' + | postfix_expression '(' arg_expr_list ')' + | postfix_expression '.' id + | postfix_expression INC_OP + | postfix_expression DEC_OP + | postfix_expression '.' ENCODING '(' ')' +// | '(' type_name ')' '{' initializer_list '}' +// | '(' type_name ')' '{' initializer_list ',' '}' + ; + +arg_expr_list: + assignment_expression + | arg_expr_list ',' assignment_expression + ; + + +unary_expression + : postfix_expression + | INC_OP unary_expression + | DEC_OP unary_expression + | unary_operator cast_expression +// | SIZEOF unary_expression +// | SIZEOF '(' type_name ')' + ; + +unary_operator + : '&' + | '*' + | '+' + | '-' + | '~' + | '!' + ; + +cast_expression + : unary_expression + | '(' type_name ')' cast_expression + ; + +multiplicative_expression + : cast_expression + | multiplicative_expression '*' cast_expression + | multiplicative_expression '/' cast_expression + | multiplicative_expression '%' cast_expression + ; + +additive_expression + : multiplicative_expression + | additive_expression '+' multiplicative_expression + | additive_expression '-' multiplicative_expression + ; + +shift_expression + : additive_expression + | shift_expression LEFT_OP additive_expression + | shift_expression RIGHT_OP additive_expression + ; + +relational_expression + : shift_expression + | relational_expression '<' shift_expression + | relational_expression '>' shift_expression + | relational_expression LE_OP shift_expression + | relational_expression GE_OP shift_expression + ; + +equality_expression + : relational_expression + | equality_expression EQ_OP relational_expression + | equality_expression NE_OP relational_expression + ; + +and_expression + : equality_expression + | and_expression '&' equality_expression + ; + +exclusive_or_expression + : and_expression + | exclusive_or_expression '^' and_expression + ; + +inclusive_or_expression + : exclusive_or_expression + | inclusive_or_expression '|' exclusive_or_expression + ; + +logical_and_expression + : inclusive_or_expression + | logical_and_expression AND_OP inclusive_or_expression + ; + +logical_or_expression + : logical_and_expression + | logical_or_expression OR_OP logical_and_expression + ; + +conditional_expression + : logical_or_expression + | logical_or_expression '?' expression ':' conditional_expression + ; + +assignment_expression + : conditional_expression + | unary_expression assignment_operator assignment_expression + ; + +expression: + assignment_expression + | expression ',' assignment_expression + ; + +//constant_expression: +// conditional_expression +// ; + +assignment_operator + : '=' +// | MUL_ASSIGN +// | DIV_ASSIGN +// | MOD_ASSIGN +// | ADD_ASSIGN +// | SUB_ASSIGN +// | LEFT_ASSIGN +// | RIGHT_ASSIGN +// | AND_ASSIGN +// | XOR_ASSIGN +// | OR_ASSIGN + ; + +declaration + : declaration_specifiers ';' + | declaration_specifiers init_declarator_list ';' + ; + +declaration_specifiers: + storage_class_specifier + | storage_class_specifier declaration_specifiers + | type_specifier + | type_specifier declaration_specifiers +// | type_qualifier +// | type_qualifier declaration_specifiers +// | function_specifier +// | function_specifier declaration_specifiers + ; + +init_declarator_list + : init_declarator + | init_declarator_list ',' init_declarator + ; + +init_declarator + : declarator + | declarator '=' initializer + ; + +storage_class_specifier: +// TYPEDEF + EXTERN +// | STATIC + | AUTO +// | REGISTER + ; + +type_specifier: +// VOID + GPR + | CSR + | UN_CONST + | S_CONST + | STRING +// | CHAR +// | SHORT +// | INT +// | LONG +// | FLOAT +// | DOUBLE +// | SIGNED +// | UNSIGNED +// | COMPLEX +// | IMAGINARY +// | struct_or_union_specifier +// | enum_specifier +// | TYPE_NAME + ; + +//struct_or_union_specifier +// : struct_or_union id '{' struct_declaration_list '}' +// | struct_or_union '{' struct_declaration_list '}' +// | struct_or_union id +// ; + +//struct_or_union +// : STRUCT +// | UNION +// ; + +//struct_declaration_list +// : struct_declaration +// | struct_declaration_list struct_declaration +// ; + +//struct_declaration +// : specifier_qualifier_list struct_declarator_list ';' + ; + +specifier_qualifier_list + : type_specifier specifier_qualifier_list + | type_specifier +// | type_qualifier specifier_qualifier_list +// | type_qualifier + ; + +//struct_declarator_list +// : struct_declarator +// | struct_declarator_list ',' struct_declarator +// ; + +//struct_declarator +// : declarator +// | ':' constant_expression +// | declarator ':' constant_expression +// ; + +//enum_specifier +// : ENUM '{' enumerator_list '}' +// | ENUM id '{' enumerator_list '}' +// | ENUM '{' enumerator_list ',' '}' +// | ENUM id '{' enumerator_list ',' '}' +// | ENUM id +// ; + +//enumerator_list +// : enumerator +// | enumerator_list ',' enumerator +// ; +// +//enumerator +// : id +//// | id '=' constant_expression +// ; +// +//type_qualifier +// : CONST +// | RESTRICT +// | VOLATILE +// ; + +//function_specifier +// : INLINE +// ; + +declarator: +// : pointer direct_declarator + direct_declarator + ; + +direct_declarator + : id + | '(' declarator ')' +// | direct_declarator '[' type_qualifier_list assignment_expression ']' +// | direct_declarator '[' type_qualifier_list ']' +// | direct_declarator '[' assignment_expression ']' +// | direct_declarator '[' STATIC type_qualifier_list assignment_expression ']' +// | direct_declarator '[' type_qualifier_list STATIC assignment_expression ']' +// | direct_declarator '[' type_qualifier_list '*' ']' + | direct_declarator '[' '*' ']' + | direct_declarator '[' constant ']' + | direct_declarator '[' constant ':' constant ']' + | direct_declarator '[' ']' + | direct_declarator '(' parameter_list ')' + | direct_declarator '(' identifier_list ')' + | direct_declarator '(' ')' + ; + +//pointer +// : '*' +//// | '*' type_qualifier_list +// | '*' pointer +//// | '*' type_qualifier_list pointer +// ; + +//type_qualifier_list +// : type_qualifier +// | type_qualifier_list type_qualifier +// ; + + +//parameter_type_list +// : parameter_list +//// | parameter_list ',' ELLIPSIS +// ; + +parameter_list + : parameter_declaration + | parameter_list ',' parameter_declaration + ; + +parameter_declaration + : declaration_specifiers declarator +// | declaration_specifiers abstract_declarator + | declaration_specifiers + ; + +identifier_list + : id + | identifier_list ',' id + ; + +type_name + : specifier_qualifier_list +// | specifier_qualifier_list abstract_declarator + ; + +//abstract_declarator: +//// : pointer +// direct_abstract_declarator +//// | pointer direct_abstract_declarator +// ; + +//direct_abstract_declarator: +//// : '(' abstract_declarator ')' +// '[' ']' +// | '[' assignment_expression ']' +// | direct_abstract_declarator '[' ']' +// | direct_abstract_declarator '[' assignment_expression ']' +// | '[' '*' ']' +// | direct_abstract_declarator '[' '*' ']' +// | '(' ')' +// | '(' parameter_list ')' +// | direct_abstract_declarator '(' ')' +// | direct_abstract_declarator '(' parameter_list ')' +// ; + +initializer: + assignment_expression + | '{' initializer_list '}' + | '{' initializer_list ',' '}' + ; + +initializer_list + : initializer + | designation initializer + | initializer_list ',' initializer + | initializer_list ',' designation initializer + ; + +designation + : designator_list '=' + ; + +designator_list + : designator + | designator_list designator + ; + +designator + : '[' expression ']' + | '.' id + ; + +statement: +// labeled_statement + pass_fail_statement + | compound_statement + | expression_statement + | selection_statement + | iteration_statement +// | jump_statement + ; + +//labeled_statement +// : id ':' statement +// | CASE constant_expression ':' statement +// | DEFAULT ':' statement +// ; + +compound_statement + : '{' '}' + | '{' block_item_list '}' + ; + +block_item_list + : block_item + | block_item_list block_item + ; + +block_item + : declaration + | statement + ; + +expression_statement + : ';' + | expression ';' + ; + +selection_statement: + IF '(' expression ')' statement %prec NO_ELSE + | IF '(' expression ')' statement ELSE statement +// | SWITCH '(' expression ')' statement + ; + +iteration_statement: +// : WHILE '(' expression ')' statement +// | DO statement WHILE '(' expression ')' ';' + FOR '(' expression_statement expression_statement ')' statement + | FOR '(' expression_statement expression_statement expression ')' statement + | FOR '(' declaration expression_statement ')' statement + | FOR '(' declaration expression_statement expression ')' statement + ; + +//jump_statement +// : GOTO id ';' +// | CONTINUE ';' +// | BREAK ';' +// | RETURN ';' +// | RETURN expression ';' +// ; + +//function_definition +// : declaration_specifiers declarator declaration_list compound_statement +// | declaration_specifiers declarator compound_statement +// ; + +//declaration_list +// : declaration +// | declaration_list declaration +// ; + +id: + ID + ; + +//bit_range: +// ID '[' constant ']' +// | ID '[' constant ':' constant ']' +// ; + +constant: + CONSTANT + | HEX_CONST + | VLOG_CONST + | QSTRING + ; +%% diff --git a/fsl/fsl_interp/src/fsl.y.sav b/fsl/fsl_interp/src/fsl.y.sav new file mode 100644 index 00000000..f9bf03bf --- /dev/null +++ b/fsl/fsl_interp/src/fsl.y.sav @@ -0,0 +1,356 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file Fsl.y bison grammar for FSL +// ---------------------------------------------------------------- +// Simplified grammar with ID location info and symbol table +// +// There are no expected r/r s/r conflicts in this grammar. +// Future: %language, variant api, unique_ptr +// ---------------------------------------------------------------- +%{ +#include "fslparser.h" + +#include +#include +#include +#include +#include +#include +using namespace std; + +extern FslParser *FP; + +extern int yylex(); +extern int yyparse(); +extern FILE *yyin; +extern char *yytext; +extern void yyerror(const char *s); +//std::vector sequence_lines; + +%} + +%union { + int ival; + float fval; + char *sval; + std::string *str; +} + +%token CONSTRAINTS +%token CONVERSION +%token EMIT +%token ENCODE_ORDER +%token ENCODING +%token FAIL +%token FUSION +%token GPR +%token IF +%token INPUT_SEQ +%token INSTR +%token IOPUT +%token ISA +%token MNEMONIC +%token OPT_TOKEN +%token PASS +%token PROLOG +%token REQ_TOKEN +%token RET +%token S0 S1 +%token SEQUENCE +%token TRANSFORM +%token UARCH +%token UID +%token EQ +%token NEQ +%token LE +%token GE +%token TRUE +%token FALSE + +%token UN_CONST S_CONST +%token HEX_CONST +//%type id +%token DEC_NUM +%token INT +%token FLOAT +%token QSTRING +%token ID + +%locations +%start top + +%% +top: + source_line + | top source_line + ; + +source_line: + transform_decl + | prolog_decl + ; + +transform_decl: + TRANSFORM id '{' '}' + | TRANSFORM id '{' transform_statements '}' + ; + +transform_statements: + transform_statement + | transform_statements transform_statement + ; + +transform_statement: + PROLOG id + | isa_decl + | uarch_decl + | ioput_decl + | variable_decl + | sequence_decl + | constraints_decl + | conversion_decl + ; + +prolog_decl: + PROLOG id '{' '}' + | PROLOG id '{' prolog_statements '}' + ; + +prolog_statements: + prolog_statement + | prolog_statements prolog_statement + ; + +prolog_statement: + ISA id + | UARCH id + | IOPUT id + ; + +isa_decl: ISA id ; +uarch_decl: UARCH id ; +ioput_decl: IOPUT id ; + +sequence_decl: + SEQUENCE '{' uid_list '}' + | SEQUENCE id '{' sequence_statements '}' + | SEQUENCE id '(' id_list ')' '{' '}' + | SEQUENCE id '(' id_list ')' '{' sequence_statements '}' + | SEQUENCE id '{' uid_list '}' + ; + +constraints_decl: + CONSTRAINTS id '{' constraints_statements '}' + | CONSTRAINTS id '(' id_list ')' '{' '}' + | CONSTRAINTS id '(' id_list ')' '{' constraints_statements '}' + ; + +conversion_decl: + CONVERSION id '{' conversion_statements '}' + | CONVERSION id '(' id_list ')' '{' '}' + | CONVERSION id '(' id_list ')' '{' conversion_statements '}' + ; + +sequence_statements: + sequence_statement + | sequence_statements sequence_statement + ; + +sequence_statement: + assembly_source_line + ; + +assembly_source_line: + mnem number + | mnem operand ',' '(' operand ')' + | mnem operand ',' number + | mnem operand ',' number '(' operand ')' + | mnem operand ',' operand + | mnem operand ',' operand '(' operand ')' + | mnem operand ',' operand ',' number + | mnem operand ',' operand ',' operand + ; + +mnem: id ; +operand: id ; + +constraints_statements: + constraints_statement + | constraints_statements constraints_statement + ; + +constraints_statement: + method_call + | pass_fail_statement + | expression + ; + +pass_fail_statement: + PASS + | FAIL + ; + +conversion_statements: + conversion_statement + | conversion_statements conversion_statement + ; + +conversion_statement: + instr_decl + | instr_update + ; + +instr_decl: + INSTR id + ; + +instr_update: + id '(' id_list ')' + { + } + ; + +method_call: + chained_routines '(' id ')' + ; + +chained_routines: + id + | chained_routines '.' id + ; + +variable_decl: + GPR id_list + | UN_CONST id_list + | S_CONST id_list + ; + +id_list: + id_expression + | id_list ',' id_expression + ; + +id_expression: + id + | QSTRING +// | assignment_expression +// | method_expression + ; + +uid_list: + UID + | uid_list UID + ; + +number: + HEX_CONST + | DEC_NUM + ; + +id: + ID + ; + +//assignment_expression: +// id '=' number +// | id '=' QSTRING +// ; +// +//method_expression: +// id '(' id ')' +// | id '(' QSTRING ')' +// ; + +expression : expression + | '!' expression + | number + | id + | TRUE + | FALSE + ; // Terminal cases (leaf elements) + +//expression: +// '(' expression ')' +// | expression EQ expression +// | expression NEQ expression +// | expression LE expression +// | expression GE expression +// | expression '>' expression +// | expression '<' expression +// | expression '&' expression +// | expression '|' expression +// | expression '^' expression +//; + +//assignment_expression +// : MNEMONIC '=' QSTRING +// | id '=' number +// ; +// +//expression: +// assignment_expression +// | logical_or_expression +// | logical_and_expression +// | equality_expression +// ; +// +//assignment_expression: +// logical_or_expression +// | unary_expression '=' assignment_expression +// ; +// +//logical_or_expression: +// logical_and_expression +// | logical_or_expression '|' logical_and_expression +// ; +// +//logical_and_expression +// : equality_expression +// | logical_and_expression '&' equality_expression +// ; +// +//equality_expression +// : relational_expression +// | equality_expression EQ relational_expression +// | equality_expression NEQ relational_expression +// ; +// +//relational_expression +// : additive_expression +// | relational_expression '<' additive_expression +// | relational_expression '>' additive_expression +// | relational_expression LE additive_expression +// | relational_expression GE additive_expression +// ; +// +//additive_expression +// : multiplicative_expression +// | additive_expression '+' multiplicative_expression +// | additive_expression '-' multiplicative_expression +// ; +// +//multiplicative_expression +// : unary_expression +// | multiplicative_expression '*' unary_expression +// | multiplicative_expression '/' unary_expression +// | multiplicative_expression '%' unary_expression +// ; +// +//unary_expression +// : postfix_expression +// | '-' unary_expression +// | '!' unary_expression +// ; +// +//postfix_expression +// : primary_expression +// ; +// +//primary_expression +// : id +// | number +// | '(' expression ')' +// ; + +%% diff --git a/fsl/fsl_interp/src/main.cpp b/fsl/fsl_interp/src/main.cpp new file mode 100644 index 00000000..a2053b69 --- /dev/null +++ b/fsl/fsl_interp/src/main.cpp @@ -0,0 +1,29 @@ +#include "Options.h" +#include "Msg.h" +#include "FslParser.h" +#include + +Options *Options::instance = 0; +std::shared_ptr opts(Options::getInstance()); + +Msg *Msg::instance = 0; +std::unique_ptr msg(Msg::getInstance()); + +FslParser *FP; + +int main(int ac,char **av) { + opts->setupOptions(ac,av); + FslParser fsl; + + if(opts->trace_en) fsl.TRACE_EN = true; + + fsl.parse(); +// std::cout << "Starting parser...\n"; +// if (yyparse() == 0) { // Call the parse function +// std::cout << "Parsing complete!\n"; +// } else { +// std::cerr << "Parsing failed.\n"; +// } + return 0; +} + diff --git a/fsl/test/CMakeLists.txt b/fsl/test/CMakeLists.txt new file mode 100644 index 00000000..eca4ffa5 --- /dev/null +++ b/fsl/test/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.10) +project(Test) + +# Include subdirectories +add_subdirectory(api) +add_subdirectory(interp) + +# Add test targets +add_custom_target(run_test_interp + COMMAND ${CMAKE_COMMAND} + --build ${CMAKE_CURRENT_BINARY_DIR}/interp --target run_interp_tests + COMMENT "Running interp tests" +) + +add_custom_target(run_test_api + COMMAND ${CMAKE_COMMAND} + --build ${CMAKE_CURRENT_BINARY_DIR}/api --target run_api_tests + COMMENT "Running API tests" +) + +# Add the regress target to run all tests +# Customize the name to avoid conflict with Oly's regress +add_custom_target(fsl_regress ALL + DEPENDS run_test_interp run_test_api + COMMENT "Running all tests" +) + diff --git a/fsl/test/Makefile b/fsl/test/Makefile new file mode 100644 index 00000000..90c18e0c --- /dev/null +++ b/fsl/test/Makefile @@ -0,0 +1,17 @@ +.PHONY: default regress test test_interp test_api + +include ../Vars.mk + +default: regress +test: regress +regress: test_interp test_api + +test_interp: + $(MAKE) -C interp test + +test_api: + $(MAKE) -C api test + +clean: + $(MAKE) -C interp clean + $(MAKE) -C api clean diff --git a/fsl/test/api/CMakeLists.txt b/fsl/test/api/CMakeLists.txt new file mode 100644 index 00000000..d3351528 --- /dev/null +++ b/fsl/test/api/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 3.10) +project(TestApi) + +# Include directories +include_directories( + inc + ../common + ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/modules/cpm.mavis +) + +# Source files +#file(GLOB ALL_SRC "src/*.cpp") +set(ALL_SRC + src/ApiTestBench.cpp + src/main.cpp + src/FslTests.cpp + src/TestData.cpp + src/TestFieldExtractor.cpp + src/Options.cpp +) + +# Add executable +add_executable(test_api_exec ${ALL_SRC}) +target_include_directories(test_api_exec + PRIVATE + ${CMAKE_SOURCE_DIR}/fsl/test/common + ${CMAKE_SOURCE_DIR} +) +target_link_libraries(test_api_exec fslinterp mavis boost_program_options) + +set(ISA_FILES --isa_file ./json/isa_rv64g.json --isa_file ./json/isa_rv64c.json) + + +# Define the test target +add_custom_target(run_api_tests + COMMAND test_api_exec + --fsl_syntax_file ./fsl/test1.fsl + --isa_file ./json/isa_rv64g.json + --isa_file ./json/isa_rv64c.json + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Running API tests" +) + +# Ensure the necessary libraries and executable are built before running tests +add_dependencies(run_api_tests test_api_exec fslinterp mavis) diff --git a/fsl/test/api/Makefile b/fsl/test/api/Makefile new file mode 100644 index 00000000..5cf74ef3 --- /dev/null +++ b/fsl/test/api/Makefile @@ -0,0 +1,67 @@ +.PHONY: clean default run +include ../../Vars.mk + +FSL_INC = -I../.. +MAVIS_INC = -I../../modules/cpm.mavis +CMN_INC = -I../common +INTERP_LIB = -L../../fsl_interp/lib -lfslinterp +MAVIS_LIB = -L../../modules/cpm.mavis/release -lmavis + +ALL_SRC = $(wildcard src/*.cpp) +SRC_OBJ = $(subst src,obj,$(ALL_SRC:.cpp=.o)) +ALL_OBJ = $(SRC_OBJ) +TARGET = bin/fsttst + +INC = -I./inc $(CMN_INC) $(FSL_INC) $(MAVIS_INC) -I./obj +LIBS = $(INTERP_LIB) $(MAVIS_LIB) -lboost_program_options + +CFLAGS = $(INC) +LDFLAGS = + +default: test + +only: $(TARGET) + +$(INTERP_LIB): + $(MAKE) -C ../../fsl_interp lib_only + +$(TARGET): $(ALL_OBJ) $(INTERP_LIB) + @mkdir -p bin + $(CXX) $(LDFLAGS) $^ -o $@ $(LIBS) + +obj/%.o : src/%.cpp + $(CXX) -c $(CFLAGS) $< -o $@ + +obj/yy.tab.o: $(BISON_OUT) + $(CXX) -c $(CFLAGS) $< -o $@ + +obj/lex.yy.o: $(FLEX_OUT) + $(CXX) -c $(CFLAGS) $< -o $@ + +# Bison build rule, generating both .c and .h files +$(BISON_OUT) $(BISON_H): $(BISON_SRC) + @mkdir -p obj + $(BISON) $(BISONFLAGS) $(BISON_SRC) -o $(BISON_OUT) + +# Flex build rule, depends on Bison header +$(FLEX_OUT): $(FLEX_SRC) $(BISON_H) + @mkdir -p obj + $(FLEX) -o $(FLEX_OUT) $(FLEX_SRC) + +#TRACE=--trace_en +ISA_FILES = --isa_file ./json/isa_rv64g.json \ + --isa_file ./json/isa_rv64c.json + +FSL_SYNTAX_FILES = --fsl_syntax_file ./fsl/test1.fsl + +test: $(TARGET) + $(TARGET) --tb_verbose \ + $(ISA_FILES) $(FSL_FILES) $(FSL_SYNTAX_FILES) $(TRACE) + +help-%: + @echo $* = $($*) + +clean: + rm -f ./bin/* ./obj/* + + diff --git a/fsl/test/api/fsl/syntax1.fsl b/fsl/test/api/fsl/syntax1.fsl new file mode 100644 index 00000000..b4cbd2f8 --- /dev/null +++ b/fsl/test/api/fsl/syntax1.fsl @@ -0,0 +1,12 @@ +// Empty definition +/* + Block comment +*/ +fusion fs1 { //end of line +/* in line block */ +} + +fusion /* messy keywords */ fs2 /* messy symbols */ { +/* in line block */ +/* here */ } // +// end of file comment diff --git a/fsl/test/api/fsl/syntax2.fsl b/fsl/test/api/fsl/syntax2.fsl new file mode 100644 index 00000000..3416dd8e --- /dev/null +++ b/fsl/test/api/fsl/syntax2.fsl @@ -0,0 +1,36 @@ +//This is the common test case +fusion fs1 { + + isa rv64g + uarch oly1 + input_seq in_seq + + sequence seq1(in_seq,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + _req_ + c.xor g2, g2, g1 + c.slli g2, g2, c3 + _opt_ + c.srli g2, c3 + } + + constraints cons1(seq1,in_seq,rv64g,oly1) { + gpr g1,g2 + g1 != g2 + } + + transform t1(seq1,cons1) { + encoding word1(seq1,opc) { + u10 opc //57:48 unsigned 10b + u6 c3 //47:42 unsigned 6b + s12 c2 //41:30 signed 12b + s20 c1 //29:10 signed 20b + gpr g1 //9:5 gpr 5b + gpr g2 //4:0 gpr 5b + encode_order(opc,c3,c2,c1,g1,g2) + } + emit(word1(seq1,opc=0x234)) + } +} + diff --git a/fsl/test/api/fsl/test1.fsl b/fsl/test/api/fsl/test1.fsl new file mode 100644 index 00000000..04a9c509 --- /dev/null +++ b/fsl/test/api/fsl/test1.fsl @@ -0,0 +1,35 @@ +// ========================================================= +// ========================================================= +transform fs1 +{ + isa rv64g + uarch oly1 + ioput in_seq + + gpr g1,g2 + + sequence seq1(in_seq,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + c.xor g2, g2, g1 + c.slli g2, g2, c3 + c.srli g2, c3 + } + + constraints cons1(seq1,in_seq,rv64g,oly1) { + g1 != g2 + } + + u10 _opc(0x234) //57:48 unsigned 10b + u6 c3 //47:42 unsigned 6b + s12 c2 //41:30 signed 12b + s20 c1 //29:10 signed 20b + gpr g1 //9:5 gpr 5b + gpr g2 //4:0 gpr 5b + + conversion t1(seq1,cons1) { + encoding word1 + word1.opc(_opc) + word1.encode_order({opc,c3,c2,c1,g1,g2}) + } +} diff --git a/fsl/test/api/fsl/test2.fsl b/fsl/test/api/fsl/test2.fsl new file mode 100644 index 00000000..7e1cad89 --- /dev/null +++ b/fsl/test/api/fsl/test2.fsl @@ -0,0 +1,46 @@ +fusion fs1 { + + isa rv64g + uarch oly1 + input_seq in_seq + + sequence seq1(in_seq,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + _req_ + c.xor g2, g2, g1 + c.slli g2, g2, c3 + _opt_ + c.srli g2, c3 + } + + constraints cons1(seq1,in_seq,rv64g,oly1) { + gpr g1,g2 + g1 != g2 + } + + transform t1(seq1,cons1) { + encoding word1(seq1,opc) { + u10 opc //57:48 unsigned 10b + u6 c3 //47:42 unsigned 6b + s12 c2 //41:30 signed 12b + s20 c1 //29:10 signed 20b + gpr g1 //9:5 gpr 5b + gpr g2 //4:0 gpr 5b + encode_order(opc,c3,c2,c1,g1,g2) + } + emit(word1(seq1,opc=0x234)) + } +} + +//Future feature allow flat decl of fusion elements +//sequence seq1(input_seq in_seq,isa rv64g) +//{ +// c.lui g1, c1 +// c.addi g1, g1, c2 +// _req_ +// c.xor g2, g2, g1 +// c.slli g2, g2, c3 +// _opt_ +// c.srli g2, c3 +//} diff --git a/fsl/test/api/fsl/test3.fsl b/fsl/test/api/fsl/test3.fsl new file mode 100644 index 00000000..a21315bf --- /dev/null +++ b/fsl/test/api/fsl/test3.fsl @@ -0,0 +1,46 @@ +// ========================================================= +// ========================================================= +fusion fs1 { + + isa rv64g + uarch oly1 + input_seq in_seq + sequence seq1(in_seq,rv64g) + constraints cons1(seq1,in_seq,rv64g,oly1) + transform t1(seq1,cons1) + +} + +//proto sequence _id_(input_seq,isa) +sequence seq1(in_seq,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + c.xor g2, g2, g1 + c.slli g2, g2, c3 + c.srli g2, c3 +} + +//proto constraints _id_(sequence,input_seq,isa,uarch) +constraints cons1(seq1,in_seq,rv64g,oly1) { + gpr g1,g2 + g1 != g2 +} + +//proto transform _id_(sequence,constraints) +transform t1(seq1,cons1) { + encoding word1(seq1,opc=0x234) +// emit(word1) +} + +//proto encoding _id_(sequence,constant) +encoding word1(seq1,opc) { + u10 opc //57:48 unsigned 10b + u6 c3 //47:42 unsigned 6b + s12 c2 //41:30 signed 12b + s20 c1 //29:10 signed 20b + gpr g1 //9:5 gpr 5b + gpr g2 //4:0 gpr 5b + + //this is an operator not a function + encode_order(opc,c3,c2,c1,g1,g2) +} diff --git a/fsl/test/api/fsl/test4.fsl b/fsl/test/api/fsl/test4.fsl new file mode 100644 index 00000000..94e030d2 --- /dev/null +++ b/fsl/test/api/fsl/test4.fsl @@ -0,0 +1,75 @@ +// ========================================================= +// ========================================================= +fusion fs1 { + sequence seq1 { + c.lui g1, c1 + c.addi g1, g1, c2 + c.xor g2, g2, g1 + c.slli g2, g2, c3 + c.srli g2, c3 + } + + constraints cons1 { + gpr g1,g2 + s20 c1 + s12 c2 + u6 c3 + + g1 != g2 + } + + iword word1 { + u1 f //59 1b + u1 c //58 1b + u10 fopc //57:48 unsigned 10b + u6 c3 //47:42 unsigned 6b + s12 c2 //41:30 signed 12b + s20 c1 //29:10 signed 20b + gpr g1 //9:5 gpr 5b + gpr g2 //4:0 gpr 5b + + encode_order(f,c,fopc,c3,c2,c1,g1,g2) + } + + transform T1 { + encoding word1(f=1,c=0,S1) + } +} +// ========================================================= +sequence S1_A { + li g1,c1 + li g2,c1 + li g3,c1 + li g4,c1 +} + +constraints C1_A { + gpr g1,g2,g3,g4 + u12 c1 + g1 != g2 != g3 != g4 + c1 == 0 +} + +iword word2 { + u1 f //59 1b + u1 c //58 1b + u10 fopc //57:48 unsigned 10b + u6 c3 //47:42 unsigned 6b + s12 c2 //41:30 signed 12b + s20 c1 //29:10 signed 20b + gpr g1 //9:5 gpr 5b + gpr g2 //4:0 gpr 5b + + encode_order(f,c,fopc,c3,c2,c1,g1,g2) +} + +transform T1 { + encoding word2(f=1,c=0,S1) +} + +fusion fs2 { + sequence S1_A() + constraints C1_A(S1_A) + transform T1_A(S1_A) +} + diff --git a/fsl/test/api/fsl/test5.fsl b/fsl/test/api/fsl/test5.fsl new file mode 100644 index 00000000..57589468 --- /dev/null +++ b/fsl/test/api/fsl/test5.fsl @@ -0,0 +1,78 @@ +// ------------------------------------ +// Known encoding for fusable sequences +// +// Work in progress +// ------------------------------------ + +// ------------------------------------ +// Example fusion declaration +// ------------------------------------ +fusion fs1 { + sequence S1 { + c.lui g1, c1 + c.addi g1, g1, c2 + c.xor g2, g2, g1 + c.slli g2, g2, c3 + c.srli g2, c3 + } +} +// constraints C1 { +// gpr g1,g2 +// s20 c1 +// s12 c2 +// u6 c3 +// +// g1 != g2 +// } +// iword W1 { +// u1 f //59 1b +// u1 c //58 1b +// u10 fopc //57:48 unsigned 10b +// u6 c3 //47:42 unsigned 6b +// s12 c2 //41:30 signed 12b +// s20 c1 //29:10 signed 20b +// gpr g1 //9:5 gpr 5b +// gpr g2 //4:0 gpr 5b +// +// encode_order(f,c,fopc,c3,c2,c1,g1,g2) +// } +// +// transform T1 { +// //60b fused op encoding +// encoding W1(f=1,c=0,S1) +// } +//} + +//sequence S1_A { +// li g1,c1 +// li g2,c1 +// li g3,c1 +// li g4,c1 +//} +// +//constraints C1_A(sequence S) { +// gpr g1,g2,g3,g4 +// u12 c1 +// S.g1 != S.g2 != S.g3 != S.g4 +// S.c1 == 0 +//} +// +//transform T1_A(sequence S,constraints C) { +// iword<8> +// +//} +// +// +//transform T1_A(sequence S,constraints C) { +// encoding.r_type enc +// encoding.custom(8) addendum +// encoding.custom(40) fused +// +//} +// +//fs2 { +// sequence S1_A +// constraints C1_A +// transform T1_A(S1_A,C1_A) +//} + diff --git a/fsl/test/api/inc/ApiTestBench.h b/fsl/test/api/inc/ApiTestBench.h new file mode 100644 index 00000000..86a66e0a --- /dev/null +++ b/fsl/test/api/inc/ApiTestBench.h @@ -0,0 +1,277 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file TestBench.h testbench interface and utils +#pragma once +#include "fsl_api/FieldExtractor.h" +#include "fsl_api/Fusion.h" +#include "fsl_api/FusionGroup.h" +#include "fsl_api/FusionTypes.h" +#include "fsl_api/MachineInfo.h" +#include +#include +//! \class TestBench +// ==================================================================== +// ==================================================================== +//! \brief local test bench for Fusion and related classes +struct TestBench +{ + //! \brief save typing + using FusionGroupType = + fusion::FusionGroup; + //! \brief save typing + using FusionGroupListType = std::vector; + + //! \brief save typing + using FusionGroupCfgType = + fusion::FusionGroupCfg; + + //! \brief save typing + using FusionType = + fusion::Fusion; + + //! \brief save typing + using InstUidListType = fusion::InstUidListType; + + //! \brief save typing + using InstPtrListType = fusion::InstPtrListType; + + //! \brief save typing + using FileNameListType = fusion::FileNameListType; + + //! \brief save typing + using Opcode = fusion::Opcode; + + //! \brief save typing + using OpcodeListType = fusion::OpcodeListType; + + //! \brief save typing + using MavisType = fusion::MavisType; + + //! \brief ctor with boost program_option support + TestBench(int, char**); + + //! \brief hold functor proxies used by the tb + struct cbProxy; + + //! \brief run all tests + bool run(); + + //! \brief sanity check compilation of ctors + bool fusionCtorCompileTest(bool debug = false); + + //! \brief basic find fusiongroup, match to input, and transform + bool fusionSearchTest(bool debug = false); + + //! \brief sanity check the way mavis and isa files supplied are used + bool basicMavisTest(bool debug = false); + + //! \brief check constraints and perform simple transform + bool basicConstraintsTest(); + + //! \brief test using alternatives to MachineInfo and FieldExtractor + bool fusionGroupAltCtorTest(); + + //! \brief test choices in specifying FusionGroupCfg + bool fusionGroupCfgCtorTest(); + + //! \brief unit test for class::FusionContext + bool fusionContextTest(bool debug = false); + + //! \brief unit test for class::RadixTrie + bool radixTrieTest(bool debug = false); + + //! \brief catch all for start up checks + bool sanityTest(bool debug = false); + + // ------------------------------------------------------------- + // field extractor method tests and support, testfieldextractor.cpp + // ------------------------------------------------------------- + //! \brief top level extractor test runner + bool fieldExtractorTests(bool debug = false); + + //! \brief create an inst from opcode, catch conversion errors + FieldExtractor::InstPtrType makeInst(MavisType &, uint32_t); + + //! \brief helper for testing field values + bool testFieldValue(uint32_t, std::string, uint32_t act,uint32_t exp); + + // ------------------------------------------------------------- + // fusion domain language tests and support + // ------------------------------------------------------------- + //! \brief this calls the fsl sub-tests + bool fslTests(bool debug = false); + + //! \brief simple sanity check on interpreter linking + //! + //! See fsl/test/interp for more extensive syntax checking + bool fslInterpQuickTest(bool debug = false); + + //! \brief support for fsl_syntax_test + bool checkSyntax(std::vector &, bool debug = false); + + //! \brief return true if files are identical + //! + //! whitespace is significant + bool compareFiles(const std::string,const std::string,bool=true); + // ------------------------------------------------------------- + + //! \brief transform funcs + static bool f1_constraints(FusionGroupType &, InstPtrListType &, + InstPtrListType &); + + //! \brief assign to InstPtrListType from opcodes + void assign(InstPtrListType &, std::vector &, + const FileNameListType &); + //! \brief info debug function + void info(InstUidListType &, InstUidListType &, InstPtrListType &); + + //! \brief support golden reference hashes + void generateExpectHashes( + std::unordered_map &, + const FusionType::FusionGroupCfgListType &); + + //! \brief duplicate of hash function found in fusion group + //! + //! duplicated to support debug + fusion::HashType jenkinsOneAtATime(const std::vector &); + + //! \brief common isa files to separate from the cmd line versions + static const std::vector stdIsaFiles; + + //! \brief extra messages + bool verbose{false}; + + //! \brief zoo.F1 example fusion group + //! + //! This is from the fusion group zoo, F1 has three variants. There are + //! three forms for each, opcode, uid, and asm text. I'm trying out + //! various methods for a user to express a fusion group when not using + //! the DSL. Note all of these will be needed. + //! @{ + static InstUidListType uf1, uf1_1, uf1_2, uf1_3; + static OpcodeListType of1, of1_1, of1_2, of1_3; + //! @} + + //! \brief zoo.F2 example fusion group + //! @{ + static InstUidListType uf2; + static OpcodeListType of2; + //! @} + + //! \brief zoo.F3 example fusion group + //! @{ + static InstUidListType uf3; + static OpcodeListType of3; + //! }@ + + //! \brief zoo.F4 example fusion group + //! @{ + static InstUidListType uf4; + static OpcodeListType of4; + //! }@ + + //! \brief zoo.F5 example fusion group and three variants + //! @{ + static InstUidListType uf5, uf5_1, uf5_2, uf5_3; + static OpcodeListType of5, of5_1, of5_2, of5_3; + //! }@ + + static const std::vector std_isa_files; +}; + +// --------------------------------------------------------------------- +//! \brief call back proxies used in the unit test(s) +//! +//! There is a callback for each fusion group test case f1, f1.1, etc +// --------------------------------------------------------------------- +struct TestBench::cbProxy +{ + //! \brief ... + static bool uf1_func(FusionGroupType &, InstPtrListType &, + InstPtrListType &) + { + cout << "HERE uf1_func called" << endl; + return true; + } + + //! \brief ... + static bool uf1_1_func(FusionGroupType &, InstPtrListType &, + InstPtrListType &) + { + cout << "HERE uf1_1_func called" << endl; + return true; + } + + //! \brief ... + static bool uf1_2_func(FusionGroupType &, InstPtrListType &, + InstPtrListType &) + { + cout << "HERE uf1_2_func called" << endl; + return true; + } + + //! \brief ... + static bool uf1_3_func(FusionGroupType &, InstPtrListType &, + InstPtrListType &) + { + cout << "HERE uf1_3_func called" << endl; + return true; + } + + //! \brief ... + static bool uf2_func(FusionGroupType &, InstPtrListType &, + InstPtrListType &) + { + cout << "HERE uf2_func called" << endl; + return true; + } + + //! \brief ... + static bool uf3_func(FusionGroupType &, InstPtrListType &, + InstPtrListType &) + { + cout << "HERE uf3_func called" << endl; + return true; + } + + //! \brief ... + static bool uf4_func(FusionGroupType &, InstPtrListType &, + InstPtrListType &) + { + cout << "HERE uf4_func called" << endl; + return true; + } + + //! \brief ... + static bool uf5_func(FusionGroupType &, InstPtrListType &, + InstPtrListType &) + { + cout << "HERE uf5_func called" << endl; + return true; + } + + //! \brief ... + static bool uf5_1_func(FusionGroupType &, InstPtrListType &, + InstPtrListType &) + { + cout << "HERE uf5_1_func called" << endl; + return true; + } + + //! \brief ... + static bool uf5_2_func(FusionGroupType &, InstPtrListType &, + InstPtrListType &) + { + cout << "HERE uf5_2_func called" << endl; + return true; + } + + //! \brief ... + static bool uf5_3_func(FusionGroupType &, InstPtrListType &, + InstPtrListType &) + { + cout << "HERE uf5_3_func called" << endl; + return true; + } +}; diff --git a/fsl/test/api/inc/Options.h b/fsl/test/api/inc/Options.h new file mode 100644 index 00000000..37ec657a --- /dev/null +++ b/fsl/test/api/inc/Options.h @@ -0,0 +1,83 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file Options.hpp testbench options +#pragma once +#include +#include +#include +#include +namespace po = boost::program_options; + +//! \brief container for boost program option settings +struct Options +{ + // ---------------------------------------------------------------- + //! \brief singleton + // ---------------------------------------------------------------- + static Options* getInstance() + { + if (!instance) + instance = new Options(); + return instance; + } + + // ---------------------------------------------------------------- + // support methods + // ---------------------------------------------------------------- + //! \brief ... + void buildOptions(po::options_description &); + + //! \brief ... + bool checkOptions(po::variables_map &, po::options_description &,bool); + + //! \brief ... + void setupOptions(int, char**); + + //! \brief ... + void usage(po::options_description & o) const + { + std::cout << o << std::endl; + } + + //! \brief ... + void version() const; + + // ---------------------------------------------------------------- + //! \brief future STF file support in test bench + std::string stf_file{""}; + //! \brief ... + std::string output_file{""}; + //! \brief ... + std::vector isa_files; + //! \brief ... + std::vector fsl_files; + //! \brief files with contorted style + std::vector fsl_syntax_files; + //! \brief enable extra messages from the tb + bool tb_verbose{false}; + // ---------------------------------------------------------------- + // ---------------------------------------------------------------- + //! \brief ... + bool notify_error{false}; + //! \brief placeholder + bool _query_options{false}; + //! \brief ... + po::variables_map vm; + //! \brief ... + static Options* instance; + + private: + //! \brief ... + Options() {} + + //! \brief ... + Options(const Options &) = delete; + //! \brief ... + Options(Options &&) = delete; + //! \brief ... + Options & operator=(const Options &) = delete; +}; + +//! \brief ... +extern std::shared_ptr opts; diff --git a/fsl/test/api/json/isa_rv64c.json b/fsl/test/api/json/isa_rv64c.json new file mode 100644 index 00000000..76e7a6f2 --- /dev/null +++ b/fsl/test/api/json/isa_rv64c.json @@ -0,0 +1,293 @@ +[ + { + "mnemonic" : "c.addi4spn", + "tags" : ["c"], + "expand" : "addi", + "form" : "C0", + "ignore" : ["func2A"], + "xform" : "CIW_sp", + "stencil" : "0x0" + }, + { + "mnemonic" : "c.lw", + "tags" : ["c"], + "expand" : "lw", + "form" : "C0", + "ignore" : ["func2A"], + "xform" : "C0_load_word", + "stencil" : "0x4000" + }, + { + "mnemonic" : "c.ld", + "tags" : ["c"], + "expand" : "ld", + "form" : "C0", + "ignore" : ["func2A"], + "xform" : "C0_load_double", + "stencil" : "0x6000" + }, + { + "mnemonic" : "c.sw", + "tags" : ["c"], + "expand" : "sw", + "form" : "C0", + "ignore" : ["func2A"], + "xform" : "C0_store_word", + "stencil" : "0xc000" + }, + { + "mnemonic" : "c.sd", + "tags" : ["c"], + "expand" : "sd", + "form" : "C0", + "ignore" : ["func2A"], + "xform" : "C0_store_double", + "stencil" : "0xe000" + }, + { + "mnemonic" : "c.addi", + "tags" : ["c"], + "expand" : "addi", + "form" : "C1", + "ignore" : ["func2", "func1", "func2b"], + "xform" : "CI_addi", + "stencil" : "0x1" + }, + { + "mnemonic" : "c.nop", + "tags" : ["c"], + "expand" : "nop", + "form" : "C1", + "ignore" : ["func1", "func2b"], + "fixed" : [ "rs1" ], + "xform" : "CI_addi", + "stencil" : "0x1" + }, + { + "mnemonic" : "c.addi16sp", + "tags" : ["c"], + "expand" : "addi", + "form" : "C1", + "ignore" : ["func1", "func2b"], + "fixed" : [ "rs1" ], + "xform" : "CI_sp", + "stencil" : "0x6101" + }, + { + "mnemonic" : "c.jr", + "tags" : ["c"], + "expand" : "jalr", + "form" : "C2", + "fixed" : ["rs2"], + "xform" : "CJR", + "stencil" : "0x8002" + }, + { + "mnemonic" : "c.addiw", + "tags" : ["c"], + "expand" : "addiw", + "form" : "C1", + "ignore" : ["func2", "func1", "func2b"], + "xform" : "CI_addiw", + "stencil" : "0x2001" + }, + { + "mnemonic" : "c.jalr", + "tags" : ["c"], + "expand" : "jalr", + "form" : "C2", + "fixed" : ["rs2"], + "xform" : "CJALR", + "stencil" : "0x9002" + }, + { + "mnemonic" : "c.li", + "tags" : ["c"], + "expand" : "li", + "form" : "C1", + "ignore" : ["func2", "func1", "func2b"], + "xform" : "CI_rD_only", + "stencil" : "0x4001" + }, + { + "mnemonic" : "c.lui", + "tags" : ["c"], + "expand" : "lui", + "form" : "C1", + "ignore" : ["func2", "func1", "func2b"], + "xform" : "CI_rD_shifted", + "stencil" : "0x6001" + }, + { + "mnemonic" : "c.srli", + "tags" : ["c"], + "expand" : "srli", + "form" : "C1", + "ignore" : ["func1", "func2b"], + "xform" : "CIX", + "stencil" : "0x8001" + }, + { + "mnemonic" : "c.srai", + "tags" : ["c"], + "expand" : "srai", + "form" : "C1", + "ignore" : ["func1", "func2b"], + "xform" : "CIX", + "stencil" : "0x8401" + }, + { + "mnemonic" : "c.andi", + "tags" : ["c"], + "expand" : "andi", + "form" : "C1", + "ignore" : ["func1", "func2b"], + "xform" : "CIX_andi", + "stencil" : "0x8801" + }, + { + "mnemonic" : "c.sub", + "tags" : ["c"], + "expand" : "sub", + "form" : "C1", + "xform" : "CA", + "stencil" : "0x8c01" + }, + { + "mnemonic" : "c.xor", + "tags" : ["c"], + "expand" : "xor", + "form" : "C1", + "xform" : "CA", + "stencil" : "0x8c21" + }, + { + "mnemonic" : "c.or", + "tags" : ["c"], + "expand" : "or", + "form" : "C1", + "xform" : "CA", + "stencil" : "0x8c41" + }, + { + "mnemonic" : "c.and", + "tags" : ["c"], + "expand" : "and", + "form" : "C1", + "xform" : "CA", + "stencil" : "0x8c61" + }, + { + "mnemonic" : "c.subw", + "tags" : ["c"], + "expand" : "subw", + "form" : "C1", + "xform" : "CA", + "stencil" : "0x9c01" + }, + { + "mnemonic" : "c.addw", + "tags" : ["c"], + "expand" : "addw", + "form" : "C1", + "xform" : "CA", + "stencil" : "0x9c21" + }, + { + "mnemonic" : "c.j", + "tags" : ["c"], + "expand" : "jal", + "form" : "C1", + "ignore" : ["func2", "func1", "func2b"], + "xform" : "CJ", + "stencil" : "0xa001" + }, + { + "mnemonic" : "c.beqz", + "tags" : ["c"], + "expand" : "beq", + "form" : "C1", + "ignore" : ["func2", "func1", "func2b"], + "xform" : "CB", + "stencil" : "0xc001" + }, + { + "mnemonic" : "c.bnez", + "tags" : ["c"], + "expand" : "bne", + "form" : "C1", + "ignore" : ["func2", "func1", "func2b"], + "xform" : "CB", + "stencil" : "0xe001" + }, + { + "mnemonic" : "c.slli", + "tags" : ["c"], + "expand" : "slli", + "form" : "C2", + "ignore" : ["func1"], + "xform" : "C2_slli", + "stencil" : "0x2" + }, + { + "mnemonic" : "c.lwsp", + "tags" : ["c"], + "expand" : "lw", + "form" : "C2", + "ignore" : ["func1"], + "xform" : "C2_sp_load_word", + "stencil" : "0x4002" + }, + { + "mnemonic" : "c.ldsp", + "tags" : ["c"], + "expand" : "ld", + "form" : "C2", + "ignore" : ["func1"], + "xform" : "C2_sp_load_double", + "stencil" : "0x6002" + }, + { + "mnemonic" : "c.mv", + "tags" : ["c"], + "expand" : "add", + "form" : "C2", + "type" : ["move"], + "xform" : "C2_mv", + "stencil" : "0x8002" + }, + { + "mnemonic" : "c.ebreak", + "tags" : ["c"], + "expand" : "ebreak", + "form" : "C2", + "fixed" : [ "rs1", "rs2" ], + "stencil" : "0x9002" + }, + { + "mnemonic" : "c.add", + "tags" : ["c"], + "expand" : "add", + "form" : "C2", + "xform" : "C2_add", + "stencil" : "0x9002" + }, + { + "mnemonic" : "c.swsp", + "tags" : ["c"], + "expand" : "sw", + "form" : "C2", + "ignore" : ["func1"], + "xform" : "C2_sp_store_word", + "stencil" : "0xc002" + }, + { + "mnemonic" : "c.sdsp", + "tags" : ["c"], + "expand" : "sd", + "form" : "C2", + "ignore" : ["func1"], + "xform" : "C2_sp_store_double", + "stencil" : "0xe002" + } +] diff --git a/fsl/test/api/json/isa_rv64g.json b/fsl/test/api/json/isa_rv64g.json new file mode 100644 index 00000000..69d86be1 --- /dev/null +++ b/fsl/test/api/json/isa_rv64g.json @@ -0,0 +1,1354 @@ +[ + { + "mnemonic" : "beq", + "form" : "B", + "stencil" : "0x63", + "type" : ["branch", "cond"], + "l-oper" : "all" + }, + { + "mnemonic" : "bne", + "form" : "B", + "stencil" : "0x1063", + "type" : ["branch", "cond"], + "l-oper" : "all" + }, + { + "mnemonic" : "blt", + "form" : "B", + "stencil" : "0x4063", + "type" : ["branch", "cond"], + "l-oper" : "all" + }, + { + "mnemonic" : "bge", + "form" : "B", + "stencil" : "0x5063", + "type" : ["branch", "cond"], + "l-oper" : "all" + }, + { + "mnemonic" : "bltu", + "form" : "B", + "stencil" : "0x6063", + "type" : ["branch", "cond"], + "l-oper" : "all" + }, + { + "mnemonic" : "bgeu", + "form" : "B", + "stencil" : "0x7063", + "type" : ["branch", "cond"], + "l-oper" : "all" + }, + { + "mnemonic" : "jalr", + "form" : "I", + "stencil" : "0x67", + "type" : ["branch","jalr"], + "l-oper" : "all" + }, + { + "mnemonic" : "jal", + "form" : "J", + "stencil" : "0x6f", + "type" : ["branch","jal"], + "l-oper" : "all" + }, + { + "mnemonic" : "lui", + "form" : "U", + "stencil" : "0x37", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "auipc", + "form" : "U", + "stencil" : "0x17", + "type" : ["int", "arith", "pc"], + "l-oper" : "all" + }, + { + "mnemonic" : "addi", + "form" : "ISH", + "ignore" : ["func6"], + "xform" : "I", + "stencil" : "0x13", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "li", + "tags" : ["i", "g"], + "form" : "ISH", + "ignore" : ["func6"], + "xform" : "I", + "stencil" : "0x13", + "fixed" : ["rs1"], + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "nop", + "overlay" : { + "base" : "li", + "match" : ["0xFFFFFF80", "0x00000000"] + }, + "xform" : "I", + "type" : ["int", "arith"] + }, + { + "mnemonic" : "mv", + "overlay" : { + "base" : "addi", + "match" : ["0xFFF00000", "0x00000000"] + }, + "xform" : "I_mv", + "type" : ["int", "arith", "move"] + }, + { + "mnemonic" : "slli", + "form" : "ISH", + "stencil" : "0x1013", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "slti", + "form" : "ISH", + "ignore" : ["func6"], + "xform" : "I", + "stencil" : "0x2013", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "sltiu", + "form" : "ISH", + "ignore" : ["func6"], + "xform" : "I", + "stencil" : "0x3013", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "xori", + "form" : "ISH", + "ignore" : ["func6"], + "xform" : "I", + "stencil" : "0x4013", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "srli", + "form" : "ISH", + "stencil" : "0x5013", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "srai", + "form" : "ISH", + "stencil" : "0x40005013", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "ori", + "form" : "ISH", + "ignore" : ["func6"], + "xform" : "I", + "stencil" : "0x6013", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "andi", + "form" : "ISH", + "ignore" : ["func6"], + "xform" : "I", + "stencil" : "0x7013", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "add", + "form" : "R", + "stencil" : "0x33", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "sub", + "form" : "R", + "stencil" : "0x40000033", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "sll", + "form" : "R", + "stencil" : "0x1033", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "slt", + "form" : "R", + "stencil" : "0x2033", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "sltu", + "form" : "R", + "stencil" : "0x3033", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "xor", + "form" : "R", + "stencil" : "0x4033", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "srl", + "form" : "R", + "stencil" : "0x5033", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "sra", + "form" : "R", + "stencil" : "0x40005033", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "or", + "form" : "R", + "stencil" : "0x6033", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "and", + "form" : "R", + "stencil" : "0x7033", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "addiw", + "form" : "ISHW", + "ignore" : [ "func7" ], + "xform" : "I", + "stencil" : "0x1b", + "w-oper" : "all", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "slliw", + "form" : "ISHW", + "stencil" : "0x101b", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "srliw", + "form" : "ISHW", + "stencil" : "0x501b", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "sraiw", + "form" : "ISHW", + "stencil" : "0x4000501b", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "addw", + "form" : "R", + "stencil" : "0x3b", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "subw", + "form" : "R", + "stencil" : "0x4000003b", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "sllw", + "form" : "R", + "stencil" : "0x103b", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "srlw", + "form" : "R", + "stencil" : "0x503b", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "sraw", + "form" : "R", + "stencil" : "0x4000503b", + "type" : ["int", "arith"], + "l-oper" : "all" + }, + { + "mnemonic" : "lb", + "form" : "I", + "xform" : "I_load", + "stencil" : "0x3", + "type" : ["int", "load"], + "l-oper" : "all", + "data" : 8 + }, + { + "mnemonic" : "lh", + "form" : "I", + "xform" : "I_load", + "stencil" : "0x1003", + "type" : ["int", "load"], + "l-oper" : "all", + "data" : 16 + }, + { + "mnemonic" : "lw", + "form" : "I", + "xform" : "I_load", + "stencil" : "0x2003", + "type" : ["int", "load"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "ld", + "form" : "I", + "xform" : "I_load", + "stencil" : "0x3003", + "type" : ["int", "load"], + "l-oper" : "all", + "data" : 64 + }, + { + "mnemonic" : "lbu", + "form" : "I", + "xform" : "I_load", + "stencil" : "0x4003", + "type" : ["int", "load"], + "l-oper" : "all", + "data" : 8 + }, + { + "mnemonic" : "lhu", + "form" : "I", + "xform" : "I_load", + "stencil" : "0x5003", + "type" : ["int", "load"], + "l-oper" : "all", + "data" : 16 + }, + { + "mnemonic" : "lwu", + "form" : "I", + "xform" : "I_load", + "stencil" : "0x6003", + "type" : ["int", "load"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "sb", + "form" : "S", + "stencil" : "0x23", + "type" : ["int", "store"], + "l-oper" : "all", + "data" : 8 + }, + { + "mnemonic" : "sh", + "form" : "S", + "stencil" : "0x1023", + "type" : ["int", "store"], + "l-oper" : "all", + "data" : 16 + }, + { + "mnemonic" : "sw", + "form" : "S", + "stencil" : "0x2023", + "type" : ["int", "store"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "sd", + "form" : "S", + "stencil" : "0x3023", + "type" : ["int", "store"], + "l-oper" : "all", + "data" : 64 + }, + { + "mnemonic" : "fence", + "form" : "FENCE", + "stencil" : "0xf", + "type" : ["fence"], + "l-oper" : "all" + }, + { + "mnemonic" : "fence.i", + "form" : "FENCE", + "xform" : "I", + "stencil" : "0x100f", + "type" : ["fence"], + "l-oper" : "all" + }, + { + "mnemonic" : "mul", + "form" : "R", + "stencil" : "0x2000033", + "type" : ["int", "mul"], + "l-oper" : "all" + }, + { + "mnemonic" : "mulh", + "form" : "R", + "stencil" : "0x2001033", + "type" : ["int", "mul"], + "l-oper" : "all" + }, + { + "mnemonic" : "mulhsu", + "form" : "R", + "stencil" : "0x2002033", + "type" : ["int", "mul"], + "l-oper" : "all" + }, + { + "mnemonic" : "mulhu", + "form" : "R", + "stencil" : "0x2003033", + "type" : ["int", "mul"], + "l-oper" : "all" + }, + { + "mnemonic" : "div", + "form" : "R", + "stencil" : "0x2004033", + "type" : ["int", "div"], + "l-oper" : "all" + }, + { + "mnemonic" : "divu", + "form" : "R", + "stencil" : "0x2005033", + "type" : ["int", "div"], + "l-oper" : "all" + }, + { + "mnemonic" : "rem", + "form" : "R", + "stencil" : "0x2006033", + "type" : ["int", "div"], + "l-oper" : "all" + }, + { + "mnemonic" : "remu", + "form" : "R", + "stencil" : "0x2007033", + "type" : ["int", "div"], + "l-oper" : "all" + }, + { + "mnemonic" : "mulw", + "form" : "R", + "stencil" : "0x200003b", + "type" : ["int", "mul"], + "l-oper" : "all" + }, + { + "mnemonic" : "divw", + "form" : "R", + "stencil" : "0x200403b", + "type" : ["int", "div"], + "l-oper" : "all" + }, + { + "mnemonic" : "divuw", + "form" : "R", + "stencil" : "0x200503b", + "type" : ["int", "div"], + "l-oper" : "all" + }, + { + "mnemonic" : "remw", + "form" : "R", + "stencil" : "0x200603b", + "type" : ["int", "div"], + "l-oper" : "all" + }, + { + "mnemonic" : "remuw", + "form" : "R", + "stencil" : "0x200703b", + "type" : ["int", "div"], + "l-oper" : "all" + }, + { + "mnemonic" : "amoadd.w", + "form" : "AMO", + "stencil" : "0x202f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "amoxor.w", + "form" : "AMO", + "stencil" : "0x2000202f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "amoor.w", + "form" : "AMO", + "stencil" : "0x4000202f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "amoand.w", + "form" : "AMO", + "stencil" : "0x6000202f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "amomin.w", + "form" : "AMO", + "stencil" : "0x8000202f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "amomax.w", + "form" : "AMO", + "stencil" : "0xa000202f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "amominu.w", + "form" : "AMO", + "stencil" : "0xc000202f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "amomaxu.w", + "form" : "AMO", + "stencil" : "0xe000202f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "amoswap.w", + "form" : "AMO", + "stencil" : "0x800202f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "lr.w", + "form" : "AMO", + "fixed" : ["rs2"], + "stencil" : "0x1000202f", + "type" : ["int", "load", "atomic"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "sc.w", + "form" : "AMO", + "stencil" : "0x1800202f", + "type" : ["int", "store", "atomic"], + "l-oper" : "all", + "data" : 32 + }, + { + "mnemonic" : "amoadd.d", + "form" : "AMO", + "stencil" : "0x302f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 64 + }, + { + "mnemonic" : "amoxor.d", + "form" : "AMO", + "stencil" : "0x2000302f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 64 + }, + { + "mnemonic" : "amoor.d", + "form" : "AMO", + "stencil" : "0x4000302f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 64 + }, + { + "mnemonic" : "amoand.d", + "form" : "AMO", + "stencil" : "0x6000302f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 64 + }, + { + "mnemonic" : "amomin.d", + "form" : "AMO", + "stencil" : "0x8000302f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 64 + }, + { + "mnemonic" : "amomax.d", + "form" : "AMO", + "stencil" : "0xa000302f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 64 + }, + { + "mnemonic" : "amominu.d", + "form" : "AMO", + "stencil" : "0xc000302f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 64 + }, + { + "mnemonic" : "amomaxu.d", + "form" : "AMO", + "stencil" : "0xe000302f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 64 + }, + { + "mnemonic" : "amoswap.d", + "form" : "AMO", + "stencil" : "0x800302f", + "type" : ["int", "arith", "atomic"], + "l-oper" : "all", + "data" : 64 + }, + { + "mnemonic" : "lr.d", + "form" : "AMO", + "fixed" : ["rs2"], + "stencil" : "0x1000302f", + "type" : ["int", "load", "atomic"], + "l-oper" : "all", + "data" : 64 + }, + { + "mnemonic" : "sc.d", + "form" : "AMO", + "stencil" : "0x1800302f", + "type" : ["int", "store", "atomic"], + "l-oper" : "all", + "data" : 64 + }, + { + "mnemonic" : "ecall", + "form" : "R", + "fixed" : ["rs2", "rs1", "rd"], + "stencil" : "0x73", + "type" : ["int", "system"], + "l-oper" : "all" + }, + { + "mnemonic" : "ebreak", + "form" : "R", + "fixed" : ["rs2", "rs1", "rd"], + "stencil" : "0x100073", + "type" : ["int", "system"], + "l-oper" : "all" + }, + { + "mnemonic" : "uret", + "form" : "R", + "fixed" : ["rs2", "rs1", "rd"], + "stencil" : "0x200073", + "type" : ["system"] + }, + { + "mnemonic" : "sret", + "form" : "R", + "fixed" : ["rs2", "rs1", "rd"], + "stencil" : "0x10200073", + "type" : ["system"] + }, + { + "mnemonic" : "mret", + "form" : "R", + "fixed" : ["rs2", "rs1", "rd"], + "stencil" : "0x30200073", + "type" : ["system"] + }, + { + "mnemonic" : "dret", + "form" : "R", + "fixed" : ["rs2", "rs1", "rd"], + "stencil" : "0x7b200073", + "type" : ["system"] + }, + { + "mnemonic" : "sfence.vma", + "form" : "R", + "fixed" : ["rd"], + "stencil" : "0x12000073", + "type" : ["fence", "system"], + "l-oper" : "all" + }, + { + "mnemonic" : "wfi", + "form" : "R", + "fixed" : ["rs2", "rs1", "rd"], + "stencil" : "0x10500073", + "type" : ["system"] + }, + { + "mnemonic" : "csrrw", + "factory" : "csr", + "form" : "R", + "ignore" : ["func7"], + "stencil" : "0x1073", + "xform" : "CSR", + "type" : ["csr", "system"], + "l-oper" : "all" + }, + { + "mnemonic" : "csrrs", + "factory" : "csr", + "form" : "R", + "ignore" : ["func7"], + "stencil" : "0x2073", + "xform" : "CSR", + "type" : ["csr", "system"], + "l-oper" : "all" + }, + { + "mnemonic" : "csrrc", + "factory" : "csr", + "form" : "R", + "ignore" : ["func7"], + "stencil" : "0x3073", + "xform" : "CSR", + "type" : ["csr", "system"], + "l-oper" : "all" + }, + { + "mnemonic" : "csrrwi", + "factory" : "csr", + "form" : "R", + "ignore" : ["func7"], + "stencil" : "0x5073", + "xform" : "CSRI", + "type" : ["csr", "system"], + "l-oper" : "all" + }, + { + "mnemonic" : "csrrsi", + "factory" : "csr", + "form" : "R", + "ignore" : ["func7"], + "stencil" : "0x6073", + "xform" : "CSRI", + "type" : ["csr", "system"], + "l-oper" : "all" + }, + { + "mnemonic" : "csrrci", + "factory" : "csr", + "form" : "R", + "ignore" : ["func7"], + "stencil" : "0x7073", + "xform" : "CSRI", + "type" : ["csr", "system"], + "l-oper" : "all" + }, + { + "mnemonic" : "cflush.d.l1", + "form" : "R", + "fixed" : ["rd", "rs2"], + "stencil" : "0xfc000073", + "type" : ["cache", "system"], + "l-oper" : ["rs1"] + }, + { + "mnemonic" : "cdiscard.d.l1", + "form" : "R", + "fixed" : ["rd", "rs2"], + "stencil" : "0xfc200073", + "type" : ["cache", "system"] + }, + { + "mnemonic" : "cflush.i.l1", + "form" : "R", + "fixed" : ["rd", "rs2"], + "stencil" : "0xfc100073", + "type" : ["cache", "system"] + }, + { + "mnemonic" : "fadd.s", + "form" : "Rfloat", + "stencil" : "0x53", + "s-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fsub.s", + "form" : "Rfloat", + "stencil" : "0x8000053", + "s-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fmul.s", + "form" : "Rfloat", + "stencil" : "0x10000053", + "s-oper" : "all", + "type" : ["float", "mul"] + }, + { + "mnemonic" : "fdiv.s", + "form" : "Rfloat", + "stencil" : "0x18000053", + "s-oper" : "all", + "type" : ["float", "div"] + }, + { + "mnemonic" : "fsgnj.s", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0x20000053", + "s-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fsgnjn.s", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0x20001053", + "s-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fsgnjx.s", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0x20002053", + "s-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fmin.s", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0x28000053", + "s-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fmax.s", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0x28001053", + "s-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fsqrt.s", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0x58000053", + "s-oper" : "all", + "type" : ["float", "sqrt"] + }, + { + "mnemonic" : "fadd.d", + "form" : "Rfloat", + "stencil" : "0x2000053", + "d-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fsub.d", + "form" : "Rfloat", + "stencil" : "0xa000053", + "d-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fmul.d", + "form" : "Rfloat", + "stencil" : "0x12000053", + "d-oper" : "all", + "type" : ["float", "mul"] + }, + { + "mnemonic" : "fdiv.d", + "form" : "Rfloat", + "stencil" : "0x1a000053", + "d-oper" : "all", + "type" : ["float", "div"] + }, + { + "mnemonic" : "fsgnj.d", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0x22000053", + "d-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fsgnjn.d", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0x22001053", + "d-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fsgnjx.d", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0x22002053", + "d-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fmin.d", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0x2a000053", + "d-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fmax.d", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0x2a001053", + "d-oper" : "all", + "type" : ["float", "arith"] + }, + { + "mnemonic" : "fcvt.s.d", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0x40100053", + "d-oper" : ["rs1"], + "s-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fcvt.d.s", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0x42000053", + "d-oper" : ["rd"], + "s-oper" : ["rs1"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fsqrt.d", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0x5a000053", + "d-oper" : "all", + "type" : ["float", "sqrt"] + }, + { + "mnemonic" : "fle.s", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0xa0000053", + "s-oper" : ["rs1","rs2"], + "w-oper" : ["rd"], + "type" : ["float", "compare"] + }, + { + "mnemonic" : "flt.s", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0xa0001053", + "s-oper" : ["rs1","rs2"], + "w-oper" : ["rd"], + "type" : ["float", "compare"] + }, + { + "mnemonic" : "feq.s", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0xa0002053", + "s-oper" : ["rs1","rs2"], + "w-oper" : ["rd"], + "type" : ["float", "compare"] + }, + { + "mnemonic" : "fle.d", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0xa2000053", + "d-oper" : ["rs1","rs2"], + "w-oper" : ["rd"], + "type" : ["float", "compare"] + }, + { + "mnemonic" : "flt.d", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0xa2001053", + "d-oper" : ["rs1","rs2"], + "w-oper" : ["rd"], + "type" : ["float", "compare"] + }, + { + "mnemonic" : "feq.d", + "form" : "Rfloat", + "fixed" : [ "rm" ], + "stencil" : "0xa2002053", + "d-oper" : ["rs1","rs2"], + "w-oper" : ["rd"], + "type" : ["float", "compare"] + }, + { + "mnemonic" : "fcvt.w.s", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xc0000053", + "s-oper" : ["rs1"], + "w-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fcvt.wu.s", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xc0100053", + "s-oper" : ["rs1"], + "w-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fcvt.l.s", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xc0200053", + "s-oper" : ["rs1"], + "l-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fcvt.lu.s", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xc0300053", + "s-oper" : ["rs1"], + "l-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fmv.x.w", + "form" : "Rfloat", + "fixed" : [ "rm", "rs2" ], + "stencil" : "0xe0000053", + "s-oper" : ["rs1"], + "l-oper" : ["rd"], + "type" : ["float", "move"] + }, + { + "mnemonic" : "fclass.s", + "form" : "Rfloat", + "fixed" : [ "rm", "rs2" ], + "stencil" : "0xe0001053", + "s-oper" : ["rs1"], + "l-oper" : ["rd"], + "type" : ["float", "classify"] + }, + { + "mnemonic" : "fcvt.w.d", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xc2000053", + "d-oper" : ["rs1"], + "w-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fcvt.wu.d", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xc2100053", + "d-oper" : ["rs1"], + "w-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fcvt.l.d", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xc2200053", + "d-oper" : ["rs1"], + "l-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fcvt.lu.d", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xc2300053", + "d-oper" : ["rs1"], + "l-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fmv.x.d", + "form" : "Rfloat", + "fixed" : [ "rm", "rs2" ], + "stencil" : "0xe2000053", + "d-oper" : ["rs1"], + "l-oper" : ["rd"], + "type" : ["float", "move"] + }, + { + "mnemonic" : "fclass.d", + "form" : "Rfloat", + "fixed" : [ "rm", "rs2" ], + "stencil" : "0xe2001053", + "d-oper" : ["rs1"], + "l-oper" : ["rd"], + "type" : ["float", "classify"] + }, + { + "mnemonic" : "fcvt.s.w", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xd0000053", + "w-oper" : ["rs1"], + "s-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fcvt.s.wu", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xd0100053", + "w-oper" : ["rs1"], + "s-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fcvt.s.l", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xd0200053", + "l-oper" : ["rs1"], + "s-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fcvt.s.lu", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xd0300053", + "l-oper" : ["rs1"], + "s-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fmv.w.x", + "form" : "Rfloat", + "fixed" : [ "rm", "rs2" ], + "stencil" : "0xf0000053", + "l-oper" : ["rs1"], + "s-oper" : ["rd"], + "type" : ["float", "move"] + }, + { + "mnemonic" : "fcvt.d.w", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xd2000053", + "w-oper" : ["rs1"], + "d-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fcvt.d.wu", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xd2100053", + "w-oper" : ["rs1"], + "d-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fcvt.d.l", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xd2200053", + "l-oper" : ["rs1"], + "d-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fcvt.d.lu", + "form" : "Rfloat", + "fixed" : [ "rs2" ], + "stencil" : "0xd2300053", + "l-oper" : ["rs1"], + "d-oper" : ["rd"], + "type" : ["float", "convert"] + }, + { + "mnemonic" : "fmv.d.x", + "form" : "Rfloat", + "fixed" : [ "rm", "rs2" ], + "stencil" : "0xf2000053", + "l-oper" : ["rs1"], + "d-oper" : ["rd"], + "type" : ["float", "move"] + }, + { + "mnemonic" : "flw", + "form" : "VF_mem", + "xform" : "I_load", + "stencil" : "0x2007", + "ignore" : ["mewop"], + "type" : ["float", "load"], + "l-oper" : ["rs1"], + "s-oper" : ["rd"], + "data" : 32 + }, + { + "mnemonic" : "fld", + "form" : "VF_mem", + "xform" : "I_load", + "stencil" : "0x3007", + "ignore" : ["mewop"], + "type" : ["float", "load"], + "l-oper" : ["rs1"], + "d-oper" : ["rd"], + "data" : 64 + }, + { + "mnemonic" : "fsw", + "form" : "VF_mem", + "xform" : "S", + "stencil" : "0x2027", + "ignore" : ["mewop"], + "type" : ["float", "store"], + "l-oper" : ["rs1"], + "s-oper" : ["rs2"], + "data" : 32 + }, + { + "mnemonic" : "fsd", + "form" : "VF_mem", + "xform" : "S", + "stencil" : "0x3027", + "ignore" : ["mewop"], + "type" : ["float", "store"], + "l-oper" : ["rs1"], + "d-oper" : ["rs2"], + "data" : 64 + }, + { + "mnemonic" : "fmadd.s", + "form" : "R4", + "stencil" : "0x43", + "type" : ["float", "mac"], + "s-oper" : "all" + }, + { + "mnemonic" : "fmsub.s", + "form" : "R4", + "stencil" : "0x47", + "type" : ["float", "mac"], + "s-oper" : "all" + }, + { + "mnemonic" : "fnmsub.s", + "form" : "R4", + "stencil" : "0x4b", + "type" : ["float", "mac"], + "s-oper" : "all" + }, + { + "mnemonic" : "fnmadd.s", + "form" : "R4", + "stencil" : "0x4f", + "type" : ["float", "mac"], + "s-oper" : "all" + }, + { + "mnemonic" : "fmadd.d", + "form" : "R4", + "stencil" : "0x2000043", + "type" : ["float", "mac"], + "d-oper" : "all" + }, + { + "mnemonic" : "fmsub.d", + "form" : "R4", + "stencil" : "0x2000047", + "type" : ["float", "mac"], + "d-oper" : "all" + }, + { + "mnemonic" : "fnmsub.d", + "form" : "R4", + "stencil" : "0x200004b", + "type" : ["float", "mac"], + "d-oper" : "all" + }, + { + "mnemonic" : "fnmadd.d", + "form" : "R4", + "stencil" : "0x200004f", + "type" : ["float", "mac"], + "d-oper" : "all" + } +] diff --git a/fsl/test/api/src/ApiTestBench.cpp b/fsl/test/api/src/ApiTestBench.cpp new file mode 100644 index 00000000..8f044bba --- /dev/null +++ b/fsl/test/api/src/ApiTestBench.cpp @@ -0,0 +1,788 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh, Condor Computing Corp. +// +#include "fsl_api/FieldExtractor.h" +#include "fsl_api/Fusion.h" +#include "fsl_api/FusionContext.h" +#include "fsl_api/FusionGroup.h" +#include "fsl_api/FusionTypes.h" +#include "fsl_api/MachineInfo.h" +#include "fsl_api/RadixTrie.h" +#include "Msg.h" +#include "Options.h" +#include "ApiTestBench.h" + +#include + +#include +#include +#include +#include +#include +#include +using namespace std; + +// ==================================================================== +// ==================================================================== +TestBench::TestBench(int ac, char** av) +{ + msg->setWho("TestBench"); + opts->setupOptions(ac, av); + verbose = opts->tb_verbose; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +bool TestBench::run() +{ + // sanity check files + if (!sanityTest()) + return false; + if (!basicMavisTest()) + return false; + if (!basicConstraintsTest()) + return false; + if (!fusionGroupAltCtorTest()) + return false; + if (!fusionGroupCfgCtorTest()) + return false; + if (!fusionContextTest(true)) + return false; + + if (!fusionCtorCompileTest(true)) + return false; + if (!fusionSearchTest(true)) + return false; + + // FieldExtractor method tests + if (!fieldExtractorTests(true)) + return false; + + // domain language tests + // This is a sanity check, full syntax checking is done + // in the interpreter test: test/interp + if (!fslInterpQuickTest(true)) + return false; + + return true; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +bool TestBench::fusionContextTest(bool debug) +{ +// if (verbose) +// msg->imsg("fusionContextTest BEGIN"); + + msg->wmsg("fusionContextTest DISABLED"); +// using FusionGroupType = +// fusion::FusionGroup; +// using FusionGroupListType = std::vector; +// +// fusion::FusionContext context_; +// +// FusionGroupType grp1("uf1", uf1, cbProxy::uf1_func); +// FusionGroupType grp2("uf2", uf2, cbProxy::uf2_func); +// FusionGroupType grp3("uf3", uf3, cbProxy::uf3_func); +// +// FusionGroupListType grouplist = {grp1, grp2, grp3}; +// +// try +// { +// context_.makeContext("fusionContextTest", grouplist); +// } +// catch (const fusion::ContextDuplicateError & e) +// { +// std::cerr << "Caught ContextDuplicateError: " << e.what() << endl; +// } +// catch (const std::exception & e) +// { +// std::cerr << "Caught unclassified exception: " << e.what() << endl; +// return false; +// } +// +// // Future: fusion::RadixTree *rtrie = context_.getTree(); +// +// if (verbose) +// msg->imsg("fusionContextTest END"); + return true; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +bool TestBench::fusionSearchTest(bool debug) +{ + if (verbose) + msg->imsg("fusionSearchTest BEGIN"); + bool ok = true; + + using FusionGroupType = + fusion::FusionGroup; + using FusionGroupCfgType = + fusion::FusionGroupCfg; + using FusionType = + fusion::Fusion; + + //This is the struct with transformFunc directly assigned + FusionType::FusionGroupCfgListType testCasesFunc = { + FusionGroupCfgType{.name = {"UF1"}, + .uids = uf1, + .transformFunc = + &TestBench::cbProxy::uf1_func}, + FusionGroupCfgType{.name = {"UF1_1"}, + .uids = uf1_1, + .transformFunc = + &TestBench::cbProxy::uf1_1_func}, + FusionGroupCfgType{.name = {"UF1_2"}, + .uids = uf1_2, + .transformFunc = + &TestBench::cbProxy::uf1_2_func}, + FusionGroupCfgType{.name = {"UF1_3"}, + .uids = uf1_3, + .transformFunc = + &TestBench::cbProxy::uf1_3_func}, + FusionGroupCfgType{.name = {"UF2"}, + .uids = uf2, + .transformFunc = + &TestBench::cbProxy::uf2_func}, + FusionGroupCfgType{.name = {"UF3"}, + .uids = uf3, + .transformFunc = + &TestBench::cbProxy::uf3_func}}; + +//FIXME: A test for this needs to be created +// +// //This is the struct with transformFunc to be set through +// //a function map +// FusionType::FusionGroupCfgListType testCasesName = { +// FusionGroupCfgType{.name = {"UF1"}, +// .uids = uf1, +// .transformName = "cbProxy::uf1_func"}, +// FusionGroupCfgType{.name = {"UF1_1"}, +// .uids = uf1_1, +// .transformName = "cbProxy::uf1_1_func"}, +// FusionGroupCfgType{.name = {"UF1_2"}, +// .uids = uf1_2, +// .transformName = "cbProxy::uf1_2_func"}, +// FusionGroupCfgType{.name = {"UF1_3"}, +// .uids = uf1_3, +// .transformName = "cbProxy::uf1_3_func"}, +// FusionGroupCfgType{.name = {"UF2"}, +// .uids = uf2, +// .transformName = "cbProxy::uf2_func"}, +// FusionGroupCfgType{.name = {"UF3"}, +// .uids = uf3, +// .transformName = "cbProxy::uf3_func"}}; + + // Future add specific tests for hash creation + // std::unordered_map expHashes; + // generateExpectHashes(expHashes,testCases); + + InstPtrListType in, out; + + assign(in, of1, opts->isa_files); + assign(out, of1, opts->isa_files); + + size_t outSize = out.size(); + size_t inSize = in.size(); + + FusionType f(testCasesFunc); + f.fusionOperator(in, out); + + // The default operator changes no machine state + if (in.size() != 0) + { + msg->emsg("fusionOperator modified the input vector"); + ok = false; + } + + if (out.size() != (outSize + inSize)) + { + msg->emsg( + "fusionOperator failed to properly modify the output vector"); + ok = false; + } + + // Test the custom operator as lambda + auto customLambda = [](FusionType & inst, fusion::InstPtrListType & in, + fusion::InstPtrListType & out) + { + out = in; // in is not cleared + }; + + // Restore in/out + in.clear(); + out.clear(); + InstPtrListType tmp; + assign(in, of1, opts->isa_files); + inSize = in.size(); + + f.setFusionOpr(customLambda); + f.fusionOperator(in, out); + + // Did the lambda clear the in vector + if (in.size() == 0) + { + msg->emsg("the custom fusionOperator incorrectly cleared the " + "input vector"); + ok = false; + } + + // The resulting out vector should be the same size as in and tmp + bool sameSize = inSize == out.size() && inSize == in.size(); + if (!sameSize) + { + msg->emsg("with the custom fusionOperator the vector sizes are " + "mismatched"); + ok = false; + } + + if (verbose) + msg->imsg("fusionSearchTest END"); + return ok; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +void TestBench::generateExpectHashes( + unordered_map & exp, + const FusionType::FusionGroupCfgListType & in) +{ + for (size_t i = 0; i < in.size(); ++i) + { + FusionGroupCfgType cfg = in[i]; + fusion::HashType expHash = jenkinsOneAtATime(cfg.uids.value()); + exp.insert(make_pair(cfg.name, expHash)); + } +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +bool TestBench::fusionCtorCompileTest(bool debug) +{ + if (verbose) + msg->imsg("fusionCtorCompileTest BEGIN"); + bool ok = true; + + using FusionGroupType = + fusion::FusionGroup; + using FusionType = + fusion::Fusion; + + // compile checks + //Removed FusionType f1; + //Removed FusionType f2{}; + //Removed FusionType f3 = + // fusion::Fusion(); + + const FusionType::FusionGroupListType fusionGroup_list = {}; + const FusionType::FusionGroupCfgListType fusionGroupCfg_list = {}; + const fusion::FileNameListType txt_file_list = {}; + + FusionType f4(fusionGroup_list); + FusionType f5(fusionGroupCfg_list); + FusionType f6(txt_file_list); + + if (verbose) + msg->imsg("fusionCtorCompileTest END"); + return ok; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +bool TestBench::basicMavisTest(bool debug) +{ + if (verbose) + msg->imsg("basicMavisTest BEGIN"); + InstUidListType goldenUid = uf1; // { 0xb, 0xd, 0x1c, 0xf, 0x13 }; + OpcodeListType goldenOpc = of1; // { 0x76e9,0x685,0x8d35,0x1542,0x9141 }; + + Instruction::PtrType inst = nullptr; + + using MavisType = Mavis, uArchInfo>; + MavisType mavis_facade(opts->isa_files, {}); + + // Make sure the opcodes convert correctly + InstPtrListType instrs; + for (const auto opc : goldenOpc) + { + try + { + instrs.emplace_back(mavis_facade.makeInst(opc, 0)); + } + catch (const mavis::IllegalOpcode & ex) + { + cout << ex.what() << endl; + msg->emsg("basicMavisTest failed to convert opcode"); + return false; + } + } + + InstUidListType uids; + for (const auto & inst : instrs) + { + uids.emplace_back(inst->getUID()); + } + + if (instrs.size() != goldenUid.size() + || instrs.size() != goldenOpc.size() + || instrs.size() != uids.size()) + { + msg->emsg("basicMavisTest size mismatch in inst vector"); + return false; + } + + // FIXME: There is an unexplained difference in UID creation + // if (goldenUid != uids) + // { + // msg->emsg("basicMavisTest inst to uid conversion + // failed"); return false; + // } + + if (debug) + info(goldenUid, uids, instrs); + + if (verbose) + msg->imsg("basicMavisTest END"); + return true; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +bool TestBench::fusionGroupAltCtorTest() +{ + if (verbose) + msg->imsg("fusionGroupAltCtorTest BEGIN"); + + // fusion ctor compile checks + fusion::FusionGroup f1; + fusion::FusionGroup f2{}; + fusion::FusionGroup f3 = + fusion::FusionGroup(); + + struct OtherMachine + { + OtherMachine() {} + }; + + struct OtherExtractor + { + OtherExtractor() {} + }; + + // Alternative machineinfo and extractor + using AltFusionGroupType = + fusion::FusionGroup; + + InstUidListType alt_uid = {}; + + AltFusionGroupType alt1("alt1"); + AltFusionGroupType alt2("alt2", alt_uid); + + struct proxy + { + static bool alt_func(AltFusionGroupType &, InstPtrListType &, + InstPtrListType &) + { + return true; + } + }; + + bool ok = true; + + AltFusionGroupType alt3("alt3", alt_uid); + alt3.setTransform(proxy::alt_func); + + InstPtrListType in, out; + + if (!alt3.transform(in, out)) + { + msg->emsg("alt3.transform() failed"); + ok = false; + } + + AltFusionGroupType alt4("alt4", alt_uid, proxy::alt_func); + if (!alt4.transform(in, out)) + { + msg->emsg("alt4.transform() failed"); + ok = false; + } + + if (verbose) + msg->imsg("fusionGroupAltCtorTest END"); + return ok; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +bool TestBench::fusionGroupCfgCtorTest() +{ + if (verbose) + msg->imsg("fusionGroupCfgCtorTest BEGIN"); + using FusionGroupCfgType = + fusion::FusionGroupCfg; + + // --------------------------------------------------------------- + // Test that hash created from the F1CfgUid matches the hash from a + // base class reference instance + // --------------------------------------------------------------- + // reference version + fusion::FusionGroupBase reference; + reference.setUids(uf1); + fusion::HashType referenceHash = reference.hash(); + + // With uids, no opcs, no mavis + FusionGroupCfgType F1CfgUid{.name = {"F1CfgUid"}, + .uids = uf1, + .transformFunc = &f1_constraints}; + + bool ok = true; + + using FusionGroupType = + fusion::FusionGroup; + FusionGroupType F1fromF1CfgUid(F1CfgUid); + + //F1fromF1CfgUid.info(); + + if (referenceHash != F1fromF1CfgUid.hash()) + { + msg->emsg("F1fromF1CfgUid hash does not match reference hash"); + ok = false; + } + // --------------------------------------------------------------- + // Test that the F1CfgUid ctor results in a FusionGroup that can + // correctly transform this input group + InstPtrListType in, out; + // assign the input vector before transform + assign(in, of1, opts->isa_files); + + if (!F1fromF1CfgUid.transform(in, out)) + { + msg->emsg("F1fromF1CfgUid.transform() returned false"); + ok = false; + } + + if (in.size() != 0) + { + msg->emsg("F1fromF1CfgUid.f1_constraints failed to modify input"); + ok = false; + } + if (out.size() != 1) + { + msg->emsg("F1fromF1CfgUid.f1_constraints failed to modify output"); + ok = false; + } + // --------------------------------------------------------------- + // Test that a FusionGroupCfg constructed from opcodes acts like + // a FusionGroupCfg constructed from respective UIDs + // + // Future support + + // --------------------------------------------------------------- + // Test that a FusionGroupCfg constructed from assembly statements acts + // like a FusionGroupCfg constructed from respective UIDs + // + // Future support + + if (verbose) + msg->imsg("fusionGroupCfgCtorTest END"); + return ok; +} + +// -------------------------------------------------------------------- +// Fusion group transform test +// -------------------------------------------------------------------- +bool TestBench::basicConstraintsTest() +{ + if (verbose) + msg->imsg("basicConstraintsTest BEGIN"); + + FusionGroupType F1("F1", TestBench::uf1, f1_constraints); + + InstPtrListType in; + InstPtrListType out; + + // Create instr from opcodes + assign(in, of1, opts->isa_files); + + bool ok = true; + + if (!F1.transform(in, out)) + { + msg->emsg("F1.transform() returned false"); + ok = false; + } + + if (in.size() != 0) + { + msg->emsg("F1.f1_constraints failed to modify input"); + ok = false; + } + + if (out.size() != 1) + { + msg->emsg("F1.f1_constraints failed to modify output"); + ok = false; + } + + FusionGroupType F2("F2", TestBench::uf2); + + if (F2.getTransform() != nullptr) + { + msg->emsg("F2.transform() was not a nullptr as expected"); + ok = false; + } + + F2.setTransform(f1_constraints); + + if (F2.getTransform() == nullptr) + { + msg->emsg("F2.transform() was not set to handler as expected"); + ok = false; + } + + if (F2.transform(in, out)) + { + msg->emsg("F2.transform() failed to reject uf2 sequence"); + ok = false; + } + + if (verbose) + msg->imsg("basicConstraintsTest END"); + return ok; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +bool TestBench::radixTrieTest(bool) +{ + if (verbose) + msg->imsg("radixTrieTest BEGIN"); + RadixTrie<4> trie; + uint32_t num_values = 1024 * 1024; + + bool ok = true; + + std::mt19937 generator(std::random_device{}()); + std::uniform_int_distribution distribution( + 0, std::numeric_limits::max()); + + auto start = std::chrono::high_resolution_clock::now(); + for (uint32_t i = 0; i < num_values; ++i) + { + uint32_t randomNumber = distribution(generator); + trie.insert(randomNumber); + } + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration insertDuration = end - start; + std::cout << "Time taken for insertion: " << insertDuration.count() + << " seconds" << std::endl; + + start = std::chrono::high_resolution_clock::now(); + for (uint32_t i = 0; i < num_values; ++i) + { + uint32_t randomNumber = distribution(generator); + trie.search(randomNumber); + } + + end = std::chrono::high_resolution_clock::now(); + std::chrono::duration searchDuration = end - start; + std::cout << "Time taken for searching: " << searchDuration.count() + << " seconds" << std::endl; + + trie.insert(12345); + trie.insert(67890); + + std::cout << "Found '12345' " << (trie.search(12345) ? "Yes" : "No") + << std::endl; + std::cout << "Found '67890' " << (trie.search(67890) ? "Yes" : "No") + << std::endl; + std::cout << "Found '54321' " << (trie.search(54321) ? "Yes" : "No") + << std::endl; + + if (trie.search(12345) && trie.search(67890) && !trie.search(54321)) + { + ok = true; + } + else + { + ok = false; + } + if (verbose) + msg->imsg("radixTrieTest END"); + return ok; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +bool TestBench::sanityTest(bool) +{ + bool ok = true; + + for (auto fn : opts->isa_files) + { + if (!std::filesystem::exists(fn)) + { + msg->emsg("Can not find isa file " + fn); + ok = false; + } + } + + return ok; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +void TestBench::assign(InstPtrListType & in, OpcodeListType & opcodes, + const FileNameListType & json_files) +{ + using MavisType = Mavis, uArchInfo>; + MavisType mavis_facade(json_files, {}); + + Instruction::PtrType inst = nullptr; + + for (const auto icode : opcodes) + { + try + { + in.emplace_back(mavis_facade.makeInst(icode, 0)); + } + catch (const mavis::IllegalOpcode & ex) + { + cout << ex.what() << endl; + } + } +} + +// ------------------------------------------------------------------------ +// zoo.F1 specific checks +// +// Operand requirements +// - rgrp[0].RD == rgrp[1].RD == rgrp[2].RS2 (note RS2 change) +// - rgrp[2].RD == rgrp[3].RD == rgrp[4].RD +// - rgrp[3].IMM == rgrp[4].IMM getField IMM not implemented +// ------------------------------------------------------------------------ +bool TestBench::f1_constraints(FusionGroupType & g, InstPtrListType & in, + InstPtrListType & out) +{ + // This goup expects at least 5 instruction positions in the input + if (in.size() < 5) + return false; + + // number of wr/rd ports required by group tested against machine + // limits + if (g.fe().getIntWrPorts(in) > g.mi().maxIntWrPorts()) + return false; + if (g.fe().getIntRdPorts(in) > g.mi().maxIntRdPorts()) + return false; + + // using enum FieldExtractor::FieldName; requires c++20 + constexpr auto RD = FieldExtractor::FieldName::RD; + constexpr auto RS2 = FieldExtractor::FieldName::RS2; + + // Operand field encodings comparison against constraints + // The indexes are positions in the group, 0 = 1st instruction + if (g.fe().noteq(in, 0, 1, RD) || g.fe().noteq(in, 0, 2, RD, RS2) + || g.fe().noteq(in, 2, 3, RD) || g.fe().noteq(in, 2, 4, RD)) + // || g.fe().noteq(in,3,4,IMM)) FIXME: IMM not implemented yet + { + return false; + } + + // This test only does constraints checking - fake a transform + out.emplace_back(in[0]); + in.clear(); + return true; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +fusion::HashType +TestBench::jenkinsOneAtATime(const ::vector & v) +{ + fusion::HashType hash = 0; + + for (auto i : v) + { + hash += i; + hash += (hash << 10); + hash ^= (hash >> 6); + } + + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return hash; +} + +// -------------------------------------------------------------------- +void TestBench::info(InstUidListType & aUIDs, InstUidListType & bUIDs, + InstPtrListType & instrs) +{ + cout << "aUIDs "; + for (auto uid : aUIDs) + { + cout << " 0x" << setw(8) << hex << setfill('0') << uid; + } + cout << endl; + cout << "bUIDs "; + for (auto uid : bUIDs) + { + cout << " 0x" << setw(8) << hex << setfill('0') << uid; + } + cout << endl; + + cout << "Instrs" << endl; + string pad = " "; + for (auto inst : instrs) + { + cout << pad << inst << endl; + } +} +// -------------------------------------------------------------------- +bool TestBench::compareFiles(const string actual, + const string expect,bool showDiffs) +{ + std::ifstream act(actual); + std::ifstream exp(expect); + + // Check existence + if (!act.is_open() || !exp.is_open()) { + msg->emsg("Error opening files"); + if(!act.is_open()) { + msg->emsg("Could not open "+actual); + } + + if(!exp.is_open()) { + msg->emsg("Could not open "+expect); + } + + return false; + } + + std::string actLine, expLine; + int lineNo = 1; + + // Check lines + while (std::getline(act, actLine) && std::getline(exp, expLine)) { + if (actLine != expLine) { + msg->emsg("Difference found at line "+::to_string(lineNo)+":"); + if(showDiffs) { + msg->emsg("Actual: '"+actLine+"'"); + msg->emsg("Expect: '"+expLine+"'"); + } + return false; + } + lineNo++; + } + + // Check lengths + if (!std::getline(act, actLine) ^ !std::getline(exp, expLine)) { + msg->emsg("Files differ in length"); + return false; + } + + return true; +} diff --git a/fsl/test/api/src/FslTests.cpp b/fsl/test/api/src/FslTests.cpp new file mode 100644 index 00000000..81f9fa22 --- /dev/null +++ b/fsl/test/api/src/FslTests.cpp @@ -0,0 +1,103 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh, Condor Computing Corp. +// +#include "fsl_api/Fusion.h" +#include "fsl_interp/inc/FslParser.h" +#include "Msg.h" +#include "Options.h" +#include "ApiTestBench.h" + +#include +using namespace std; +extern FslParser* FP; +extern uint32_t lineNo; + +// -------------------------------------------------------------------- +// More tests will be written +// -------------------------------------------------------------------- +bool TestBench::fslTests(bool) +{ + if (!fslInterpQuickTest()) + return false; + + return true; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +bool TestBench::checkSyntax(vector & files, bool) +{ + bool ok = true; + for (auto fn : files) + { + + if (verbose) + { + std::filesystem::path fp(fn); + string fandext = + fp.filename().string() + fp.extension().string(); + msg->imsg("parsing " + fandext); + } + + FP->warmReset(); + + if (!(FP->parse(fn))) + { + // yyerror() reports the error message + ok = false; + } + } + + return ok; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +bool TestBench::fslInterpQuickTest(bool) +{ + if (verbose) + msg->imsg("fslInterpQuickTest BEGIN"); + + // There should be at least one file for this test + if (opts->fsl_syntax_files.size() == 0) + { + msg->emsg("No FSL syntax test files specified"); + return false; + } + + bool ok = true; + + FP->coldReset(); + + // Check the files specifically that hold syntax corner cases + if (!checkSyntax(opts->fsl_syntax_files)) + ok = false; + + //See the cmake command that copies expected to the bin dir. + string actualFN = "symtab_actual.txt"; + string expectFN = "symtab_expect.txt"; + + //Write the symtab to a file, (true) use the file name.ext + //only option + ofstream actual(actualFN.c_str()); + FP->symtab.info(actual, true); + actual.close(); + + // (true) emit differences + if(!compareFiles(actualFN,expectFN)) { + ok = false; + msg->emsg("Symbol table does not match expect"); + msg->emsg(" Actual data : "+actualFN); + msg->emsg(" Expect data : "+expectFN); + } + + // Check all the other files, looking for things to add to + // corner cases tests + if (!checkSyntax(opts->fsl_files)) + ok = false; + + if (verbose) + msg->imsg("fslInterpQuickTest END"); + + return ok; +} diff --git a/fsl/test/api/src/Options.cpp b/fsl/test/api/src/Options.cpp new file mode 100644 index 00000000..8ac826eb --- /dev/null +++ b/fsl/test/api/src/Options.cpp @@ -0,0 +1,108 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh, Condor Computing Corp. +// +#include "Msg.h" +#include "Options.h" +#include +using namespace std; + +// -------------------------------------------------------------------- +// Build the option set and check the options +// -------------------------------------------------------------------- +void Options::setupOptions(int ac, char** av) +{ + notify_error = false; + + po::options_description visibleOpts( + "\nFusion API test\n " + "Usage:: test [--help|-h|--version|-v] { options }"); + + po::options_description stdOpts("Standard options"); + buildOptions(stdOpts); + + try + { + po::store(po::command_line_parser(ac, av).options(stdOpts).run(), + vm); + + // Without positional option po::parse_command_line can be used + // po::store(po::parse_command_line(ac, av, allOpts), vm); + } + catch (boost::program_options::error & e) + { + msg->msg(""); + msg->emsg("1st pass command line option parsing failed"); + msg->emsg("What: " + string(e.what())); + usage(stdOpts); + exit(1); + } + + po::notify(vm); + if (!checkOptions(vm, stdOpts, true)) + exit(1); +} + +// -------------------------------------------------------------------- +// Construct the std, hidden and positional option descriptions +// -------------------------------------------------------------------- +// clang-format off +void Options::buildOptions(po::options_description & stdOpts) +{ + stdOpts.add_options() + + ("help,h", "...") + + ("version,v", "report version and exit") + + ("stf", po::value(&stf_file), "STF input file") + + ("output,o", po::value(&output_file), + "Log output file") + + ("isa_file", po::value>(&isa_files), + "Multiple --isa_file accepted") + + ("fsl_file", po::value>(&fsl_files), + "Multiple --fsl_file accepted") + + ("fsl_syntax_file", po::value>(&fsl_syntax_files), + "Syntax stress test files. Multiple " + "--fsl_syntax_file accepted") + + ("tb_verbose", po::bool_switch(&tb_verbose) ->default_value(false), + "Test bench message control"); +} +// clang-format on +// -------------------------------------------------------------------- +// Check sanity on the options, handle --help, --version +// -------------------------------------------------------------------- +bool Options::checkOptions(po::variables_map & vm, + po::options_description & stdOpts, + bool firstPass) +{ + if (firstPass) + { + if (vm.count("help")) + { + usage(stdOpts); + return false; + } + if (vm.count("version")) + { + version(); + return false; + } + } + + return true; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +void Options::version() const +{ + msg->imsg(""); + msg->imsg("Fusion api tester"); + msg->imsg("Slack jeff w/any questions"); + msg->imsg(""); +} diff --git a/fsl/test/api/src/TestData.cpp b/fsl/test/api/src/TestData.cpp new file mode 100644 index 00000000..3124be7e --- /dev/null +++ b/fsl/test/api/src/TestData.cpp @@ -0,0 +1,130 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh, Condor Computing Corp. +// +#include "fsl_api/FieldExtractor.h" +#include "fsl_api/Fusion.h" +#include "fsl_api/FusionContext.h" +#include "fsl_api/FusionGroup.h" +#include "fsl_api/FusionTypes.h" +#include "fsl_api/MachineInfo.h" +#include "fsl_api/RadixTrie.h" +#include "Msg.h" +#include "Options.h" +#include "ApiTestBench.h" + +#include + +#include +#include +#include +using namespace std; +// -------------------------------------------------------------------- +// Example +// -------------------------------------------------------------------- +// TestBench::OpcodeListType TestBench::of1 = { +// // INDEX DISASM FORM FIELDS UID +// 0x76e9, // 0 c.lui x13, -6 CI-TYPE RD IMM 0xb +// 0x0685, // 1 c.addi x13,0x1 I-TYPE RD RS1 IMM 0xd +// 0x8d35, // 2 c.xor x10,x13 R-TYPE RD RS1 RS2 0x1c +// 0x1542, // 3 c.slli x10,48 I-TYPE RD RS1 IMM 0xf +// 0x9141 // 4 c.srli x10,48 I-TYPE RD RS1 IMM 0x13 +// }; +// +// 0 U RD = G1 IMM = C1 +// 1 I RD = G1 RS1 = G1 IMM = C2 +// 2 R RD = G1 RS1 = G2 RD2 = G1 +// 3 I RD = G2 RS1 = G2 IMM = C3 +// 4 I RD = G2 RS1 = G2 IMM = C3 +// ---------------------------------------------------------------------- +TestBench::InstUidListType TestBench::uf1 = {0xb, 0xd, 0x1c, 0xf, 0x13}; +TestBench::OpcodeListType TestBench::of1 = { + // INDEX DISASM FORM FIELDS UID + 0x76e9, // 0 c.lui x13, -6 CI-TYPE RD IMM 0xb + 0x0685, // 1 c.addi x13,0x1 I-TYPE RD RS1 IMM 0xd + 0x8d35, // 2 c.xor x10,x13 R-TYPE RD RS1 RS2 0x1c + 0x1542, // 3 c.slli x10,48 I-TYPE RD RS1 IMM 0xf + 0x9141 // 4 c.srli x10,48 I-TYPE RD RS1 IMM 0x13 +}; +// fusion::HashType TestBench::hf1 = { 0xb,0xd,0x1c,0xf,0x13 }; +// -------------------------------------------------------------------- +// Fragment of of1 +// -------------------------------------------------------------------- +TestBench::InstUidListType TestBench::uf1_1 = {0xd, 0x1c, 0xf, 0x13}; +TestBench::OpcodeListType TestBench::of1_1 = { + 0x0685, // "c.addi x13,0x1", 0xd + 0x8d35, // "c.xor x10,x13", 0x1c + 0x1542, // "c.slli x10,48", 0xf + 0x9141 // "c.srli x10,48" 0x13 +}; +//// -------------------------------------------------------------------- +TestBench::InstUidListType TestBench::uf1_2 = {0x1c, 0xf, 0x13}; +TestBench::OpcodeListType TestBench::of1_2 = { + 0x8d35, // "c.xor x10,x13", 0xf + 0x1542, // "c.slli x10,48", 0xf + 0x9141 // "c.srli x10,48" 0x13 +}; +// -------------------------------------------------------------------- +TestBench::InstUidListType TestBench::uf1_3 = {0xf, 0x13}; +TestBench::OpcodeListType TestBench::of1_3 = { + 0x1542, // "c.slli x10,48", 0xf + 0x9141 // "c.srli x10,48" 0x13 +}; +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +TestBench::InstUidListType TestBench::uf2 = {0xd, 0x34}; +TestBench::OpcodeListType TestBench::of2 = { + 0x7159, // "c.addi16sp -112", 0xd + 0xf0a2 // "c.fswsp f8, 96" 0x34 +}; +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +TestBench::InstUidListType TestBench::uf3 = {0x17, 0x2d}; +TestBench::OpcodeListType TestBench::of3 = { + 0x843a, // "c.mv x8, x14", 0x17 + 0x6018 // "c.flw f14, 0(x8)" 0x2d +}; +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +TestBench::InstUidListType TestBench::uf4 = {0xf, 0x13}; +TestBench::OpcodeListType TestBench::of4 = { + 0xe014, // "c.fsw f13, 0(x8)", 0xf + 0x86a2 // "c.mv x13, x8"; 0x13 +}; +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +TestBench::InstUidListType TestBench::uf5 = {0x17, 0x2d, 0x34, 0x17, 0x4}; +TestBench::OpcodeListType TestBench::of5 = { + 0x843a, // "c.mv x8, x14", 0x17 + 0x6018, // "c.flw f14, 0(x8)", 0x2d + 0xe014, // "c.fsw f13, 0(x8)", 0x34 + 0x86a2, // "c.mv x13, x8", 0x17 + 0xff65 // "c.bnez x14, -8" 0x4 +}; +// -------------------------------------------------------------------- +TestBench::InstUidListType TestBench::uf5_1 = {0x17, 0x2d, 0x34, 0x17}; +TestBench::OpcodeListType TestBench::of5_1 = { + 0x843a, // "c.mv x8, x14", 0x17 + 0x6018, // "c.flw f14, 0(x8)", 0x2d + 0xe014, // "c.fsw f13, 0(x8)", 0x34 + 0x86a2 // "c.mv x13, x8" 0x17 +}; +// -------------------------------------------------------------------- +TestBench::InstUidListType TestBench::uf5_2 = {0x2d, 0x34, 0x17, 0x4}; +TestBench::OpcodeListType TestBench::of5_2 = { + 0x6018, // "c.flw f14, 0(x8)", 0x2d + 0xe014, // "c.fsw f13, 0(x8)", 0x34 + 0x86a2, // "c.mv x13, x8", 0x17 + 0xff65, // "c.bnez x14, -8" 0x4 +}; +// -------------------------------------------------------------------- +TestBench::InstUidListType TestBench::uf5_3 = {0x2d, 0x34, 0x17}; +TestBench::OpcodeListType TestBench::of5_3 = { + 0x6018, // "c.flw f14, 0(x8)", 0x2d + 0xe014, // "c.fsw f13, 0(x8)", 0x34 + 0x86a2 // "c.mv x13, x8" 0x17 +}; +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- + const vector TestBench::std_isa_files = { + "../../../mavis/json/isa_rv64g.json", + "../../../mavis/json/isa_rv64c.json"}; diff --git a/fsl/test/api/src/TestFieldExtractor.cpp b/fsl/test/api/src/TestFieldExtractor.cpp new file mode 100644 index 00000000..1f749368 --- /dev/null +++ b/fsl/test/api/src/TestFieldExtractor.cpp @@ -0,0 +1,125 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh, Condor Computing Corp. +// +#include "Msg.h" +#include "Options.h" +#include "ApiTestBench.h" +#include +#include +using namespace std; + +// -------------------------------------------------------------------- +// The intent is at least one test for the top level methods overall. +// +// Some method tests are covered as part of the Fusion Group and transform +// tests. SField and ImmField tests are less used elsewhere. +// These outliers are tested here. +// -------------------------------------------------------------------- +bool TestBench::fieldExtractorTests(bool debug) +{ + FieldExtractor fe; + using InstPtrType = FieldExtractor::InstPtrType; + + if (verbose) + msg->imsg("fieldExtractorTests BEGIN"); + + bool ok = true; + MavisType mavis(opts->isa_files, {}); + + // add x1,x2,x3 + InstPtrType inst_1 = makeInst(mavis, 0x003100b3); + + if (inst_1 == nullptr) + ok = false; + + using FN = FieldExtractor::FieldName; + using SFN = FieldExtractor::SFieldName; + + // Test for uint32_t getField(InstPtrType,FieldName) const + uint32_t rd_inst_1 = fe.getField(inst_1, FN::RD); + uint32_t rs1_inst_1 = fe.getField(inst_1, FN::RS1); + uint32_t rs2_inst_1 = fe.getField(inst_1, FN::RS2); + + if (!testFieldValue(0, "RD", rd_inst_1, 0x1)) + ok = false; + if (!testFieldValue(1, "RS1", rs1_inst_1, 0x2)) + ok = false; + if (!testFieldValue(2, "RS2", rs2_inst_1, 0x3)) + ok = false; + + bool isDest = false; + if (!fe.checkInstHasField(inst_1, FN::RD, isDest)) + { + msg->emsg("checkInstHasField() failed to detect RD"); + ok = false; + } + + if (!isDest) + { + msg->emsg("ID=3: checkInstHasField() failed to set isDest"); + ok = false; + } + + // Test for uint32_t getSField(InstPtrType,SFieldName) const + // [ funct7 | rs2 | rs1 | rm | rd | opcode ] + // 3322 2222 2222 1111 1111 11 + // 1098 7654 3210 9876 5432 1098 7654 3210 + // 0111 0010 1010 0111 1111 0101 0100 0011 + // RM should be 111 -> 0x7 + InstPtrType inst_2 = makeInst(mavis, 0x72a7f543); + if (inst_2 == nullptr) + ok = false; + uint32_t rm_inst_2 = fe.getSField(inst_2, SFN::RM); + if (!testFieldValue(4, "RM", rm_inst_2, 0x7)) + ok = false; + + // Test for uint32_t getImmField(InstPtrType inst) const + + if (!ok) + msg->emsg("fieldExtractor_tests FAILED"); + if (verbose) + msg->imsg("fieldExtractor_tests END"); + return ok; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +FieldExtractor::InstPtrType TestBench::makeInst(MavisType & m, + uint32_t opc) +{ + FieldExtractor::InstPtrType inst; + + try + { + inst = m.makeInst(opc, 0); + } + catch (const std::exception &) + { + if (!inst) + { + std::ostringstream ss; + ss << "0x" << std::setw(8) << std::setfill('0') << std::hex + << opc; + msg->emsg("Mavis could not create instruction from " + + ss.str()); + return nullptr; + } + } + + return inst; +} + +// -------------------------------------------------------------------- +// -------------------------------------------------------------------- +bool TestBench::testFieldValue(uint32_t id, string name, uint32_t act, + uint32_t exp) +{ + if (act != exp) + { + msg->emsg("ID:" + ::to_string(id) + ":FIELD:" + name + + ": value mismatch"); + return false; + } + + return true; +} diff --git a/fsl/test/api/src/main.cpp b/fsl/test/api/src/main.cpp new file mode 100644 index 00000000..17b31685 --- /dev/null +++ b/fsl/test/api/src/main.cpp @@ -0,0 +1,46 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh, Condor Computing Corp. +// +#include "fsl_interp/inc/FslParser.h" +#include "ApiTestBench.h" +#include "Msg.h" +#include "Options.h" + +#include +#include +using namespace std; + +FslParser* FP; + +Options* Options::instance = 0; +std::shared_ptr opts(Options::getInstance()); + +Msg* Msg::instance = 0; +std::unique_ptr msg(Msg::getInstance()); + +// ------------------------------------------------------------------------ +int main(int ac, char** av) +{ + FslParser fp; + FP = &fp; + + TestBench tb(ac, av); + ofstream out("PASSFAIL"); + if (!out.is_open()) + { + msg->emsg("Could not open pass/fail status file"); + return 1; + } + + msg->imsg("Test run begin"); + bool ok = tb.run(); + if (!ok) + { + out << "FAIL" << endl; + msg->emsg("Test run end FAIL"); + return 1; + } + out << "PASS" << endl; + msg->imsg("Test run end PASS"); + return 0; +} diff --git a/fsl/test/api/symtab_actual.txt b/fsl/test/api/symtab_actual.txt new file mode 100644 index 00000000..268fb8ff --- /dev/null +++ b/fsl/test/api/symtab_actual.txt @@ -0,0 +1,8 @@ + +---------- +Symbol table +Name Type Line File +---------- + +Symbol table total entries 0 + diff --git a/fsl/test/api/symtab_expect.txt b/fsl/test/api/symtab_expect.txt new file mode 100644 index 00000000..268fb8ff --- /dev/null +++ b/fsl/test/api/symtab_expect.txt @@ -0,0 +1,8 @@ + +---------- +Symbol table +Name Type Line File +---------- + +Symbol table total entries 0 + diff --git a/fsl/test/common/Msg.h b/fsl/test/common/Msg.h new file mode 100644 index 00000000..8d8d1724 --- /dev/null +++ b/fsl/test/common/Msg.h @@ -0,0 +1,152 @@ +// HEADER PLACEHOLDER +// contact Jeff Nye, jeffnye-gh +// +//! \file Msg.hpp header for simple uniform messages +#pragma once +#include +#include +#include +#include + +//! \brief singleton for standardized messages +//! +//! I use this to standardize local output. +//! +//! I'm using an ad hoc test bench, a compliant testbench +//! would be part of a fusion capable Sparta unit. In that +//! case this would be replaced with the mechanism found +//! in the unit benches. +struct Msg +{ + //! \brief get the singleton instance + static Msg* getInstance() + { + if (!instance) + instance = new Msg; + return instance; + } + + ~Msg() {} // dtor + + //! \brief this adds an identifier prefix to messages + //! + //! Example -I:MYUNIT: {message} + void setWho(std::string _w) { w = _w + ": "; } + + //! \brief shared message method + void mmsg(std::string p, std::string m) const + { + std::cout << p << w << m << std::endl; + } + + //! \brief debug messages + void dmsg(std::string m = "", int v = 4) const + { + if (v <= verbose) + mmsg("-D: ", m); + } + + //! \brief error messages + void emsg(std::string m = "", int v = 1) const + { + if (v <= verbose) + mmsg("-E: ", m); + } + + //! \brief info messages + void imsg(std::string m = "", int v = 3) const + { + if (v <= verbose) + mmsg("-I: ", m); + } + + //! \brief warining messages + void wmsg(std::string m = "", int v = 2) const + { + if (v <= verbose) + mmsg("-W: ", m); + } + + //! \brief warining messages + void mmsg(std::ostream & o, std::string p, std::string m) const + { + o << p << w << m << std::endl; + } + + // ---------------------------------------------------------------- + //! \brief dmsg should be v level 4 + void dmsg(std::ostream & o, std::string m = "", int v = 4) const + { + mmsg(o, "-D: ", m); + } + + //! \brief ... + void emsg(std::ostream & o, std::string m = "", int v = 1) const + { + mmsg(o, "-E: ", m); + } + + //! \brief ... + void imsg(std::ostream & o, std::string m = "", int v = 3) const + { + mmsg(o, "-I: ", m); + } + + //! \brief ... + void wmsg(std::ostream & o, std::string m = "", int v = 2) const + { + mmsg(o, "-W: ", m); + } + + //! \brief ... + void msg(std::string m) const { std::cout << m << std::endl; } + + // ---------------------------------------------------------------- + //! \brief helper to show potentially empty strings + std::string tq(std::string s) const { return "'" + s + "'"; } + + //! \brief ... + std::string w; + /** + * \brief verbosity setting + * + * \verbatim + * verbose 0 - silent + * 1 - errors + * 2 - errors,warnings + * 3 - errors,warnings,info + * >= 4 - errors,warnings,info,debug4 + * - debug messages can be a various levels, debugN + * \endverbatim + */ + + //! \brief ... + int verbose{3}; + + //! \brief ... + static Msg* instance; + + private: + //! \brief ... + Msg() + { + w = ""; + verbose = 3; + } + + // ------------------------------------------------------------------- + // Msg(std::string _who="",int _verbose=3) + // : w(_who+": "), + // verbose(_verbose) + // {} + // ------------------------------------------------------------------- + //! \brief ...copy + Msg(const Msg &) = delete; + //! \brief ...move + Msg(Msg &&) = delete; + //! \brief ...assign + Msg & operator=(const Msg &) = delete; +}; + +//! \brief ... +extern std::unique_ptr msg; diff --git a/fsl/test/interp/CMakeLists.txt b/fsl/test/interp/CMakeLists.txt new file mode 100644 index 00000000..a515ba06 --- /dev/null +++ b/fsl/test/interp/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.10) +project(TestInterp) + +# Include directories +include_directories(../../fsl_interp/inc) + +set(INTERP_BIN ${CMAKE_BINARY_DIR}/bin/fsl_interp) + +# Test command +add_custom_target(run_interp_tests + COMMAND ${INTERP_BIN} + --verbose + -i syntax_tests/_1_syntax_test.fsl + -i syntax_tests/_2_syntax_test.fsl + -i syntax_tests/sample1.fsl + -i syntax_tests/all_comments.fsl + -i syntax_tests/empty_file.fsl + -i syntax_tests/syntax1.fsl + -i syntax_tests/syntax2.fsl + -i syntax_tests/test3.fsl + -i syntax_tests/test4.fsl + -o output.txt + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Running interpreter tests" +) + +# Ensure the interpreter binary is built before running tests +add_dependencies(run_interp_tests fsl_interp) + diff --git a/fsl/test/interp/Makefile b/fsl/test/interp/Makefile new file mode 100644 index 00000000..7a91706f --- /dev/null +++ b/fsl/test/interp/Makefile @@ -0,0 +1,35 @@ +.PHONY: clean default run +include ../../Vars.mk +# +INP_FILES = -i syntax_tests/_1_syntax_test.fsl \ + -i syntax_tests/_2_syntax_test.fsl \ + -i syntax_tests/sample1.fsl \ + -i syntax_tests/all_comments.fsl \ + -i syntax_tests/empty_file.fsl \ + -i syntax_tests/syntax1.fsl \ + -i syntax_tests/syntax2.fsl \ + -i syntax_tests/test3.fsl \ + -i syntax_tests/test4.fsl \ + +INTERP_BIN=../../fsl_interp/bin/fslinterp + +OUT_FILE = -o output.txt + +default: $(INTERP_BIN) + $(MAKE) test + +$(INTERP_BIN): + $(MAKE) -C ../../fsl_interp interp_only + +#TRACE=--trace_en +test: $(INTERP_BIN) + $(INTERP_BIN) --verbose $(INP_FILES) $(OUT_FILE) $(TRACE) + +help-%: + @echo $* = $($*) + +# Clean build files +clean: + rm -f ./bin/* ./obj/* + + diff --git a/fsl/test/interp/syntax_tests/_1_syntax_test.fsl b/fsl/test/interp/syntax_tests/_1_syntax_test.fsl new file mode 100644 index 00000000..be168c9d --- /dev/null +++ b/fsl/test/interp/syntax_tests/_1_syntax_test.fsl @@ -0,0 +1,406 @@ +// ---------------------------------------------------------------- +// FSL syntax test 1 +// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// TEST:shared prolog +// ---------------------------------------------------------------- +prolog plog1 +{ + isa rv64gc + uarch oly + ioput iop +} +// ---------------------------------------------------------------- +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x2f 0xf511c783 lbu x15, -175(x3) I imm is s12 +// 0x3 0xfbf78793 addi x15, x15,-65 I imm is s12 +// ---------------------------------------------------------------- +transform uf1 +{ + isa rv64gc //Isa definition should include G and compressed + uarch oly //Model will supply the uarch needed by MachineInfo.hpp + ioput iop //Model will attach iop to it's instr io structures + + gpr g0,g1,g2,g3 + s12 c1,c2 + + sequence seq_uf1(iop,rv64gc) { //TEST: optional explicit arg form + lbu g1,c1(g2) //Note G1 in the rd and rs1 positions + addi g3,g1,c2 + } + + //TEST: optional explicit arguments form + constraints cns_uf1(seq_uf1,iop,rv64gc,oly) { + _pass_ + } + + conversion cnv_uf1(seq_uf1,iop,cns_uf1) { + //TEST: automatic creation of mnemonic, "lbu_addi" + //TEST: override auto mnemonic, "lbu_addi" + instr lbu_addi + lbu_addi.mnemonic(lbu_addix) + + //TEST: automatically merge the operands and instructions in the + //sequence in the order listed. + lbu_addi.morph(seq_uf1) + iop.input.replace(seq_uf1,lbu_addi) + } +} +// ---------------------------------------------------------------- +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x2f 0xfff5c703 lbu x14,-1(x11), I imm is s12 +// 0x3 0xc799 c.beqz x15, 14 CB imm is s8 +// ---------------------------------------------------------------- +transform uf4 +{ + isa rv64gc + uarch oly + ioput iop + + //TEST: implicit arguments + sequence seq_uf4 { + lbu g1,c1(g2) + c.beqz g3,c2 + } + + gpr g1,g2,g3 + s12 c1 + //SHOULD_FAIL: s5 should be s8 + s5 c2 + + //TEST: implicit arguments + constraints cns_uf4 { //showing the proposed implicit arguments feature + + //TEST: redundant _pass_ + _pass_ + } + + //TEST: implicit arguments + conversion cnv_uf4 { + instr lbu_bez + //TEST: morph command + lbu_bez.morph(seq_uf4) + } +} +// ---------------------------------------------------------------- +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x33 0xf6b41623 sh x11,-148(x8) S s12 +// 0x2f 0x01e74783 lbu x15, 0(x14) I s12 +// ---------------------------------------------------------------- +//TEST: non-typical clause ordering +transform uf8 +{ + //TEST: UID sequence + sequence seq_uf8 { + 0x33 + 0x2f + } + + ioput iop + + conversion cnv_uf8 { + instr ins_uf8 + lbu_bez.morph(seq_uf8) + } + + //TEST: no explicit constraints + constraints cns_uf8 { + _pass_ + } + + isa rv64gc + uarch oly +} +// ---------------------------------------------------------------- +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x35 0xe290 sd x12,0(x13) CS u5 +// 0x35 0xf6743023 sd x7,-160(x8) S s12 +// ---------------------------------------------------------------- +transform uf10 +{ + //TEST: shared external prolog + prolog plog1 + + gpr g1,g2,g3,g4 + u5 c1 + s12 c2 + + //showing the UID version of a sequence + sequence seq_uf10 { + sd g1,c1(g2) + sd g3,c2(g4) + } + + constraints cns_uf10 { + //TEST: inequality syntax + g1 != g2 + g3 != g4 + g1 != g4 + //TEST implicit _pass_ + } + + //TEST: instr in-line arguments + conversion cnv_uf10 { + instr ins_uf10( + mnemonic="sdsd", + opc=0xFFFF, + src={g1,g3}, + rsx={g2,g4}, + imm={c1,c2}, + type="fused") //user assigned type + } +} +// ---------------------------------------------------------------- +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0xa 0xdebff0ef jal x1, -534 J s20 +// 0xd 0x7139 addi x2, x2, -64 CI s6 +// ---------------------------------------------------------------- +transform uf12 { + prolog plog1 + sequence seq_u12 { + jal g1,c1 + addi g2,g2,c2 + } + + gpr g1 + gpr g2 + s20 c1 + s6 c2 + + constraints cns_u12 { + _pass_ + } + + //TEST: instr method call syntax + conversion cnv_u12 { + instr anyname + anyname.mnemonic("jalsp") + anyname.opc(*) + anyname.dst(g2) + anyname.src({g1,g2}) + anyname.type("branch") + //FIXME: add emit or what ever + } +} +// ---------------------------------------------------------------- +// UF14 - 2% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x2e 0x00093783 ld x15,0(x18) I s12 +// 0x35 0xe822 sd x8,16(x2) CSS u6 +// ---------------------------------------------------------------- +transform uf14 +{ + prolog plog1 + + //TEST: reduced punctuation/boilerplate sequence + //TEST: mixed puntuation and reduced punctuation/boilerplate sequence + sequence seq_u14 { + ld g1 c1 g2 + sd g3 c2(g4) + } + + //TEST: operand variables out side constraints clause + //TEST: declare variables after use, can linker find the variables + gpr g1,g2,g3,g4 + s12 c1 + u6 c2 + + //TEST:This is to test the constraints checker + constraints cns_u14 { + g1 == x15 + g2 == x18 + g3 == x8 + g4 == x2 + c1 == 0 + c2 == 16 + } + + conversion cnv_u14 { + encoding enc_u14 + //TEST: separated methods + enc_u14.opc(0xFFFF) + // u16 opc //53:38 + // u6 c2 //37:32 + // s12 c1 //31:20 + // gpr g4 //19:15 + // gpr g3 //14:10 + // gpr g2 //9:5 + // gpr g1 //4:0 + //TEST: encode order expression + enc_u14.encode_order({opc,c2,c1,g1,g3,g2,g4}) + } +} +// ---------------------------------------------------------------- +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x34 0xf401aa23 sw x0, -172(x3) S s12 +// 0x9 0x8082 ret CR +// ---------------------------------------------------------------- +transform uf16 +{ + prolog plog1 + + sequence seq_u16 { + sw g0, c1(g1) + ret + } + + gpr g0,g1 + s12 c1 + + constraints cns_u16 { + g0 == 0 + } + + conversion cnv_u16 { + instr i_uf16 + i_uf16.morph(seq_u16) + } +} +// ---------------------------------------------------------------- +// UF18 - 2.6% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x34 0x64f72e23 sw x15,1628(x14) S s12 +// 0xa 0xdebff0ef jal x1,-534 J s20 +// ---------------------------------------------------------------- +transform uf18 +{ + prolog plog1 + + //SHOULD_WARN: g4 is defined but not used + //SHOULD_FAIL: g5 is used but not initialized + gpr g1,g2,g3,g4,g5 + s12 c1 + s20 c2 + + sequence seq_u18 { + sw x15,1628(x14) + jal x1,-534 + sw g1,c1(g2) + jal g3,c2 + } + + //TEST: expression syntax, fsl lib, comparison + constraints cns_u18 { + g1 != g2 + if(abs(c1)+abs(c2) < 1234) _pass_ + else _fail_ + } + + //TEST: expression syntax - boolean ops, intermediate variable + //FIXME: u20 cx = c2 & { 8'hff,c1 } + u20 cx = c2 + + conversion cnv_u18 { + + encoding enc_u18 + //TEST: g5 used, not initialized + //TEST: inline opc + enc_u18.encode_order({opc=0xF7FF,g1,cx,g3,g2,g5}) + } +} +// ---------------------------------------------------------------- +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x35 0xec06 sd x1, 24(x2) CSS u6 +// 0x18 0x842a mv x8, x10 CR +// ---------------------------------------------------------------- +transform uf20 +{ + prolog plog1 + sequence seq_u20 { + //TEST: odd operand naming + sd g100,c_5_0x(g__) + mv _gg_,g_share + } + + gpr g100,g__,_gg_,g_share + u6 c_5_0x + + constraints cns_u20 { + _pass_ + } + + conversion cnv_u20 { + //SHOULD_FAIL: no conversion statement(s) + _pass_ + } +} +// ---------------------------------------------------------------- +// UF22 - 2.12% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x18 0x8522 mv x10, x8 CR +// 0xa 0xfa7ff0ef jal x1, -90 J S20 +// ---------------------------------------------------------------- +transform uf22 +{ + prolog plog1 + sequence seq_u22 { + mv A, B + jal C, D + } + + gpr A,B,C + s20 D + + constraints cns_u22 { + _pass_ + } + + //TEST: concatenate operator + //TEST: sequence index and getter method +// u32 enc_seq0 = xeq_u22[0].encoding +// u32 enc_seq1 = xeq_u22[1].encoding +// u32 env_seq0 = xeq_u22[0].encoding() +// u32 env_seq1 = xeq_u22[1].encoding() + conversion cnv_u22 { + instr i_u22({xeq_u22[0].encoding,seq_u22[1].encoding}) + } +} +// ---------------------------------------------------------------- +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x35 0x00fcb023 sd x15,0(x25) S s12 +// 0x35 0xf5243823 sd x18,-176(x8) S s12 +// 0x35 0xf4943c23 sd x9, -168(x8) S s12 +// ---------------------------------------------------------------- +transform uf24 { + prolog plog1 + + gpr g1,g2,g3,g4,g5,g6 + s12 C,D,E + + sequence seq_u24 { + sd x15,0(x25) + sd x18,-176(x8) + sd x9, -168(x8) + } + + //TEST: sequence method call + //TEST: uarch method call + constraints cns_u24 { + seq_u24 <= plog1 + seq_u24.writePorts() <= plog1.oly.writePorts() + seq_u24.readPorts() <= plog1.oly.readPorts() + C.minBits <= 4 + D.minBits <= c.minBits << 1 + E.minBits <= C.width + } + + //TEST: bit range +// conversion cnv_u24 { +// instr i_u24({0xCC,c[3:0],D[4:0],E[3:0]}) +// } + +} diff --git a/fsl/test/interp/syntax_tests/_2_syntax_test.fsl b/fsl/test/interp/syntax_tests/_2_syntax_test.fsl new file mode 100644 index 00000000..43d8aa4c --- /dev/null +++ b/fsl/test/interp/syntax_tests/_2_syntax_test.fsl @@ -0,0 +1,366 @@ +// ---------------------------------------------------------------- +// Fusion group FSL definition set for dhrystone +// TODO: record dhrystone compile options used +// +// ISA definition files are the defined in +// mavis isa_rv64g.json isa_rv64c.json +// +// This example is using olympia and mavis to help make the +// discussion concrete. But mapping of the rv64gc and oly +// names for isa and uarch can be independent of the specifics +// of Mavis (isa def) and Olympia (riscv-perf-model). +// +// See FSL_ENCODING_FORMATS.md file for RISC-V encoding reference +// $TOP/utils/fusion/FSL_ENCODING_FORMATS.md +// +// 188390 instructions in small test case trace +// +// ---------------------------------------------------------------- +// Shared prolog +// ---------------------------------------------------------------- +prolog plg +{ + isa rv64gc + uarch oly + ioput iop +} +// ---------------------------------------------------------------- +// UF1 - 11.7% of trace +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x2f 0xf511c783 lbu x15, -175(x3) I imm is s12 +// 0x0d 0xfbf78793 addi x15, x15,-65 I imm is s12 +// ---------------------------------------------------------------- +transform uf1 +{ + prolog plg + //if there are no constraints the explicit constraints clause is not needed + //constraints cns_uf1 { _pass_ } + //If the conversion is a morph of the sequence, this + //sequence seq_uf1 { 0x2f 0x0d } + //conversion cnv_uf1 { plg.iop.input.replace(seq_uf1,instr(morph(seq_uf1))) } + //is replaced by this: + sequence { 0x2f 0x0d } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x2f 0xfff5c703 lbu x14,-1(x11), I imm is s12 +// 0x03 0xc799 c.beqz x15, 14 CB imm is s8 +// ---------------------------------------------------------------- +transform uf4 +{ + prolog plg + sequence { 0x2f 0x3 } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF8 - minimal +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x33 0xf6b41623 sh x11,-148(x8) S s12 +// 0x2f 0x01e74783 lbu x15, 0(x14) I s12 +// ---------------------------------------------------------------- +transform uf8 +{ + prolog plg + sequence { 0x33 0x2f } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF10 - 3.4% +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x35 0xe290 sd x12,0(x13) CS u5 +// 0x35 0xf6743023 sd x7,-160(x8) S s12 +// ---------------------------------------------------------------- +transform uf10 +{ + prolog plg + sequence { 0x35 0x35 } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF12 - 3.4% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0xa 0xdebff0ef jal x1, -534 J s20 +// 0xd 0x7139 addi x2, x2, -64 CI s6 +// ---------------------------------------------------------------- +transform uf12 { + prolog plg + sequence { 0xa 0xd } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF14 - 2% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x2e 0x00093783 ld x15,0(x18) I s12 +// 0x35 0xe822 sd x8,16(x2) CSS u6 +// ---------------------------------------------------------------- +transform uf14 +{ + prolog plg + sequence { 0x2e 0x35 } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF16 - 3.2% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x34 0xf401aa23 sw x0, -172(x3) S s12 +// 0x9 0x8082 ret CR +// ---------------------------------------------------------------- +transform uf16 +{ + prolog plg + sequence { 0x34 0x09 } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF18 - 2.6% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x34 0x64f72e23 sw x15,1628(x14) S s12 +// 0xa 0xdebff0ef jal x1,-534 J s20 +// ---------------------------------------------------------------- +transform uf18 +{ + prolog plg + sequence { 0x34 0x0a } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF20 - 3.2% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x35 0xec06 sd x1, 24(x2) CSS u6 +// 0x18 0x842a mv x8, x10 CR +// ---------------------------------------------------------------- +transform uf20 +{ + prolog plg + sequence { 0x35 0x18 } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF22 - 2.12% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x18 0x8522 mv x10, x8 CR +// 0xa 0xfa7ff0ef jal x1, -90 J S20 +// ---------------------------------------------------------------- +transform uf22 +{ + prolog plg + sequence { 0x18 0xa } + conversion { plg.iop.input.replace(_morph_) } +} +// ---------------------------------------------------------------- +// UF24 - 3.4% +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x35 0x00fcb023 sd x15,0(x25) S s12 +// 0x35 0xf5243823 sd x18,-176(x8) S s12 +// 0x35 0xf4943c23 sd x9, -168(x8) S s12 +// ---------------------------------------------------------------- +transform uf24 +{ + + prolog plg + gpr g1,g2,g3,g4,g5,g6 + s12 C,D,E + + sequence seq_uf24 { + sd g1, c1(g2) + sd g3, c2(g4) + sd g5, c3(g6) + } + + //The only constraints on this tuple are wr/rd port limits + //we do not need to test the operands only the wr/rd port + //requirements of the combined operand set. Within those + //limits any combination of operands will do. + constraints cns_uf24 { + seq_uf24.writePorts() <= plg.oly.writePorts() + seq_uf24.readPorts() <= plg.oly.readPorts() + } + + // This is a generic transform but with mnemonic assigned + conversion { + instr i_uf24(morph(seq_uf24)) + plg.iop.input.replace(seq_uf24,i_uf24) + } +} +// ---------------------------------------------------------------- +// UF24_example - This version has artifical constraints to show +// syntax options. +// +// UID encoding mnem operands enc-type notes +// ------------------------------------------------------------- +// 0x35 0x00fcb023 sd x15,0(x25) S s12 +// 0x35 0xf5243823 sd x18,-176(x8) S s12 +// 0x35 0xf4943c23 sd x9, -168(x8) S s12 +// ---------------------------------------------------------------- +transform uf24_example +{ + prolog plg + gpr g1,g2,g3,g4,g5,g6 + s12 C,D,E + + sequence seq_uf24_example { + sd g1, c1(g2) + sd g3, c2(g4) + sd g5, c3(g6) + } + + // We could do these constraints all in one block but what is below + // is the example for constraints composition + + //Constraint: the combined encoding for the immediates <= 24bits + //Constraint: the number of wr/rd ports must be compatible with + // the micro architecture limits expressed in plg.oly + + //This constraint checks the ranges on the immediates + //If this fails the fusion group can not be matched + constraints cns_uf24_examplea { + fsl.requiredBits(c1) <= 8 + fsl.requiredBits(c2) <= 8 + fsl.requiredBits(c3) <= 8 + } + + //This constraint just checks for read/write port limits, pass/fail + // + // Fully generalized with g1-g6 all unique represents 6 required + // read ports. If the uarch only supports 4 for example we must + // constrain the match function + // + // This is a simplified all or nothing constraint + constraints cns_uf24_exampleb { + seq_uf24_example.writePorts() <= plg.oly.writePorts() + seq_uf24_example.readPorts() <= plg.oly.readPorts() + } + + constraints cns_uf24_examplec { + //We are going to pretend we can only accept 24 bits of immediate + //8 for each instruction + fsl.requiredBits(c1) <= 8 //if any of these are not true + fsl.requiredBits(c2) <= 8 //the clause exits with _fail_ + fsl.requiredBits(c3) <= 8 + } + + //Given the way it's coded above this is redundant + if(!cns_uf24_examplea || !cns_uf24_exampleb || !cns_uf24_examplec) { _fail_ } + + //The encoding extracts the common info from the S-type format + // S-type + // |---------------------------------------------------------------------| + // | 31 25|24 20|19 15|14 12|11 7|6 0| + // |---------------------------------------------------------------------| + // | imm[11:5] | rs2 | rs1 | funct3 | imm[4:0] | opcode | + // |---------------------------------------------------------------------| + // | 7 bits | 5 bits | 5 bits | 3 bits | 5 bits | 7 bits | + // |---------------------------------------------------------------------| + // + // With the above we are going to assume that since we are executing + // the conversion clause, our machine has enough rd/wr ports so we will + // express the rs2/rs1/imm for each, but share the opcode and funct3 + // + // seq[0] seq[1] seq[0] funct3 opcode + // rs2 rs1 imm rs2 rs1 imm rs2 rs1 imm + conversion cnv_uf24_example { + // Our new encoding contains 24 bits for immediate evenly distributed + s8 c1e(fsl.encodeSigned(c1,8)) + s8 c2e(fsl.encodeSigned(c2,8)) + s8 c3e(fsl.encodeSigned(c3,8)) + + //10b of opcode extracted from the 1st seq element, {funct3,opcode} + u10 opcf = {seq_uf24_example[0][14:12],seq_uf24_example[0][6:0]} + + u13 seq0 = {seq_uf24_example[0].rs2,seq_uf24_example[0].rs1,c1e} + u13 seq1 = {seq_uf24_example[1].rs2,seq_uf24_example[1].rs1,c2e} + u13 seq2 = {seq_uf24_example[2].rs2,seq_uf24_example[2].rs1,c3e} + + //Encoding simply skips the need to explicitly declare an unsigned + //bit width, it figures it out + encoding enc({seq0,seq1,seq2,opcf}) + //The mnemonic will be "i_uf24_example" + instr i_uf24_example(encoding(enc)) + } +} + +// ---------------------------------------------------------------- +// Using the sequence composition syntax +// ---------------------------------------------------------------- +prolog plg +{ + isa rv64gc + uarch oly + ioput iop +} + +transform composition +{ + prolog plg //new: prolog can be external and shared +// gpr g1..9 //new: variable naming expansion syntax + + //setof is a collection type + //hasAttr will scan the contents of the isa specification named rv64gc + //for objects with the rtype and logical attributes, 'rtype' and 'logical' + //must be known to the isa object. + setof r_bools = plg.rv64gc.hasAttr(rtype).hasAttr(logical) + + //If the constraints or conversion clauses access g1..g9 then + //it would be written this way: + sequence comp_seq_a { + r_bools g1, g2, g3 + r_bools g4, g5, g6 + r_bools g7, g8, g9 + } + + //Since the constraints do not care about which values g1..9 + //hold this can be written as simply + sequence comp_seq_b { + r_bools + r_bools + r_bools + } + + //These are redundant, only _a or _b is really needed depending + //on the sequence used. + constraints { + comp_seq_a.writePorts() <= plg.oly.writePorts() + comp_seq_a.readPorts() <= plg.oly.readPorts() + comp_seq_b.writePorts() <= plg.oly.writePorts() + comp_seq_b.readPorts() <= plg.oly.readPorts() + } + + //fsl is the standard library equivalent + //morph() combines the sequence as specified by the + //user defined function object registered with the Fusion API + //by default this just calls the mavis equivalent + conversion { + //declare an instruction object, initialize using the fsl.morph() + //operation performed on the sequence + instr i_comp(fsl.morph(comp_seq_b)) + + //by default the mnemonic is the same as the instr object name. + //this can be overridden + i_comp.mnemonic("r_bool") + + //this is using the replace idiom, the sequence objects in .input + //are removed and replaced with the instruction created by morphing. + plg.iop.input.replace(comp_seq_b,i_comp) + } +} + diff --git a/fsl/test/interp/syntax_tests/all_comments.fsl b/fsl/test/interp/syntax_tests/all_comments.fsl new file mode 100644 index 00000000..92d7237f --- /dev/null +++ b/fsl/test/interp/syntax_tests/all_comments.fsl @@ -0,0 +1,47 @@ +// ========================================================= +// THIS IS OUT OF DATE, KEPT FOR REFERENCE AS LIBRARY +// STYLE +// ========================================================= +//transform fs1 { +// isa rv64g +// uarch oly1 +// ioput in_seq +// sequence seq1(in_seq,rv64g) +// constraints cons1(seq1,in_seq,rv64g,oly1) +// transform t1(seq1,cons1) +// +//} +// +////proto sequence _id_(input_seq,isa) +//sequence seq1(in_seq,rv64g) { +// c.lui g1, c1 +// c.addi g1, g1, c2 +// c.xor g2, g2, g1 +// c.slli g2, g2, c3 +// c.srli g2, c3 +//} +// +////proto constraints _id_(sequence,input_seq,isa,uarch) +//constraints cons1(seq1,in_seq,rv64g,oly1) { +// gpr g1,g2 +// g1 != g2 +//} +// +////proto transform _id_(sequence,constraints) +//transform t1(seq1,cons1) { +// encoding word1(seq1,opc=0x234) +//// emit(word1) +//} +// +////proto encoding _id_(sequence,constant) +//encoding word1(seq1,opc) { +// u10 opc //57:48 unsigned 10b +// u6 c3 //47:42 unsigned 6b +// s12 c2 //41:30 signed 12b +// s20 c1 //29:10 signed 20b +// gpr g1 //9:5 gpr 5b +// gpr g2 //4:0 gpr 5b +// +// //this is an operator not a function +// encode_order(opc,c3,c2,c1,g1,g2) +//} diff --git a/fsl/test/interp/syntax_tests/empty_file.fsl b/fsl/test/interp/syntax_tests/empty_file.fsl new file mode 100644 index 00000000..e69de29b diff --git a/fsl/test/interp/syntax_tests/sample1.fsl b/fsl/test/interp/syntax_tests/sample1.fsl new file mode 100644 index 00000000..0a77152c --- /dev/null +++ b/fsl/test/interp/syntax_tests/sample1.fsl @@ -0,0 +1,35 @@ +// ========================================================= +// ========================================================= +transform fs1 +{ + isa rv64g + uarch oly1 + ioput in_seq + + gpr g1,g2 + + sequence seq1(in_seq,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + c.xor g2, g2, g1 + c.slli g2, g2, c3 + c.srli g2, c3 + } + + constraints cons1(seq1,in_seq,rv64g,oly1) { + g1 != g2 + } + + u10 _opc(0x234) //57:48 unsigned 10b + u6 c3 //47:42 unsigned 6b + s12 c2 //41:30 signed 12b + s20 c1 //29:10 signed 20b + gpr g1 //9:5 gpr 5b + gpr g2 //4:0 gpr 5b + + conversion t1(seq1,cons1) { + encoding word1 + word1.opc(_opc) + word1.encode_order({opc,c3,c2,c1,g1,g2}) + } +} diff --git a/fsl/test/interp/syntax_tests/syntax1.fsl b/fsl/test/interp/syntax_tests/syntax1.fsl new file mode 100644 index 00000000..203c3a1f --- /dev/null +++ b/fsl/test/interp/syntax_tests/syntax1.fsl @@ -0,0 +1,12 @@ +// Empty definition +/* + Block comment +*/ +transform t1 { //end of line +/* in line block */ +} + +transform /* messy keywords */ t2 /* messy symbols */ { +/* in line block */ +/* here */ } // +// end of file comment diff --git a/fsl/test/interp/syntax_tests/syntax2.fsl b/fsl/test/interp/syntax_tests/syntax2.fsl new file mode 100644 index 00000000..25344606 --- /dev/null +++ b/fsl/test/interp/syntax_tests/syntax2.fsl @@ -0,0 +1,36 @@ +//This is the common test case +transform fs1 { + + isa rv64g + uarch oly1 + ioput in_seq + + sequence seq1(in_seq,rv64g) { + c.lui g1, c1 + c.addi g1, g1, c2 + _req_ + c.xor g2, g2, g1 + c.slli g2, g2, c3 + _opt_ + c.srli g2, c3 + } + + gpr g1,g2 + + constraints cns1(seq1,in_seq,rv64g,oly1) { + g1 != g2 + } + + conversion cnv1(seq1,cons1) { + encoding word1 + // u10 opc //57:48 unsigned 10b + // u6 c3 //47:42 unsigned 6b + // s12 c2 //41:30 signed 12b + // s20 c1 //29:10 signed 20b + // gpr g1 //9:5 gpr 5b + // gpr g2 //4:0 gpr 5b + word1.encode_order({opc=0x234,c3,c2,c1,g1,g2}) + in_seq.input.replace(cns1,word1) + } +} + diff --git a/fsl/test/interp/syntax_tests/test3.fsl b/fsl/test/interp/syntax_tests/test3.fsl new file mode 100644 index 00000000..a3563c40 --- /dev/null +++ b/fsl/test/interp/syntax_tests/test3.fsl @@ -0,0 +1,46 @@ +//// ========================================================= +//// FUTURE FEATURE: the library form of transform expression +//// ========================================================= +//transform fs1 { +// +// isa rv64g +// uarch oly1 +// ioput in_seq +// sequence seq1(in_seq,rv64g) +// constraints cons1(seq1,in_seq,rv64g,oly1) +// transform t1(seq1,cons1) +//} +// +////proto sequence _id_(input_seq,isa) +//sequence seq1(in_seq,rv64g) { +// c.lui g1, c1 +// c.addi g1, g1, c2 +// c.xor g2, g2, g1 +// c.slli g2, g2, c3 +// c.srli g2, c3 +//} +// +////proto constraints _id_(sequence,input_seq,isa,uarch) +//constraints cons1(seq1,in_seq,rv64g,oly1) { +// gpr g1,g2 +// g1 != g2 +//} +// +////proto transform _id_(sequence,constraints) +//conversion c1(seq1,cons1) { +// encoding word1(seq1,opc=0x234) +//// emit(word1) +//} +// +////proto encoding _id_(sequence,constant) +//encoding word1(seq1,opc) { +// //u10 opc 57:48 unsigned 10b +// //u6 c3 47:42 unsigned 6b +// //s12 c2 41:30 signed 12b +// //s20 c1 29:10 signed 20b +// //gpr g1 9:5 gpr 5b +// //gpr g2 4:0 gpr 5b +// +// //this is an operator not a function +// encode_order(opc,c3,c2,c1,g1,g2) +//} diff --git a/fsl/test/interp/syntax_tests/test4.fsl b/fsl/test/interp/syntax_tests/test4.fsl new file mode 100644 index 00000000..e4e56d0a --- /dev/null +++ b/fsl/test/interp/syntax_tests/test4.fsl @@ -0,0 +1,76 @@ +//// ========================================================= +//// FUTURE FEATURE: the library form of transform expression +//// ========================================================= +//fusion fs1 { +// sequence seq1 { +// c.lui g1, c1 +// c.addi g1, g1, c2 +// c.xor g2, g2, g1 +// c.slli g2, g2, c3 +// c.srli g2, c3 +// } +// +// constraints cons1 { +// gpr g1,g2 +// s20 c1 +// s12 c2 +// u6 c3 +// +// g1 != g2 +// } +// +// iword word1 { +// u1 f //59 1b +// u1 c //58 1b +// u10 fopc //57:48 unsigned 10b +// u6 c3 //47:42 unsigned 6b +// s12 c2 //41:30 signed 12b +// s20 c1 //29:10 signed 20b +// gpr g1 //9:5 gpr 5b +// gpr g2 //4:0 gpr 5b +// +// encode_order(f,c,fopc,c3,c2,c1,g1,g2) +// } +// +// transform T1 { +// encoding word1(f=1,c=0,S1) +// } +//} +//// ========================================================= +//sequence S1_A { +// li g1,c1 +// li g2,c1 +// li g3,c1 +// li g4,c1 +//} +// +//constraints C1_A { +// gpr g1,g2,g3,g4 +// u12 c1 +// g1 != g2 != g3 != g4 +// c1 == 0 +//} +// +//iword word2 { +// u1 f //59 1b +// u1 c //58 1b +// u10 fopc //57:48 unsigned 10b +// u6 c3 //47:42 unsigned 6b +// s12 c2 //41:30 signed 12b +// s20 c1 //29:10 signed 20b +// gpr g1 //9:5 gpr 5b +// gpr g2 //4:0 gpr 5b +// +// encode_order(f,c,fopc,c3,c2,c1,g1,g2) +//} +// +//transform T1 { +// encoding word2(f=1,c=0,S1) +//} +// +//fusion fs2 { +// sequence S1_A() +// constraints C1_A(S1_A) +// transform T1_A(S1_A) +//} +// diff --git a/fsl/version.txt b/fsl/version.txt new file mode 100644 index 00000000..2e2a48e3 --- /dev/null +++ b/fsl/version.txt @@ -0,0 +1 @@ +jeffnye/cmake_conversion From 182401d06c6d7b65cc8820b8d3fe085eb9573ef8 Mon Sep 17 00:00:00 2001 From: Knute Lingaard Date: Fri, 4 Jul 2025 10:40:22 -0500 Subject: [PATCH 3/4] Moved stf library forward --- stf_lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stf_lib b/stf_lib index b874cc0c..ebe08928 160000 --- a/stf_lib +++ b/stf_lib @@ -1 +1 @@ -Subproject commit b874cc0c8dc6a7e95fe00c2f9cd8e4504270d395 +Subproject commit ebe08928f4ceeef65a2275fb3e177ce07c99c2bc From 13c6459a3d668f7779daeeba194eca9c6c3b1310 Mon Sep 17 00:00:00 2001 From: Knute Lingaard Date: Fri, 4 Jul 2025 10:40:37 -0500 Subject: [PATCH 4/4] Removed unused header file --- core/rename/Rename.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/core/rename/Rename.cpp b/core/rename/Rename.cpp index eef7639e..ebd8023e 100644 --- a/core/rename/Rename.cpp +++ b/core/rename/Rename.cpp @@ -10,7 +10,6 @@ #include "rename/Rename.hpp" #include "sparta/events/StartupEvent.hpp" #include "sparta/app/FeatureConfiguration.hpp" -#include "sparta/report/DatabaseInterface.hpp" namespace olympia {