├── .clang-format ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── CMakeLists.txt.in ├── README.md ├── compile_commands.json ├── include ├── verilogAST.hpp └── verilogAST │ ├── assign_inliner.hpp │ ├── concat_coalescer.hpp │ ├── make_packed.hpp │ ├── transformer.hpp │ └── zext_coalescer.hpp ├── src ├── assign_inliner.cpp ├── concat_coalescer.cpp ├── make_packed.cpp ├── transformer.cpp ├── verilogAST.cpp └── zext_coalescer.cpp └── tests ├── assign_inliner.cpp ├── basic.cpp ├── common.cpp ├── concat_coalescer.cpp ├── make_packed.cpp ├── parameterized_module.cpp ├── transformer.cpp └── zext_coalescer.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Left 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: All 15 | AllowShortIfStatementsOnASingleLine: true 16 | AllowShortLoopsOnASingleLine: true 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: true 20 | AlwaysBreakTemplateDeclarations: Yes 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: false 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | AfterExternBlock: false 33 | BeforeCatch: false 34 | BeforeElse: false 35 | IndentBraces: false 36 | SplitEmptyFunction: true 37 | SplitEmptyRecord: true 38 | SplitEmptyNamespace: true 39 | BreakBeforeBinaryOperators: None 40 | BreakBeforeBraces: Attach 41 | BreakBeforeInheritanceComma: false 42 | BreakInheritanceList: BeforeColon 43 | BreakBeforeTernaryOperators: true 44 | BreakConstructorInitializersBeforeComma: false 45 | BreakConstructorInitializers: BeforeColon 46 | BreakAfterJavaFieldAnnotations: false 47 | BreakStringLiterals: true 48 | ColumnLimit: 80 49 | CommentPragmas: '^ IWYU pragma:' 50 | CompactNamespaces: false 51 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 52 | ConstructorInitializerIndentWidth: 4 53 | ContinuationIndentWidth: 4 54 | Cpp11BracedListStyle: true 55 | DerivePointerAlignment: true 56 | DisableFormat: false 57 | ExperimentalAutoDetectBinPacking: false 58 | FixNamespaceComments: true 59 | ForEachMacros: 60 | - foreach 61 | - Q_FOREACH 62 | - BOOST_FOREACH 63 | IncludeBlocks: Preserve 64 | IncludeCategories: 65 | - Regex: '^' 66 | Priority: 2 67 | - Regex: '^<.*\.h>' 68 | Priority: 1 69 | - Regex: '^<.*' 70 | Priority: 2 71 | - Regex: '.*' 72 | Priority: 3 73 | IncludeIsMainRegex: '([-_](test|unittest))?$' 74 | IndentCaseLabels: true 75 | IndentPPDirectives: None 76 | IndentWidth: 2 77 | IndentWrappedFunctionNames: false 78 | JavaScriptQuotes: Leave 79 | JavaScriptWrapImports: true 80 | KeepEmptyLinesAtTheStartOfBlocks: false 81 | MacroBlockBegin: '' 82 | MacroBlockEnd: '' 83 | MaxEmptyLinesToKeep: 1 84 | NamespaceIndentation: None 85 | ObjCBinPackProtocolList: Never 86 | ObjCBlockIndentWidth: 2 87 | ObjCSpaceAfterProperty: false 88 | ObjCSpaceBeforeProtocolList: true 89 | PenaltyBreakAssignment: 2 90 | PenaltyBreakBeforeFirstCallParameter: 1 91 | PenaltyBreakComment: 300 92 | PenaltyBreakFirstLessLess: 120 93 | PenaltyBreakString: 1000 94 | PenaltyBreakTemplateDeclaration: 10 95 | PenaltyExcessCharacter: 1000000 96 | PenaltyReturnTypeOnItsOwnLine: 200 97 | PointerAlignment: Left 98 | RawStringFormats: 99 | - Language: Cpp 100 | Delimiters: 101 | - cc 102 | - CC 103 | - cpp 104 | - Cpp 105 | - CPP 106 | - 'c++' 107 | - 'C++' 108 | CanonicalDelimiter: '' 109 | BasedOnStyle: google 110 | - Language: TextProto 111 | Delimiters: 112 | - pb 113 | - PB 114 | - proto 115 | - PROTO 116 | EnclosingFunctions: 117 | - EqualsProto 118 | - EquivToProto 119 | - PARSE_PARTIAL_TEXT_PROTO 120 | - PARSE_TEST_PROTO 121 | - PARSE_TEXT_PROTO 122 | - ParseTextOrDie 123 | - ParseTextProtoOrDie 124 | CanonicalDelimiter: '' 125 | BasedOnStyle: google 126 | ReflowComments: true 127 | SortIncludes: true 128 | SortUsingDeclarations: true 129 | SpaceAfterCStyleCast: false 130 | SpaceAfterTemplateKeyword: true 131 | SpaceBeforeAssignmentOperators: true 132 | SpaceBeforeCpp11BracedList: false 133 | SpaceBeforeCtorInitializerColon: true 134 | SpaceBeforeInheritanceColon: true 135 | SpaceBeforeParens: ControlStatements 136 | SpaceBeforeRangeBasedForLoopColon: true 137 | SpaceInEmptyParentheses: false 138 | SpacesBeforeTrailingComments: 2 139 | SpacesInAngles: false 140 | SpacesInContainerLiterals: true 141 | SpacesInCStyleCastParentheses: false 142 | SpacesInParentheses: false 143 | SpacesInSquareBrackets: false 144 | Standard: Auto 145 | StatementMacros: 146 | - Q_UNUSED 147 | - QT_REQUIRE_VERSION 148 | TabWidth: 8 149 | UseTab: Never 150 | ... 151 | 152 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .ignore 2 | build 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | matrix: 4 | include: 5 | - os: linux 6 | addons: 7 | apt: 8 | sources: 9 | - ubuntu-toolchain-r-test 10 | packages: 11 | - g++-7 12 | env: 13 | - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7 && GCOV=gcov-7" 14 | 15 | - os: osx 16 | osx_image: xcode10.2 17 | env: 18 | - MATRIX_EVAL="GCOV=gcov" 19 | 20 | before_install: 21 | - eval "${MATRIX_EVAL}" 22 | 23 | script: 24 | - mkdir build 25 | - cd build 26 | - cmake -DCOVERAGE=1 -DVERILOGAST_BUILD_TESTS=ON .. 27 | - cmake --build . 28 | - ctest 29 | # Check that installation works 30 | - sudo make install 31 | - | 32 | if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then 33 | test -f /usr/local/lib/libverilogAST.dylib 34 | else 35 | test -f /usr/local/lib/libverilogAST.so 36 | fi 37 | - test -f /usr/local/include/verilogAST.hpp 38 | 39 | after_success: 40 | - bash <(curl -s https://codecov.io/bash) 41 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | set(CMAKE_CXX_STANDARD 17) 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") 5 | 6 | option(VERILOGAST_BUILD_TESTS "Build all of verilogAST's own tests." OFF) 7 | 8 | project(verilogAST) 9 | set(COVERAGE OFF CACHE BOOL "Coverage") 10 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Werror") 11 | 12 | 13 | if (COVERAGE) 14 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g --coverage") 15 | endif() 16 | 17 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") 18 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") 19 | 20 | include_directories( 21 | ${PROJECT_SOURCE_DIR}/include/ 22 | ) 23 | 24 | set(LIB_SOURCES 25 | src/verilogAST.cpp 26 | src/transformer.cpp 27 | src/assign_inliner.cpp 28 | src/concat_coalescer.cpp 29 | src/zext_coalescer.cpp 30 | src/make_packed.cpp 31 | ) 32 | 33 | set(LIBRARY_NAME verilogAST) 34 | add_library(${LIBRARY_NAME} SHARED ${LIB_SOURCES}) 35 | 36 | if (VERILOGAST_BUILD_TESTS) 37 | # Download and unpack googletest at configure time 38 | configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) 39 | execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . 40 | RESULT_VARIABLE result 41 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) 42 | if(result) 43 | message(FATAL_ERROR "CMake step for googletest failed: ${result}") 44 | endif() 45 | execute_process(COMMAND ${CMAKE_COMMAND} --build . 46 | RESULT_VARIABLE result 47 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) 48 | if(result) 49 | message(FATAL_ERROR "Build step for googletest failed: ${result}") 50 | endif() 51 | 52 | 53 | # Add googletest directly to our build. This defines 54 | # the gtest and gtest_main targets. 55 | add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src 56 | ${CMAKE_CURRENT_BINARY_DIR}/googletest-build 57 | EXCLUDE_FROM_ALL) 58 | enable_testing() 59 | 60 | add_executable(basic tests/basic.cpp) 61 | target_link_libraries(basic gtest_main ${LIBRARY_NAME}) 62 | add_test(NAME basic_tests COMMAND basic) 63 | 64 | add_executable(parameterized_module tests/parameterized_module.cpp) 65 | target_link_libraries(parameterized_module gtest_main ${LIBRARY_NAME}) 66 | add_test(NAME parameterized_module_tests COMMAND parameterized_module) 67 | 68 | add_executable(transformer tests/transformer.cpp) 69 | target_link_libraries(transformer gtest_main ${LIBRARY_NAME}) 70 | add_test(NAME transformer_tests COMMAND transformer) 71 | 72 | add_executable(assign_inliner tests/assign_inliner.cpp) 73 | target_link_libraries(assign_inliner gtest_main ${LIBRARY_NAME}) 74 | add_test(NAME assign_inliner_tests COMMAND assign_inliner) 75 | 76 | add_executable(concat_coalescer tests/concat_coalescer.cpp) 77 | target_link_libraries(concat_coalescer gtest_main ${LIBRARY_NAME}) 78 | add_test(NAME concat_coalescer_tests COMMAND concat_coalescer) 79 | 80 | add_executable(zext_coalescer tests/zext_coalescer.cpp) 81 | target_link_libraries(zext_coalescer gtest_main ${LIBRARY_NAME}) 82 | add_test(NAME zext_coalescer_tests COMMAND zext_coalescer) 83 | 84 | add_executable(make_packed tests/make_packed.cpp) 85 | target_link_libraries(make_packed gtest_main ${LIBRARY_NAME}) 86 | add_test(NAME make_packed_tests COMMAND make_packed) 87 | endif() 88 | 89 | install(TARGETS ${LIBRARY_NAME} DESTINATION lib) 90 | install(FILES include/verilogAST.hpp DESTINATION include) 91 | install(DIRECTORY include/verilogAST DESTINATION include) 92 | -------------------------------------------------------------------------------- /CMakeLists.txt.in: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.2) 2 | 3 | project(googletest-download NONE) 4 | 5 | include(ExternalProject) 6 | ExternalProject_Add(googletest 7 | GIT_REPOSITORY https://github.com/google/googletest.git 8 | GIT_TAG main 9 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" 10 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" 11 | CONFIGURE_COMMAND "" 12 | BUILD_COMMAND "" 13 | INSTALL_COMMAND "" 14 | TEST_COMMAND "" 15 | ) 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # verilogAST-cpp 2 | [![Build Status](https://travis-ci.com/leonardt/verilogAST-cpp.svg?branch=master)](https://travis-ci.com/leonardt/verilogAST-cpp) 3 | [![codecov](https://codecov.io/gh/leonardt/verilogAST-cpp/branch/master/graph/badge.svg?token=P7tdc1K0CH)](https://codecov.io/gh/leonardt/verilogAST-cpp/) 4 | 5 | C++17 Implementation of an AST for Verilog code generation 6 | 7 | ## Dependencies 8 | * Compiler: Tested using gcc-7 on Ubuntu trusty (14.04.5) and Xcode 10.2.1 on macOS 10.14. 9 | 10 | ## Building 11 | ``` 12 | mkdir build 13 | cd build 14 | cmake .. 15 | cmake --build . 16 | ``` 17 | 18 | ## Testing 19 | ``` 20 | # inside build directory 21 | cmake -DVERILOGAST_BUILD_TESTS=ON .. 22 | cmake --build . 23 | ctest 24 | ``` 25 | 26 | ## Style 27 | All changes should be processed using `clang-format` before merging into 28 | master. 29 | -------------------------------------------------------------------------------- /compile_commands.json: -------------------------------------------------------------------------------- 1 | build/compile_commands.json -------------------------------------------------------------------------------- /include/verilogAST.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef VERILOGAST_H 3 | #define VERILOGAST_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include // std::pair 11 | #include 12 | #include 13 | 14 | namespace verilogAST { 15 | 16 | template 17 | class WithComment : public T { 18 | std::string comment; 19 | 20 | public: 21 | WithComment(std::unique_ptr node, std::string comment) 22 | : T(std::move(node)), comment(comment){}; 23 | 24 | std::string toString() override { 25 | return T::toString() + "/*" + this->comment + "*/"; 26 | }; 27 | ~WithComment(){}; 28 | }; 29 | 30 | template 31 | std::unique_ptr> AddComment(std::unique_ptr node, 32 | std::string comment) { 33 | return std::make_unique>(std::move(node), comment); 34 | } 35 | 36 | class Node { 37 | public: 38 | virtual std::string toString() = 0; 39 | virtual ~Node() = default; 40 | }; 41 | 42 | class Expression : public Node { 43 | protected: 44 | virtual Expression* clone_impl() const = 0; 45 | 46 | public: 47 | virtual std::string toString() = 0; 48 | virtual ~Expression() = default; 49 | auto clone() const { return std::unique_ptr(clone_impl()); } 50 | }; 51 | 52 | enum Radix { BINARY, OCTAL, HEX, DECIMAL }; 53 | 54 | class NumericLiteral : public Expression { 55 | protected: 56 | virtual NumericLiteral* clone_impl() const override { 57 | return new NumericLiteral(this->value, this->size, this->_signed, 58 | this->radix, this->always_codegen_size); 59 | }; 60 | 61 | public: 62 | /// For now, we model values as strings because it depends on their radix 63 | // (alternatively, we could store an unsigned integer representation and 64 | // convert it during code generation) 65 | // 66 | // TODO Maybe add special toString logic for the default case? E.g. if we're 67 | // generating a 32 bit unsigned decimal literal (commonly used for indexing 68 | // into ports) then we don't need to generate the "32'd" prefix 69 | std::string value; 70 | unsigned int size; // default 32 71 | bool _signed; // default false 72 | Radix radix; // default decimal 73 | // always generate size prefix (default false will not codegen size for 32 74 | // bit literals) 75 | bool always_codegen_size = false; 76 | 77 | NumericLiteral(std::string value, unsigned int size, bool _signed, 78 | Radix radix, bool always_codegen_size) 79 | : value(value), 80 | size(size), 81 | _signed(_signed), 82 | radix(radix), 83 | always_codegen_size(always_codegen_size){}; 84 | 85 | NumericLiteral(std::string value, unsigned int size, bool _signed, 86 | Radix radix) 87 | : value(value), size(size), _signed(_signed), radix(radix){}; 88 | 89 | NumericLiteral(std::string value, unsigned int size, bool _signed) 90 | : value(value), size(size), _signed(_signed), radix(Radix::DECIMAL){}; 91 | 92 | NumericLiteral(std::string value, unsigned int size) 93 | : value(value), size(size), _signed(false), radix(Radix::DECIMAL){}; 94 | 95 | explicit NumericLiteral(std::string value) 96 | : value(value), size(32), _signed(false), radix(Radix::DECIMAL){}; 97 | 98 | NumericLiteral(std::string value, Radix radix) 99 | : value(value), size(32), _signed(false), radix(radix){}; 100 | 101 | std::string toString() override; 102 | auto clone() const { return std::unique_ptr(clone_impl()); } 103 | }; 104 | 105 | class Cast : public Expression { 106 | protected: 107 | virtual Cast* clone_impl() const override { 108 | return new Cast(this->width, this->expr->clone()); 109 | }; 110 | 111 | public: 112 | // integer width because we want to avoid numeric literals with ' like 2'b01 113 | unsigned int width; 114 | std::unique_ptr expr; 115 | 116 | Cast(unsigned int width, std::unique_ptr expr) 117 | : width(width), expr(std::move(expr)){}; 118 | Cast(const Cast& rhs) : width(rhs.width), expr(rhs.expr->clone()){}; 119 | auto clone() const { return std::unique_ptr(clone_impl()); } 120 | 121 | std::string toString() override; 122 | ~Cast(){}; 123 | }; 124 | 125 | // TODO also need a string literal, as strings can be used as parameter values 126 | 127 | class Identifier : public Expression { 128 | protected: 129 | virtual Identifier* clone_impl() const override { 130 | return new Identifier(*this); 131 | }; 132 | 133 | public: 134 | std::string value; 135 | 136 | explicit Identifier(std::string value); 137 | Identifier(const Identifier& rhs) : value(rhs.value){}; 138 | auto clone() const { return std::unique_ptr(clone_impl()); } 139 | 140 | bool operator==(const Identifier& rhs) { return (this->value == rhs.value); } 141 | 142 | std::string toString() override; 143 | ~Identifier(){}; 144 | }; 145 | 146 | class Attribute : public Expression { 147 | protected: 148 | virtual Attribute* clone_impl() const override { 149 | return new Attribute(*this); 150 | }; 151 | 152 | public: 153 | std::variant, std::unique_ptr> value; 154 | std::string attr; 155 | 156 | Attribute( 157 | std::variant, std::unique_ptr> 158 | value, 159 | std::string attr) 160 | : value(std::move(value)), attr(attr){}; 161 | 162 | Attribute(const Attribute& rhs) 163 | : value(std::visit( 164 | [](auto&& val) -> std::variant, 165 | std::unique_ptr> { 166 | return val->clone(); 167 | }, 168 | rhs.value)), 169 | attr(rhs.attr){}; 170 | 171 | std::unique_ptr clone() const { 172 | return std::unique_ptr(clone_impl()); 173 | } 174 | 175 | bool operator==(const Attribute& rhs) { 176 | return (this->value == rhs.value && this->attr == rhs.attr); 177 | } 178 | 179 | std::string toString() override; 180 | ~Attribute(){}; 181 | }; 182 | 183 | class String : public Expression { 184 | protected: 185 | virtual String* clone_impl() const override { return new String(*this); }; 186 | 187 | public: 188 | std::string value; 189 | 190 | explicit String(std::string value) : value(value){}; 191 | String(const String& rhs) : value(rhs.value){}; 192 | 193 | std::string toString() override; 194 | ~String(){}; 195 | auto clone() const { return std::unique_ptr(clone_impl()); } 196 | }; 197 | 198 | class Slice : public Expression { 199 | protected: 200 | virtual Slice* clone_impl() const override { 201 | return new Slice(this->expr->clone(), this->high_index->clone(), 202 | this->low_index->clone()); 203 | }; 204 | 205 | public: 206 | std::unique_ptr expr; 207 | std::unique_ptr high_index; 208 | std::unique_ptr low_index; 209 | 210 | Slice(std::unique_ptr expr, 211 | std::unique_ptr high_index, 212 | std::unique_ptr low_index) 213 | : expr(std::move(expr)), 214 | high_index(std::move(high_index)), 215 | low_index(std::move(low_index)){}; 216 | Slice(const Slice& rhs) 217 | : expr(rhs.expr->clone()), 218 | high_index(rhs.high_index->clone()), 219 | low_index(rhs.low_index->clone()){}; 220 | std::string toString() override; 221 | ~Slice(){}; 222 | auto clone() const { return std::unique_ptr(clone_impl()); } 223 | }; 224 | 225 | class Index : public Expression { 226 | protected: 227 | virtual Index* clone_impl() const override { 228 | return new Index(this->clone_index_value(), this->index->clone()); 229 | }; 230 | 231 | public: 232 | std::variant, std::unique_ptr, 233 | std::unique_ptr, std::unique_ptr> 234 | value; 235 | std::unique_ptr index; 236 | 237 | Index(std::variant, std::unique_ptr, 238 | std::unique_ptr, std::unique_ptr> 239 | value, 240 | std::unique_ptr index) 241 | : value(std::move(value)), index(std::move(index)){}; 242 | 243 | Index(const Index& rhs) 244 | : value(rhs.clone_index_value()), index(rhs.index->clone()){}; 245 | 246 | std::string toString() override; 247 | ~Index(){}; 248 | auto clone() const { return std::unique_ptr(clone_impl()); } 249 | 250 | private: 251 | std::variant, std::unique_ptr, 252 | std::unique_ptr, std::unique_ptr> 253 | clone_index_value() const { 254 | return std::visit( 255 | [](auto&& val) 256 | -> std::variant, 257 | std::unique_ptr, std::unique_ptr, 258 | std::unique_ptr> { return val->clone(); }, 259 | this->value); 260 | } 261 | }; 262 | 263 | namespace BinOp { 264 | enum BinOp { 265 | LSHIFT, 266 | RSHIFT, 267 | AND, 268 | LAND, 269 | OR, 270 | LOR, 271 | XOR, 272 | EQ, 273 | NEQ, 274 | ADD, 275 | SUB, 276 | MUL, 277 | DIV, 278 | POW, 279 | MOD, 280 | ALSHIFT, 281 | ARSHIFT, 282 | LT, 283 | LTE, 284 | GT, 285 | GTE 286 | }; 287 | } 288 | 289 | class BinaryOp : public Expression { 290 | protected: 291 | virtual BinaryOp* clone_impl() const override { 292 | return new BinaryOp(this->left->clone(), this->op, this->right->clone()); 293 | }; 294 | 295 | public: 296 | std::unique_ptr left; 297 | BinOp::BinOp op; 298 | std::unique_ptr right; 299 | 300 | BinaryOp(std::unique_ptr left, BinOp::BinOp op, 301 | std::unique_ptr right) 302 | : left(std::move(left)), op(op), right(std::move(right)){}; 303 | BinaryOp(const BinaryOp& rhs) 304 | : left(rhs.left->clone()), op(rhs.op), right(rhs.right->clone()){}; 305 | 306 | std::string toString() override; 307 | ~BinaryOp(){}; 308 | auto clone() const { return std::unique_ptr(clone_impl()); } 309 | }; 310 | 311 | namespace UnOp { 312 | enum UnOp { 313 | NOT, 314 | INVERT, 315 | AND, 316 | NAND, 317 | OR, 318 | NOR, 319 | XOR, 320 | NXOR, 321 | XNOR, // TODO ~^ vs ^~? 322 | PLUS, 323 | MINUS 324 | }; 325 | } 326 | 327 | class UnaryOp : public Expression { 328 | protected: 329 | virtual UnaryOp* clone_impl() const override { 330 | return new UnaryOp(this->operand->clone(), this->op); 331 | }; 332 | 333 | public: 334 | std::unique_ptr operand; 335 | 336 | UnOp::UnOp op; 337 | 338 | UnaryOp(std::unique_ptr operand, UnOp::UnOp op) 339 | : operand(std::move(operand)), op(op){}; 340 | UnaryOp(const UnaryOp& rhs) : operand(rhs.operand->clone()), op(rhs.op){}; 341 | 342 | std::string toString() override; 343 | ~UnaryOp(){}; 344 | auto clone() const { return std::unique_ptr(clone_impl()); } 345 | }; 346 | 347 | class TernaryOp : public Expression { 348 | protected: 349 | virtual TernaryOp* clone_impl() const override { 350 | return new TernaryOp(this->cond->clone(), this->true_value->clone(), 351 | this->false_value->clone()); 352 | }; 353 | 354 | public: 355 | std::unique_ptr cond; 356 | std::unique_ptr true_value; 357 | std::unique_ptr false_value; 358 | 359 | TernaryOp(std::unique_ptr cond, 360 | std::unique_ptr true_value, 361 | std::unique_ptr false_value) 362 | : cond(std::move(cond)), 363 | true_value(std::move(true_value)), 364 | false_value(std::move(false_value)){}; 365 | TernaryOp(const TernaryOp& rhs) 366 | : cond(rhs.cond->clone()), 367 | true_value(rhs.true_value->clone()), 368 | false_value(rhs.false_value->clone()){}; 369 | 370 | std::string toString() override; 371 | ~TernaryOp(){}; 372 | auto clone() const { return std::unique_ptr(clone_impl()); } 373 | }; 374 | 375 | class Concat : public Expression { 376 | protected: 377 | virtual Concat* clone_impl() const override { 378 | std::vector> new_args; 379 | for (const auto& arg : this->args) { 380 | new_args.push_back(arg->clone()); 381 | } 382 | return new Concat(std::move(new_args)); 383 | }; 384 | 385 | public: 386 | std::vector> args; 387 | bool unpacked; 388 | 389 | explicit Concat(std::vector> args, bool unpacked = false) 390 | : args(std::move(args)), unpacked(unpacked){}; 391 | Concat(const Concat& rhs) { 392 | for (const auto& arg : rhs.args) args.push_back(arg->clone()); 393 | this->unpacked = rhs.unpacked; 394 | }; 395 | 396 | std::string toString() override; 397 | auto clone() const { return std::unique_ptr(clone_impl()); } 398 | }; 399 | 400 | class Replicate : public Expression { 401 | protected: 402 | virtual Replicate* clone_impl() const override { 403 | return new Replicate(this->num->clone(), this->value->clone()); 404 | }; 405 | 406 | public: 407 | std::unique_ptr num; 408 | std::unique_ptr value; 409 | 410 | Replicate(std::unique_ptr num, std::unique_ptr value) 411 | : num(std::move(num)), value(std::move(value)){}; 412 | Replicate(const Replicate& rhs) 413 | : num(rhs.num->clone()), value(rhs.value->clone()){}; 414 | 415 | std::string toString() override; 416 | auto clone() const { return std::unique_ptr(clone_impl()); } 417 | }; 418 | 419 | class NegEdge : public Node { 420 | public: 421 | std::unique_ptr value; 422 | 423 | explicit NegEdge(std::unique_ptr value) : value(std::move(value)){}; 424 | std::string toString() override; 425 | ~NegEdge(){}; 426 | }; 427 | 428 | class PosEdge : public Node { 429 | public: 430 | std::unique_ptr value; 431 | 432 | explicit PosEdge(std::unique_ptr value) : value(std::move(value)){}; 433 | std::string toString() override; 434 | ~PosEdge(){}; 435 | }; 436 | 437 | class Call { 438 | public: 439 | std::string func; 440 | std::vector> args; 441 | 442 | Call(std::string func, std::vector> args) 443 | : func(func), args(std::move(args)){}; 444 | explicit Call(std::string func) : func(func){}; 445 | std::string toString(); 446 | ~Call(){}; 447 | }; 448 | 449 | class CallExpr : public Expression, public Call { 450 | protected: 451 | virtual CallExpr* clone_impl() const override { 452 | std::vector> new_args; 453 | for (const auto& arg : this->args) { 454 | new_args.push_back(arg->clone()); 455 | } 456 | return new CallExpr(this->func, std::move(new_args)); 457 | }; 458 | 459 | public: 460 | CallExpr(std::string func, std::vector> args) 461 | : Call(std::move(func), std::move(args)){}; 462 | explicit CallExpr(std::string func) : Call(std::move(func)){}; 463 | CallExpr(const CallExpr& rhs) : Call(std::move(rhs.func)) { 464 | for (const auto& arg : rhs.args) { 465 | args.push_back(arg->clone()); 466 | } 467 | }; 468 | 469 | std::string toString() override { return Call::toString(); }; 470 | auto clone() const { return std::unique_ptr(clone_impl()); } 471 | }; 472 | 473 | enum Direction { INPUT, OUTPUT, INOUT }; 474 | 475 | // TODO: Unify with declarations? 476 | enum PortType { WIRE, REG }; 477 | 478 | class AbstractPort : public Node {}; 479 | 480 | class Vector : public Node { 481 | public: 482 | std::unique_ptr id; 483 | std::unique_ptr msb; 484 | std::unique_ptr lsb; 485 | 486 | Vector(std::unique_ptr id, std::unique_ptr msb, 487 | std::unique_ptr lsb) 488 | : id(std::move(id)), msb(std::move(msb)), lsb(std::move(lsb)){}; 489 | std::string toString() override; 490 | ~Vector(){}; 491 | }; 492 | 493 | class NDVector : public Vector { 494 | public: 495 | std::vector< 496 | std::pair, std::unique_ptr>> 497 | outer_dims; 498 | 499 | NDVector(std::unique_ptr id, std::unique_ptr msb, 500 | std::unique_ptr lsb, 501 | std::vector, 502 | std::unique_ptr>> 503 | outer_dims) 504 | : Vector(std::move(id), std::move(msb), std::move(lsb)), 505 | outer_dims(std::move(outer_dims)){}; 506 | std::string toString() override; 507 | ~NDVector(){}; 508 | }; 509 | 510 | class PackedNDVector : public NDVector { 511 | public: 512 | PackedNDVector( 513 | std::unique_ptr id, std::unique_ptr msb, 514 | std::unique_ptr lsb, 515 | std::vector< 516 | std::pair, std::unique_ptr>> 517 | outer_dims) 518 | : NDVector(std::move(id), std::move(msb), std::move(lsb), 519 | std::move(outer_dims)) {} 520 | 521 | std::string toString() override; 522 | ~PackedNDVector() = default; 523 | }; 524 | 525 | class Port : public AbstractPort { 526 | public: 527 | // Required 528 | // `` or `[n]` or `name[n:m]` 529 | std::variant, std::unique_ptr> value; 530 | 531 | // technically the following are optional (e.g. port direction/data type 532 | // can be declared in the body of the definition), but for now let's force 533 | // users to declare ports in a single, unified way for 534 | // simplicity/maintenance 535 | Direction direction; 536 | PortType data_type; 537 | 538 | Port(std::variant, std::unique_ptr> value, 539 | Direction direction, PortType data_type) 540 | : value(std::move(value)), direction(direction), data_type(data_type){}; 541 | explicit Port(std::unique_ptr port) 542 | : value(std::move(port->value)), 543 | direction(port->direction), 544 | data_type(port->data_type){}; 545 | std::string toString() override; 546 | ~Port(){}; 547 | }; 548 | 549 | class StringPort : public AbstractPort { 550 | public: 551 | std::string value; 552 | 553 | explicit StringPort(std::string value) : value(value){}; 554 | std::string toString() { return value; }; 555 | ~StringPort(){}; 556 | }; 557 | 558 | class Statement : public Node {}; 559 | 560 | class BehavioralStatement : public Statement {}; 561 | class StructuralStatement : public Statement {}; 562 | 563 | class SingleLineComment : public StructuralStatement, 564 | public BehavioralStatement { 565 | public: 566 | std::string value; 567 | std::unique_ptr statement; // optional 568 | 569 | explicit SingleLineComment(std::string value) 570 | : value(value), statement(std::unique_ptr{}){}; 571 | SingleLineComment(std::string value, std::unique_ptr statement) 572 | : value(value), statement(std::move(statement)){}; 573 | std::string toString() override; 574 | ~SingleLineComment(){}; 575 | }; 576 | 577 | class BlockComment : public StructuralStatement, public BehavioralStatement { 578 | public: 579 | std::string value; 580 | 581 | explicit BlockComment(std::string value) : value(value){}; 582 | std::string toString() { return "/*\n" + value + "\n*/"; }; 583 | ~BlockComment(){}; 584 | }; 585 | 586 | class InlineVerilog : public StructuralStatement { 587 | // Serializes into `value`, so allows the inclusion of arbitrary verilog 588 | // statement(s) in the body of a module definition. The contents of 589 | // `value` must be a valid verilog statement inside a module body. The 590 | // contents are not validated. 591 | public: 592 | std::string value; 593 | 594 | explicit InlineVerilog(std::string value) : value(value){}; 595 | std::string toString() { return value; }; 596 | ~InlineVerilog(){}; 597 | }; 598 | 599 | typedef std::vector, std::unique_ptr>, 601 | std::unique_ptr>> 602 | Parameters; 603 | 604 | typedef std::vector>> 605 | ConnectionVector; 606 | 607 | class Connections { 608 | public: 609 | Connections() : connections() {} 610 | ~Connections() = default; 611 | 612 | // Non-copyable class 613 | Connections(const Connections&) = delete; 614 | 615 | // Takes ownership of @expr. 616 | void insert(std::string name, std::unique_ptr expr) { 617 | connections.push_back(std::make_pair(name, std::move(expr))); 618 | } 619 | 620 | // Releases ownership of expression at @name if exists, othwerwise throws 621 | // error. 622 | std::unique_ptr at(std::string name) { 623 | auto is_name = [name](auto& element) { return element.first == name; }; 624 | auto it = std::find_if(connections.begin(), connections.end(), is_name); 625 | if (it != connections.end()) return std::move(it->second); 626 | throw std::runtime_error("Could not find '" + name + "'"); 627 | } 628 | 629 | ConnectionVector::iterator begin() { return connections.begin(); } 630 | ConnectionVector::iterator end() { return connections.end(); } 631 | 632 | bool empty() const { return connections.empty(); } 633 | 634 | private: 635 | ConnectionVector connections; 636 | }; 637 | 638 | class ModuleInstantiation : public StructuralStatement { 639 | public: 640 | std::string module_name; 641 | 642 | // parameter,value 643 | Parameters parameters; 644 | 645 | std::string instance_name; 646 | 647 | // NOTE: anonymous style of module connections is not supported 648 | std::unique_ptr connections; 649 | 650 | // TODO Need to make sure that the instance parameters are a subset of the 651 | // module parameters 652 | ModuleInstantiation(std::string module_name, Parameters parameters, 653 | std::string instance_name, 654 | std::unique_ptr connections) 655 | : module_name(module_name), 656 | parameters(std::move(parameters)), 657 | instance_name(instance_name), 658 | connections(std::move(connections)){}; 659 | std::string toString() override; 660 | ~ModuleInstantiation(){}; 661 | }; 662 | 663 | class Declaration : public Node { 664 | public: 665 | std::string decl; 666 | std::variant, std::unique_ptr, 667 | std::unique_ptr, std::unique_ptr> 668 | value; 669 | 670 | Declaration(std::variant, std::unique_ptr, 671 | std::unique_ptr, std::unique_ptr> 672 | value, 673 | std::string decl) 674 | : decl(decl), value(std::move(value)){}; 675 | 676 | std::string toString() override; 677 | virtual ~Declaration() = default; 678 | }; 679 | 680 | class IfMacro : public StructuralStatement { 681 | virtual std::string getMacroString() = 0; 682 | 683 | public: 684 | std::string condition_str; 685 | std::vector, 686 | std::unique_ptr>> 687 | true_body; 688 | std::vector, 689 | std::unique_ptr>> 690 | else_body; 691 | IfMacro(std::string condition_str, 692 | std::vector, 693 | std::unique_ptr>> 694 | true_body) 695 | : condition_str(condition_str), true_body(std::move(true_body)){}; 696 | IfMacro(std::string condition_str, 697 | std::vector, 698 | std::unique_ptr>> 699 | true_body, 700 | std::vector, 701 | std::unique_ptr>> 702 | else_body) 703 | : condition_str(condition_str), 704 | true_body(std::move(true_body)), 705 | else_body(std::move(else_body)){}; 706 | ~IfMacro(){}; 707 | std::string toString() override; 708 | }; 709 | 710 | class IfDef : public IfMacro { 711 | std::string getMacroString() { return "`ifdef "; }; 712 | 713 | public: 714 | IfDef(std::string condition_str, 715 | std::vector, 716 | std::unique_ptr>> 717 | body) 718 | : IfMacro(condition_str, std::move(body)){}; 719 | IfDef(std::string condition_str, 720 | std::vector, 721 | std::unique_ptr>> 722 | true_body, 723 | std::vector, 724 | std::unique_ptr>> 725 | else_body) 726 | : IfMacro(condition_str, std::move(true_body), std::move(else_body)){}; 727 | ~IfDef(){}; 728 | }; 729 | 730 | class IfNDef : public IfMacro { 731 | std::string getMacroString() { return "`ifndef "; }; 732 | 733 | public: 734 | IfNDef(std::string condition_str, 735 | std::vector, 736 | std::unique_ptr>> 737 | body) 738 | : IfMacro(condition_str, std::move(body)){}; 739 | IfNDef(std::string condition_str, 740 | std::vector, 741 | std::unique_ptr>> 742 | true_body, 743 | std::vector, 744 | std::unique_ptr>> 745 | else_body) 746 | : IfMacro(condition_str, std::move(true_body), std::move(else_body)){}; 747 | ~IfNDef(){}; 748 | }; 749 | 750 | class Wire : public Declaration { 751 | public: 752 | explicit Wire(std::variant, std::unique_ptr, 753 | std::unique_ptr, std::unique_ptr> 754 | value) 755 | : Declaration(std::move(value), "wire"){}; 756 | ~Wire(){}; 757 | }; 758 | 759 | class Reg : public Declaration { 760 | public: 761 | explicit Reg(std::variant, std::unique_ptr, 762 | std::unique_ptr, std::unique_ptr> 763 | value) 764 | : Declaration(std::move(value), "reg"){}; 765 | ~Reg(){}; 766 | }; 767 | 768 | class Assign : public Node { 769 | public: 770 | std::variant, std::unique_ptr, 771 | std::unique_ptr> 772 | target; 773 | std::unique_ptr value; 774 | std::string prefix; 775 | std::string symbol; 776 | 777 | Assign(std::variant, std::unique_ptr, 778 | std::unique_ptr> 779 | target, 780 | std::unique_ptr value, std::string prefix) 781 | : target(std::move(target)), 782 | value(std::move(value)), 783 | prefix(prefix), 784 | symbol("="){}; 785 | Assign(std::variant, std::unique_ptr, 786 | std::unique_ptr> 787 | target, 788 | std::unique_ptr value, std::string prefix, 789 | std::string symbol) 790 | : target(std::move(target)), 791 | value(std::move(value)), 792 | prefix(prefix), 793 | symbol(symbol){}; 794 | 795 | std::string toString() override; 796 | virtual ~Assign() = default; 797 | }; 798 | 799 | class ContinuousAssign : public StructuralStatement, public Assign { 800 | public: 801 | ContinuousAssign(std::variant, 802 | std::unique_ptr, std::unique_ptr> 803 | target, 804 | std::unique_ptr value) 805 | : Assign(std::move(target), std::move(value), "assign "){}; 806 | // Multiple inheritance forces us to have to explicitly state this? 807 | std::string toString() { return Assign::toString(); }; 808 | ~ContinuousAssign(){}; 809 | }; 810 | 811 | class BehavioralAssign : public BehavioralStatement {}; 812 | 813 | class BlockingAssign : public BehavioralAssign, public Assign { 814 | public: 815 | BlockingAssign(std::variant, 816 | std::unique_ptr, std::unique_ptr> 817 | target, 818 | std::unique_ptr value) 819 | : Assign(std::move(target), std::move(value), ""){}; 820 | // Multiple inheritance forces us to have to explicitly state this? 821 | std::string toString() { return Assign::toString(); }; 822 | ~BlockingAssign(){}; 823 | }; 824 | 825 | class NonBlockingAssign : public BehavioralAssign, public Assign { 826 | public: 827 | NonBlockingAssign(std::variant, 828 | std::unique_ptr, std::unique_ptr> 829 | target, 830 | std::unique_ptr value) 831 | : Assign(std::move(target), std::move(value), "", "<="){}; 832 | // Multiple inheritance forces us to have to explicitly state this? 833 | std::string toString() { return Assign::toString(); }; 834 | ~NonBlockingAssign(){}; 835 | }; 836 | 837 | class CallStmt : public BehavioralStatement, public Call { 838 | public: 839 | CallStmt(std::string func, std::vector> args) 840 | : Call(std::move(func), std::move(args)){}; 841 | explicit CallStmt(std::string func) : Call(std::move(func)){}; 842 | std::string toString() { return Call::toString() + ";"; }; 843 | }; 844 | 845 | class Star : Node { 846 | public: 847 | std::string toString() { return "*"; }; 848 | ~Star(){}; 849 | }; 850 | 851 | class Always : public StructuralStatement { 852 | public: 853 | std::vector< 854 | std::variant, std::unique_ptr, 855 | std::unique_ptr, std::unique_ptr>> 856 | sensitivity_list; 857 | std::vector> body; 858 | 859 | Always(std::vector< 860 | std::variant, std::unique_ptr, 861 | std::unique_ptr, std::unique_ptr>> 862 | sensitivity_list, 863 | std::vector> body) 864 | : body(std::move(body)) { 865 | if (sensitivity_list.empty()) { 866 | throw std::runtime_error( 867 | "vAST::Always expects non-empty sensitivity list"); 868 | } 869 | this->sensitivity_list = std::move(sensitivity_list); 870 | }; 871 | std::string toString() override; 872 | ~Always(){}; 873 | }; 874 | 875 | class If : public BehavioralStatement { 876 | public: 877 | std::unique_ptr cond; 878 | std::vector> true_body; 879 | // pair of cond + body for else if cases 880 | std::vector, 881 | std::vector>>> 882 | else_ifs; 883 | std::vector> else_body; 884 | 885 | If(std::unique_ptr cond, 886 | std::vector> true_body, 887 | std::vector, 888 | std::vector>>> 889 | else_ifs, 890 | std::vector> else_body) 891 | : cond(std::move(cond)), 892 | true_body(std::move(true_body)), 893 | else_ifs(std::move(else_ifs)), 894 | else_body(std::move(else_body)){}; 895 | 896 | If(std::unique_ptr cond, 897 | std::vector> true_body, 898 | std::vector> else_body) 899 | : cond(std::move(cond)), 900 | true_body(std::move(true_body)), 901 | else_body(std::move(else_body)){}; 902 | 903 | std::string toString() override; 904 | ~If(){}; 905 | }; 906 | 907 | class AbstractModule : public Node {}; 908 | 909 | class Module : public AbstractModule { 910 | public: 911 | std::string name; 912 | std::vector> ports; 913 | std::vector, 914 | std::unique_ptr>> 915 | body; 916 | Parameters parameters; 917 | std::string emitModuleHeader(); 918 | // Protected initializer that is used by the StringBodyModule subclass which 919 | // overrides the `body` field (but reuses the other fields) 920 | Module(std::string name, std::vector> ports, 921 | Parameters parameters) 922 | : name(name), 923 | ports(std::move(ports)), 924 | parameters(std::move(parameters)){}; 925 | 926 | Module(std::string name, std::vector> ports, 927 | std::vector, 928 | std::unique_ptr>> 929 | body, 930 | Parameters parameters) 931 | : name(name), 932 | ports(std::move(ports)), 933 | body(std::move(body)), 934 | parameters(std::move(parameters)){}; 935 | 936 | Module(std::string name, std::vector> ports, 937 | std::vector, 938 | std::unique_ptr>> 939 | body) 940 | : name(name), ports(std::move(ports)), body(std::move(body)){}; 941 | 942 | std::string toString() override; 943 | ~Module(){}; 944 | }; 945 | 946 | class StringBodyModule : public Module { 947 | public: 948 | std::string body; 949 | 950 | StringBodyModule(std::string name, 951 | std::vector> ports, 952 | std::string body, Parameters parameters) 953 | : Module(name, std::move(ports), std::move(parameters)), body(body){}; 954 | std::string toString() override; 955 | ~StringBodyModule(){}; 956 | }; 957 | 958 | class StringModule : public AbstractModule { 959 | public: 960 | std::string definition; 961 | 962 | explicit StringModule(std::string definition) : definition(definition){}; 963 | std::string toString() { return definition; }; 964 | ~StringModule(){}; 965 | }; 966 | 967 | class File : public Node { 968 | public: 969 | std::vector> modules; 970 | 971 | explicit File(std::vector>& modules) 972 | : modules(std::move(modules)){}; 973 | std::string toString() override; 974 | ~File(){}; 975 | }; 976 | 977 | // Helper functions for constructing unique pointers 978 | std::unique_ptr make_id(std::string name); 979 | 980 | std::unique_ptr make_num(std::string val); 981 | 982 | std::unique_ptr make_binop(std::unique_ptr left, 983 | BinOp::BinOp op, 984 | std::unique_ptr right); 985 | 986 | std::unique_ptr make_port( 987 | std::variant, std::unique_ptr> value, 988 | Direction direction, PortType data_type); 989 | 990 | std::unique_ptr make_vector(std::unique_ptr id, 991 | std::unique_ptr msb, 992 | std::unique_ptr lsb); 993 | 994 | } // namespace verilogAST 995 | #endif 996 | -------------------------------------------------------------------------------- /include/verilogAST/assign_inliner.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef VERILOGAST_ASSIGN_INLINER_H 3 | #define VERILOGAST_ASSIGN_INLINER_H 4 | #include 5 | #include "verilogAST.hpp" 6 | #include "verilogAST/transformer.hpp" 7 | 8 | namespace verilogAST { 9 | 10 | class AssignMapBuilder : public Transformer { 11 | std::map &assign_count; 12 | std::map> &assign_map; 13 | std::set &non_input_ports; 14 | std::set &output_ports; 15 | std::set &input_ports; 16 | 17 | template 18 | std::unique_ptr process_assign(std::unique_ptr node); 19 | 20 | public: 21 | AssignMapBuilder( 22 | std::map &assign_count, 23 | std::map> &assign_map, 24 | std::set &non_input_ports, 25 | std::set &output_ports, std::set &input_ports) 26 | : assign_count(assign_count), 27 | assign_map(assign_map), 28 | non_input_ports(non_input_ports), 29 | output_ports(output_ports), 30 | input_ports(input_ports){}; 31 | 32 | using Transformer::visit; 33 | virtual std::unique_ptr visit(std::unique_ptr node); 34 | virtual std::unique_ptr visit( 35 | std::unique_ptr node); 36 | virtual std::unique_ptr visit( 37 | std::unique_ptr node); 38 | }; 39 | 40 | class WireReadCounter : public Transformer { 41 | // Counts number of times a wire is read 42 | // 43 | std::map &read_count; 44 | 45 | template 46 | std::unique_ptr process_assign(std::unique_ptr node); 47 | 48 | public: 49 | WireReadCounter(std::map &read_count) 50 | : read_count(read_count){}; 51 | 52 | using Transformer::visit; 53 | // Increment read count 54 | virtual std::unique_ptr visit(std::unique_ptr node); 55 | // Skip target of assign (not read) 56 | virtual std::unique_ptr visit( 57 | std::unique_ptr node); 58 | virtual std::unique_ptr visit( 59 | std::unique_ptr node); 60 | // Skip declarations (not read) 61 | virtual std::unique_ptr visit(std::unique_ptr node); 62 | }; 63 | 64 | class Blacklister : public Transformer { 65 | std::set &wire_blacklist; 66 | std::map> &assign_map; 67 | 68 | protected: 69 | bool blacklist = false; 70 | // Allow numeric literals as valid drivers (okay for module instances, not 71 | // okay for slice/index) 72 | virtual bool allowNumDriver() { return false; }; 73 | void blacklist_invalid_driver(std::unique_ptr node); 74 | 75 | public: 76 | Blacklister(std::set &wire_blacklist, 77 | std::map> &assign_map) 78 | : wire_blacklist(wire_blacklist), assign_map(assign_map){}; 79 | using Transformer::visit; 80 | virtual std::unique_ptr visit(std::unique_ptr node); 81 | }; 82 | 83 | class SliceBlacklister : public Blacklister { 84 | // Prevent inling wires into slice nodes, e.g. 85 | // wire [7:0] x; 86 | // assign x = y + z; 87 | // assign w = x[4:0]; 88 | // 89 | // Verilog does not support (y + z)[4:0] 90 | public: 91 | SliceBlacklister( 92 | std::set &wire_blacklist, 93 | std::map> &assign_map) 94 | : Blacklister(wire_blacklist, assign_map){}; 95 | using Blacklister::visit; 96 | virtual std::unique_ptr visit(std::unique_ptr node); 97 | }; 98 | 99 | class IndexBlacklister : public Blacklister { 100 | // Prevent inling wires into index nodes, e.g. 101 | // wire x; 102 | // assign x = y + z; 103 | // assign w = x[0]; 104 | // 105 | // Verilog does not support (y + z)[0] 106 | public: 107 | IndexBlacklister( 108 | std::set &wire_blacklist, 109 | std::map> &assign_map) 110 | : Blacklister(wire_blacklist, assign_map){}; 111 | using Blacklister::visit; 112 | virtual std::unique_ptr visit(std::unique_ptr node); 113 | }; 114 | 115 | class IfMacroBlacklister : public Blacklister { 116 | // Prevent inling wires defined inside a macro, e.g. 117 | // `ifdef ASSERT_ON 118 | // assign x = y + z; 119 | // assign w = x[0]; 120 | // `else 121 | // assign x = 0; 122 | // assign w = 0; 123 | // `endif 124 | public: 125 | IfMacroBlacklister( 126 | std::set &wire_blacklist, 127 | std::map> &assign_map) 128 | : Blacklister(wire_blacklist, assign_map){}; 129 | using Blacklister::visit; 130 | virtual std::unique_ptr visit(std::unique_ptr node); 131 | }; 132 | 133 | class ModuleInstanceBlacklister : public Blacklister { 134 | // Prevent inling wires into module instance nodes, e.g. 135 | // wire z; 136 | // assign b = a; 137 | // assign z = i + a; // <--- not inlined into .w below 138 | // inner_module inner_module_inst ( 139 | // .c(a), 140 | // .i(i), 141 | // .w(z), 142 | // .o(o) 143 | // ); 144 | // 145 | // We can make this configurable, but for now we keep it as the default since 146 | // some tools do not support general expressions inside module instance 147 | // statements 148 | protected: 149 | bool allowNumDriver() override { return true; }; 150 | 151 | public: 152 | ModuleInstanceBlacklister( 153 | std::set &wire_blacklist, 154 | std::map> &assign_map) 155 | : Blacklister(wire_blacklist, assign_map){}; 156 | using Blacklister::visit; 157 | virtual std::unique_ptr visit( 158 | std::unique_ptr node) override; 159 | }; 160 | 161 | class AssignInliner : public Transformer { 162 | std::map read_count; 163 | std::map assign_count; 164 | std::map> assign_map; 165 | std::set non_input_ports; 166 | std::set output_ports; 167 | std::set input_ports; 168 | std::set inlined_outputs; 169 | std::set wire_blacklist; 170 | 171 | std::vector, 172 | std::unique_ptr>> 173 | do_inline(std::vector, 174 | std::unique_ptr>> 175 | body); 176 | 177 | bool can_inline(std::string key); 178 | 179 | template 180 | std::unique_ptr process_assign(std::unique_ptr node); 181 | 182 | public: 183 | AssignInliner() : wire_blacklist(){}; 184 | explicit AssignInliner(std::set wire_blacklist) 185 | : wire_blacklist(wire_blacklist){}; 186 | using Transformer::visit; 187 | virtual std::unique_ptr visit(std::unique_ptr node); 188 | virtual std::unique_ptr visit(std::unique_ptr node); 189 | virtual std::unique_ptr visit( 190 | std::unique_ptr node); 191 | virtual std::unique_ptr visit( 192 | std::unique_ptr node); 193 | virtual std::unique_ptr visit(std::unique_ptr node); 194 | virtual std::unique_ptr visit(std::unique_ptr node); 195 | }; 196 | 197 | } // namespace verilogAST 198 | #endif 199 | -------------------------------------------------------------------------------- /include/verilogAST/concat_coalescer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VERILOGAST_CONCAT_COALESCER_H 2 | #define VERILOGAST_CONCAT_COALESCER_H 3 | 4 | #include "verilogAST.hpp" 5 | #include "verilogAST/transformer.hpp" 6 | 7 | namespace verilogAST { 8 | 9 | class ConcatCoalescer : public Transformer { 10 | public: 11 | using Transformer::visit; 12 | 13 | std::unique_ptr visit(std::unique_ptr node) override; 14 | }; 15 | 16 | } // namespace verilogAST 17 | 18 | #endif // VERILOGAST_CONCAT_COALESCER_H 19 | -------------------------------------------------------------------------------- /include/verilogAST/make_packed.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VERILOGAST_MAKE_PACKED_H 2 | #define VERILOGAST_MAKE_PACKED_H 3 | 4 | #include "verilogAST.hpp" 5 | #include "verilogAST/transformer.hpp" 6 | 7 | namespace verilogAST { 8 | 9 | class MakePacked : public Transformer { 10 | public: 11 | MakePacked() = default; 12 | 13 | using Transformer::visit; 14 | 15 | std::unique_ptr visit(std::unique_ptr vector) override; 16 | }; 17 | 18 | } // namespace verilogAST 19 | 20 | #endif // VERILOGAST_MAKE_PACKED_H 21 | -------------------------------------------------------------------------------- /include/verilogAST/transformer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef VERILOGAST_TRANSFORMER_H 3 | #define VERILOGAST_TRANSFORMER_H 4 | #include "verilogAST.hpp" 5 | 6 | namespace verilogAST { 7 | 8 | class Transformer { 9 | public: 10 | template 11 | T visit(T node) { 12 | return std::visit( 13 | [&](auto&& value) -> T { return this->visit(std::move(value)); }, node); 14 | } 15 | 16 | virtual std::unique_ptr visit(std::unique_ptr node); 17 | 18 | virtual std::unique_ptr visit( 19 | std::unique_ptr node); 20 | 21 | virtual std::unique_ptr visit(std::unique_ptr node); 22 | 23 | virtual std::unique_ptr visit(std::unique_ptr node); 24 | 25 | virtual std::unique_ptr visit(std::unique_ptr node); 26 | 27 | virtual std::unique_ptr visit(std::unique_ptr node); 28 | 29 | virtual std::unique_ptr visit(std::unique_ptr node); 30 | 31 | virtual std::unique_ptr visit(std::unique_ptr node); 32 | 33 | virtual std::unique_ptr visit(std::unique_ptr node); 34 | 35 | virtual std::unique_ptr visit(std::unique_ptr node); 36 | 37 | virtual std::unique_ptr visit(std::unique_ptr node); 38 | 39 | virtual std::unique_ptr visit(std::unique_ptr node); 40 | 41 | virtual std::unique_ptr visit(std::unique_ptr node); 42 | 43 | virtual std::unique_ptr visit(std::unique_ptr node); 44 | 45 | virtual std::unique_ptr visit(std::unique_ptr node); 46 | 47 | virtual std::unique_ptr visit(std::unique_ptr node); 48 | 49 | virtual std::variant, std::unique_ptr> 50 | visit( 51 | std::variant, std::unique_ptr> node); 52 | 53 | virtual std::unique_ptr visit(std::unique_ptr node); 54 | 55 | virtual std::unique_ptr visit(std::unique_ptr node); 56 | 57 | virtual std::unique_ptr visit(std::unique_ptr node); 58 | 59 | virtual std::unique_ptr visit( 60 | std::unique_ptr node); 61 | 62 | virtual std::unique_ptr visit( 63 | std::unique_ptr node); 64 | 65 | virtual std::unique_ptr visit(std::unique_ptr node); 66 | 67 | virtual std::unique_ptr visit( 68 | std::unique_ptr node); 69 | 70 | virtual std::unique_ptr visit(std::unique_ptr node); 71 | 72 | virtual std::unique_ptr visit( 73 | std::unique_ptr node); 74 | 75 | virtual std::unique_ptr visit(std::unique_ptr node); 76 | 77 | virtual std::unique_ptr visit(std::unique_ptr node); 78 | 79 | virtual std::unique_ptr visit( 80 | std::unique_ptr node); 81 | 82 | virtual std::unique_ptr visit(std::unique_ptr node); 83 | 84 | virtual std::unique_ptr visit( 85 | std::unique_ptr node); 86 | 87 | virtual std::unique_ptr visit( 88 | std::unique_ptr node); 89 | 90 | virtual std::unique_ptr visit( 91 | std::unique_ptr node); 92 | 93 | virtual std::unique_ptr visit(std::unique_ptr node); 94 | 95 | virtual std::unique_ptr visit(std::unique_ptr node); 96 | 97 | virtual std::unique_ptr visit(std::unique_ptr node); 98 | 99 | virtual std::unique_ptr visit( 100 | std::unique_ptr node); 101 | 102 | virtual std::unique_ptr visit( 103 | std::unique_ptr node); 104 | 105 | virtual std::unique_ptr visit(std::unique_ptr node); 106 | 107 | virtual std::unique_ptr visit( 108 | std::unique_ptr node); 109 | 110 | virtual std::unique_ptr visit( 111 | std::unique_ptr node); 112 | 113 | virtual std::unique_ptr visit( 114 | std::unique_ptr node); 115 | 116 | virtual std::unique_ptr visit(std::unique_ptr node); 117 | }; 118 | 119 | } // namespace verilogAST 120 | #endif 121 | -------------------------------------------------------------------------------- /include/verilogAST/zext_coalescer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VERILOGAST_ZEXT_COALESCER_H 2 | #define VERILOGAST_ZEXT_COALESCER_H 3 | 4 | #include "verilogAST.hpp" 5 | #include "verilogAST/transformer.hpp" 6 | 7 | namespace verilogAST { 8 | 9 | class ZextCoalescer : public Transformer { 10 | public: 11 | ZextCoalescer(bool elide = false) : elide_(elide) {} 12 | 13 | using Transformer::visit; 14 | 15 | std::unique_ptr visit(std::unique_ptr node) override; 16 | 17 | private: 18 | const bool elide_; 19 | }; 20 | 21 | } // namespace verilogAST 22 | 23 | #endif // VERILOGAST_ZEXT_COALESCER_H 24 | -------------------------------------------------------------------------------- /src/assign_inliner.cpp: -------------------------------------------------------------------------------- 1 | #include "verilogAST/assign_inliner.hpp" 2 | #include 3 | 4 | namespace verilogAST { 5 | 6 | void Blacklister::blacklist_invalid_driver(std::unique_ptr node) { 7 | if (this->wire_blacklist.count(node->value)) { 8 | // Already blacklisted 9 | return; 10 | } 11 | if (!assign_map.count(node->toString())) { 12 | // Not in assign map, means it's a module input, don't need to do anything 13 | // because it won't be inlined 14 | return; 15 | } 16 | auto driver = assign_map[node->toString()]->clone(); 17 | // Can only inline if driven by identifier, index, or slice 18 | bool valid_driver = 19 | dynamic_cast(driver.get()) || 20 | dynamic_cast(driver.get()) || 21 | dynamic_cast(driver.get()) || 22 | (this->allowNumDriver() && dynamic_cast(driver.get())); 23 | if (!valid_driver) { 24 | this->wire_blacklist.insert(node->value); 25 | } else if (auto ptr = dynamic_cast(driver.get())) { 26 | // if driven by an id, we need to recursively blacklist any invalid 27 | // drivers, else they'll eventually get inlined into here 28 | driver.release(); 29 | blacklist_invalid_driver(std::unique_ptr(ptr)); 30 | } 31 | } 32 | 33 | std::unique_ptr Blacklister::visit( 34 | std::unique_ptr node) { 35 | if (this->blacklist) { 36 | blacklist_invalid_driver(node->clone()); 37 | } 38 | return node; 39 | } 40 | 41 | std::unique_ptr SliceBlacklister::visit(std::unique_ptr node) { 42 | bool prev = this->blacklist; 43 | this->blacklist = true; 44 | node = Transformer::visit(std::move(node)); 45 | // Restore prev value, since we could be nested inside an slice 46 | this->blacklist = prev; 47 | return node; 48 | } 49 | 50 | std::unique_ptr IndexBlacklister::visit(std::unique_ptr node) { 51 | bool prev = this->blacklist; 52 | this->blacklist = true; 53 | node = Transformer::visit(std::move(node)); 54 | // Restore prev value, since we could be nested inside an index 55 | this->blacklist = prev; 56 | return node; 57 | } 58 | 59 | std::unique_ptr IfMacroBlacklister::visit(std::unique_ptr node) { 60 | bool prev = this->blacklist; 61 | this->blacklist = true; 62 | node = Transformer::visit(std::move(node)); 63 | // Restore prev value, since we could be nested 64 | this->blacklist = prev; 65 | return node; 66 | } 67 | 68 | std::unique_ptr ModuleInstanceBlacklister::visit( 69 | std::unique_ptr node) { 70 | this->blacklist = true; 71 | for (auto&& conn : *node->connections) { 72 | conn.second = this->visit(std::move(conn.second)); 73 | } 74 | this->blacklist = false; 75 | return node; 76 | } 77 | 78 | std::unique_ptr WireReadCounter::visit( 79 | std::unique_ptr node) { 80 | this->read_count[node->toString()]++; 81 | return node; 82 | } 83 | 84 | std::unique_ptr WireReadCounter::visit( 85 | std::unique_ptr node) { 86 | return node; 87 | } 88 | 89 | template 90 | std::unique_ptr WireReadCounter::process_assign(std::unique_ptr node) { 91 | node->value = this->visit(std::move(node->value)); 92 | return node; 93 | } 94 | 95 | std::unique_ptr WireReadCounter::visit( 96 | std::unique_ptr node) { 97 | return this->process_assign(std::move(node)); 98 | } 99 | 100 | std::unique_ptr WireReadCounter::visit( 101 | std::unique_ptr node) { 102 | return this->process_assign(std::move(node)); 103 | } 104 | 105 | std::unique_ptr AssignMapBuilder::visit(std::unique_ptr node) { 106 | std::string port_str = std::visit( 107 | [](auto&& value) -> std::string { 108 | if (auto ptr = dynamic_cast(value.get())) { 109 | return ptr->toString(); 110 | } else if (auto ptr = dynamic_cast(value.get())) { 111 | return ptr->id->toString(); 112 | } 113 | throw std::runtime_error("Unreachable"); // LCOV_EXCL_LINE 114 | return ""; // LCOV_EXCL_LINE 115 | }, 116 | node->value); 117 | if (node->direction != Direction::INPUT) { 118 | this->non_input_ports.insert(port_str); 119 | if (node->direction == Direction::OUTPUT) { 120 | this->output_ports.insert(port_str); 121 | } 122 | } else { 123 | this->input_ports.insert(port_str); 124 | } 125 | return node; 126 | } 127 | template 128 | std::unique_ptr AssignMapBuilder::process_assign(std::unique_ptr node) { 129 | node = Transformer::visit(std::move(node)); 130 | std::string key = 131 | std::visit([](auto&& value) -> std::string { return value->toString(); }, 132 | node->target); 133 | this->assign_map[key] = node->value->clone(); 134 | this->assign_count[key]++; 135 | return node; 136 | } 137 | 138 | std::unique_ptr AssignMapBuilder::visit( 139 | std::unique_ptr node) { 140 | return this->process_assign(std::move(node)); 141 | } 142 | 143 | std::unique_ptr AssignMapBuilder::visit( 144 | std::unique_ptr node) { 145 | return this->process_assign(std::move(node)); 146 | } 147 | 148 | bool AssignInliner::can_inline(std::string key) { 149 | if (this->wire_blacklist.count(key)) { 150 | return false; 151 | } 152 | auto it = assign_map.find(key); 153 | return it != assign_map.end() && 154 | (this->read_count[key] == 1 || 155 | dynamic_cast(it->second.get()) || 156 | dynamic_cast(it->second.get())); 157 | } 158 | 159 | std::unique_ptr AssignInliner::visit(std::unique_ptr node) { 160 | if (std::holds_alternative>(node->value)) { 161 | std::string key = 162 | std::get>(node->value)->toString(); 163 | if (this->can_inline(key)) { 164 | std::unique_ptr value = this->visit(assign_map[key]->clone()); 165 | if (auto ptr = dynamic_cast(value.get())) { 166 | value.release(); 167 | node->value = std::unique_ptr(ptr); 168 | } else if (auto ptr = dynamic_cast(value.get())) { 169 | value.release(); 170 | node->value = std::unique_ptr(ptr); 171 | } else if (auto ptr = dynamic_cast(value.get())) { 172 | value.release(); 173 | node->value = std::unique_ptr(ptr); 174 | } 175 | } 176 | return node; 177 | } 178 | return Transformer::visit(std::move(node)); 179 | } 180 | 181 | std::unique_ptr AssignInliner::visit( 182 | std::unique_ptr node) { 183 | if (auto ptr = dynamic_cast(node.get())) { 184 | node.release(); 185 | std::unique_ptr id(ptr); 186 | std::string key = id->toString(); 187 | if (this->can_inline(key)) { 188 | return this->visit(assign_map[key]->clone()); 189 | } 190 | return id; 191 | } 192 | return Transformer::visit(std::move(node)); 193 | } 194 | 195 | std::unique_ptr AssignInliner::visit(std::unique_ptr node) { 196 | bool remove = false; 197 | std::visit( 198 | [&](auto&& value) { 199 | if (auto ptr = dynamic_cast(value.get())) { 200 | remove = this->can_inline(ptr->toString()); 201 | } else if (auto ptr = dynamic_cast(value.get())) { 202 | remove = this->can_inline(ptr->id->toString()); 203 | } 204 | }, 205 | node->value); 206 | if (remove) { 207 | return std::unique_ptr{}; 208 | } 209 | node->value = this->visit(std::move(node->value)); 210 | return node; 211 | } 212 | 213 | template 214 | std::unique_ptr AssignInliner::process_assign(std::unique_ptr node) { 215 | node->value = this->visit(std::move(node->value)); 216 | std::string key = 217 | std::visit([](auto&& value) -> std::string { return value->toString(); }, 218 | node->target); 219 | bool remove = false; 220 | std::visit( 221 | [&](auto&& value) { 222 | if (auto ptr = dynamic_cast(value.get())) { 223 | if (this->can_inline(key) && this->non_input_ports.count(key) == 0) { 224 | remove = true; 225 | } else if (this->inlined_outputs.count(ptr->toString())) { 226 | remove = true; 227 | }; 228 | } 229 | }, 230 | node->target); 231 | if (remove) { 232 | return std::unique_ptr{}; 233 | } 234 | return node; 235 | } 236 | 237 | std::unique_ptr AssignInliner::visit( 238 | std::unique_ptr node) { 239 | return this->process_assign(std::move(node)); 240 | } 241 | 242 | std::unique_ptr AssignInliner::visit( 243 | std::unique_ptr node) { 244 | return this->process_assign(std::move(node)); 245 | } 246 | 247 | std::vector, 248 | std::unique_ptr>> 249 | AssignInliner::do_inline( 250 | std::vector, 251 | std::unique_ptr>> 252 | body) { 253 | std::vector, 254 | std::unique_ptr>> 255 | new_body; 256 | for (auto&& item : body) { 257 | std::variant, 258 | std::unique_ptr> 259 | result = this->visit(std::move(item)); 260 | bool is_null; 261 | std::visit( 262 | [&](auto&& value) { 263 | if (value) { 264 | is_null = false; 265 | } else { 266 | is_null = true; 267 | } 268 | }, 269 | result); 270 | if (!is_null) { 271 | new_body.push_back(std::move(result)); 272 | } 273 | } 274 | return new_body; 275 | } 276 | 277 | std::unique_ptr AssignInliner::visit(std::unique_ptr node) { 278 | AssignMapBuilder builder(this->assign_count, this->assign_map, 279 | this->non_input_ports, this->output_ports, 280 | this->input_ports); 281 | node = builder.visit(std::move(node)); 282 | for (auto entry : assign_count) { 283 | if (entry.second > 1) { 284 | // Do not inline things assigned more than once, e.g. a reg inside 285 | // if/else statements 286 | this->wire_blacklist.insert(entry.first); 287 | } 288 | } 289 | 290 | WireReadCounter counter(this->read_count); 291 | node = counter.visit(std::move(node)); 292 | 293 | IndexBlacklister index_blacklist(this->wire_blacklist, this->assign_map); 294 | node = index_blacklist.visit(std::move(node)); 295 | 296 | IfMacroBlacklister if_macro_blacklist(this->wire_blacklist, this->assign_map); 297 | node = if_macro_blacklist.visit(std::move(node)); 298 | 299 | SliceBlacklister slice_blacklist(this->wire_blacklist, this->assign_map); 300 | node = slice_blacklist.visit(std::move(node)); 301 | 302 | ModuleInstanceBlacklister module_instance_blacklister(this->wire_blacklist, 303 | this->assign_map); 304 | node = module_instance_blacklister.visit(std::move(node)); 305 | 306 | std::vector> new_ports; 307 | for (auto&& item : node->ports) { 308 | new_ports.push_back(this->visit(std::move(item))); 309 | } 310 | node->ports = std::move(new_ports); 311 | 312 | node->body = this->do_inline(std::move(node->body)); 313 | // Now "reverse inline" output wires 314 | for (auto output : this->output_ports) { 315 | if (!this->assign_map.count(output)) { 316 | continue; 317 | } 318 | std::unique_ptr value = this->assign_map[output]->clone(); 319 | this->assign_map.erase(output); 320 | if (dynamic_cast(value.get()) && 321 | this->assign_count[value->toString()] == 0 && 322 | this->input_ports.count(value->toString()) == 0 && 323 | this->wire_blacklist.count(value->toString()) == 0) { 324 | this->assign_map[value->toString()] = make_id(output); 325 | this->assign_count[value->toString()]++; 326 | this->inlined_outputs.insert(output); 327 | } 328 | } 329 | node->body = this->do_inline(std::move(node->body)); 330 | return node; 331 | } 332 | 333 | } // namespace verilogAST 334 | -------------------------------------------------------------------------------- /src/concat_coalescer.cpp: -------------------------------------------------------------------------------- 1 | #include "verilogAST/concat_coalescer.hpp" 2 | #include 3 | 4 | namespace verilogAST { 5 | 6 | namespace { 7 | 8 | struct Run { 9 | std::string name; 10 | int first; // inclusive 11 | int last; // inclusive 12 | }; 13 | 14 | class RunOrExpr { 15 | public: 16 | explicit RunOrExpr(const Expression* expr) : run_(), expr_(expr) {} 17 | explicit RunOrExpr(std::string name, int first, int last) 18 | : run_({name, first, last}), expr_(nullptr) {} 19 | 20 | bool isRun() const { return expr_ == nullptr; } 21 | 22 | // Tries to merge in @other into this run if it is contiguous. Returns true if 23 | // merged, falses otherwise. 24 | bool tryMerge(const RunOrExpr& other) { 25 | if (!isRun() or !other.isRun()) return false; 26 | if (run_.name != other.run_.name) return false; 27 | if (run_.last != other.run_.first + 1) return false; 28 | run_.last = other.run_.first; 29 | return true; 30 | } 31 | 32 | // Returns the expression corresponding to this run. If this is not a run, 33 | // then we return a clone of the contained expression. Otherwise, we return an 34 | // Index expresssion if the run contains only one index, or a Slice if it 35 | // contains > 1. 36 | std::unique_ptr generateExpression() const { 37 | if (not isRun()) return expr_->clone(); 38 | auto first = std::unique_ptr( 39 | new NumericLiteral(std::to_string(run_.first))); 40 | if (run_.first == run_.last) { 41 | return std::unique_ptr( 42 | new Index(std::make_unique(run_.name), std::move(first))); 43 | } 44 | auto id = std::unique_ptr(new Identifier(run_.name)); 45 | auto last = std::unique_ptr( 46 | new NumericLiteral(std::to_string(run_.last))); 47 | return std::unique_ptr( 48 | new Slice(std::move(id), std::move(first), std::move(last))); 49 | } 50 | 51 | private: 52 | Run run_; 53 | const Expression* expr_ = nullptr; 54 | }; 55 | 56 | // Tries to extract a NumericLiteral (int) from @expr. Returns a pair of if successful; otherwise, returns . 58 | std::pair expr_to_int(const Expression* expr) { 59 | auto ptr = dynamic_cast(expr); 60 | if (not ptr) return std::make_pair(false, 0); 61 | return std::make_pair(true, std::atoi(ptr->value.c_str())); 62 | } 63 | 64 | // Consumes a Concat node argument @arg and tries to make a run out of it. If it 65 | // is of the form Index(Identifier name, NumericLiteral val) then we return 66 | // RunOrExpr(name, val, val); otherwise we return RunOrExpr(arg). 67 | RunOrExpr makeRunOrExpr(const Expression* arg) { 68 | auto index = dynamic_cast(arg); 69 | if (not index) return RunOrExpr(arg); 70 | auto as_int = expr_to_int(index->index.get()); 71 | if (not as_int.first) return RunOrExpr(arg); 72 | if (not std::holds_alternative>(index->value)) { 73 | return RunOrExpr(arg); 74 | } 75 | auto& id = std::get>(index->value); 76 | return RunOrExpr(id->value, as_int.second, as_int.second); 77 | } 78 | 79 | } // namespace 80 | 81 | std::unique_ptr ConcatCoalescer::visit( 82 | std::unique_ptr node) { 83 | auto ptr = dynamic_cast(node.get()); 84 | // This pass only operates on non-empty Concat nodes. 85 | if (not ptr or ptr->args.size() == 0) return node; 86 | std::vector runs; 87 | for (const auto& arg : ptr->args) { 88 | auto run_or_expr = makeRunOrExpr(arg.get()); 89 | // If this is the first run, then we append it. Otherwise, we try to merge 90 | // it into the previous run. If it cannot be merged, then we append it. 91 | if (runs.size() == 0 or not runs.back().tryMerge(run_or_expr)) { 92 | runs.push_back(run_or_expr); 93 | } 94 | } 95 | assert(runs.size() > 0); 96 | // If there is sonly one run, then we return that run as a standalone 97 | // expression; otherwise, we return a Concat node containing the runs. 98 | if (runs.size() == 1) return runs.front().generateExpression(); 99 | std::vector> args; 100 | for (const auto& run : runs) { 101 | args.push_back(run.generateExpression()); 102 | } 103 | return std::make_unique(std::move(args)); 104 | } 105 | 106 | } // namespace verilogAST 107 | -------------------------------------------------------------------------------- /src/make_packed.cpp: -------------------------------------------------------------------------------- 1 | #include "verilogAST/make_packed.hpp" 2 | #include 3 | 4 | namespace verilogAST { 5 | 6 | std::unique_ptr MakePacked::visit(std::unique_ptr vector) { 7 | auto ptr = dynamic_cast(vector.get()); 8 | if (not ptr) return vector; 9 | std::vector< 10 | std::pair, std::unique_ptr>> 11 | outer_dims; 12 | for (const auto& dim : ptr->outer_dims) { 13 | outer_dims.push_back( 14 | std::make_pair(dim.first->clone(), dim.second->clone())); 15 | } 16 | return std::make_unique(ptr->id->clone(), ptr->msb->clone(), 17 | ptr->lsb->clone(), 18 | std::move(outer_dims)); 19 | } 20 | 21 | } // namespace verilogAST 22 | -------------------------------------------------------------------------------- /src/transformer.cpp: -------------------------------------------------------------------------------- 1 | #include "verilogAST/transformer.hpp" 2 | #include 3 | 4 | namespace verilogAST { 5 | 6 | std::unique_ptr Transformer::visit( 7 | std::unique_ptr node) { 8 | if (auto ptr = dynamic_cast(node.get())) { 9 | node.release(); 10 | return this->visit(std::unique_ptr(ptr)); 11 | } 12 | if (auto ptr = dynamic_cast(node.get())) { 13 | node.release(); 14 | return this->visit(std::unique_ptr(ptr)); 15 | } 16 | if (auto ptr = dynamic_cast(node.get())) { 17 | node.release(); 18 | return this->visit(std::unique_ptr(ptr)); 19 | } 20 | if (auto ptr = dynamic_cast(node.get())) { 21 | node.release(); 22 | return this->visit(std::unique_ptr(ptr)); 23 | } 24 | if (auto ptr = dynamic_cast(node.get())) { 25 | node.release(); 26 | return this->visit(std::unique_ptr(ptr)); 27 | } 28 | if (auto ptr = dynamic_cast(node.get())) { 29 | node.release(); 30 | return this->visit(std::unique_ptr(ptr)); 31 | } 32 | if (auto ptr = dynamic_cast(node.get())) { 33 | node.release(); 34 | return this->visit(std::unique_ptr(ptr)); 35 | } 36 | if (auto ptr = dynamic_cast(node.get())) { 37 | node.release(); 38 | return this->visit(std::unique_ptr(ptr)); 39 | } 40 | if (auto ptr = dynamic_cast(node.get())) { 41 | node.release(); 42 | return this->visit(std::unique_ptr(ptr)); 43 | } 44 | if (auto ptr = dynamic_cast(node.get())) { 45 | node.release(); 46 | return this->visit(std::unique_ptr(ptr)); 47 | } 48 | if (auto ptr = dynamic_cast(node.get())) { 49 | node.release(); 50 | return this->visit(std::unique_ptr(ptr)); 51 | } 52 | if (auto ptr = dynamic_cast(node.get())) { 53 | node.release(); 54 | return this->visit(std::unique_ptr(ptr)); 55 | } 56 | if (auto ptr = dynamic_cast(node.get())) { 57 | node.release(); 58 | return this->visit(std::unique_ptr(ptr)); 59 | } 60 | throw std::runtime_error("Unreachable"); // LCOV_EXCL_LINE 61 | return node; // LCOV_EXCL_LINE 62 | } 63 | 64 | std::unique_ptr Transformer::visit( 65 | std::unique_ptr node) { 66 | return node; 67 | } 68 | 69 | std::unique_ptr Transformer::visit( 70 | std::unique_ptr node) { 71 | return node; 72 | } 73 | 74 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 75 | node->expr = this->visit(std::move(node->expr)); 76 | return node; 77 | } 78 | 79 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 80 | node->value = this->visit(std::move(node->value)); 81 | return node; 82 | } 83 | 84 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 85 | return node; 86 | } 87 | 88 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 89 | node->value = this->visit(std::move(node->value)); 90 | node->index = this->visit(std::move(node->index)); 91 | return node; 92 | } 93 | 94 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 95 | node->expr = this->visit(std::move(node->expr)); 96 | node->high_index = this->visit(std::move(node->high_index)); 97 | node->low_index = this->visit(std::move(node->low_index)); 98 | return node; 99 | } 100 | 101 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 102 | node->left = this->visit(std::move(node->left)); 103 | node->right = this->visit(std::move(node->right)); 104 | return node; 105 | } 106 | 107 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 108 | node->operand = this->visit(std::move(node->operand)); 109 | return node; 110 | } 111 | 112 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 113 | node->cond = this->visit(std::move(node->cond)); 114 | node->true_value = this->visit(std::move(node->true_value)); 115 | node->false_value = this->visit(std::move(node->false_value)); 116 | return node; 117 | } 118 | 119 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 120 | std::vector> new_args; 121 | for (auto&& expr : node->args) { 122 | new_args.push_back(this->visit(std::move(expr))); 123 | } 124 | node->args = std::move(new_args); 125 | return node; 126 | } 127 | 128 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 129 | node->num = this->visit(std::move(node->num)); 130 | node->value = this->visit(std::move(node->value)); 131 | return node; 132 | } 133 | 134 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 135 | node->value = this->visit(std::move(node->value)); 136 | return node; 137 | } 138 | 139 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 140 | node->value = this->visit(std::move(node->value)); 141 | return node; 142 | } 143 | 144 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 145 | std::vector> new_args; 146 | for (auto&& expr : node->args) { 147 | new_args.push_back(this->visit(std::move(expr))); 148 | } 149 | node->args = std::move(new_args); 150 | return node; 151 | } 152 | 153 | std::variant, std::unique_ptr> 154 | Transformer::visit( 155 | std::variant, std::unique_ptr> node) { 156 | return std::visit( 157 | [&](auto&& value) -> std::variant, 158 | std::unique_ptr> { 159 | if (auto ptr = dynamic_cast(value.get())) { 160 | value.release(); 161 | return this->visit(std::unique_ptr(ptr)); 162 | } 163 | if (auto ptr = dynamic_cast(value.get())) { 164 | value.release(); 165 | return this->visit(std::unique_ptr(ptr)); 166 | } 167 | throw std::runtime_error("Unreachable"); // LCOV_EXCL_LINE 168 | return std::move(value); // LCOV_EXCL_LINE 169 | }, 170 | node); 171 | } 172 | 173 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 174 | node->id = this->visit(std::move(node->id)); 175 | node->msb = this->visit(std::move(node->msb)); 176 | node->lsb = this->visit(std::move(node->lsb)); 177 | if (auto ptr = dynamic_cast(node.get())) { 178 | std::vector< 179 | std::pair, std::unique_ptr>> 180 | new_outer_dims; 181 | for (auto& dim : ptr->outer_dims) { 182 | new_outer_dims.push_back({this->visit(std::move(dim.first)), 183 | this->visit(std::move(dim.second))}); 184 | } 185 | ptr->outer_dims = std::move(new_outer_dims); 186 | } 187 | return node; 188 | } 189 | 190 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 191 | node->value = this->visit(std::move(node->value)); 192 | return node; 193 | } 194 | 195 | std::unique_ptr Transformer::visit( 196 | std::unique_ptr node) { 197 | return node; 198 | } 199 | 200 | std::unique_ptr Transformer::visit( 201 | std::unique_ptr node) { 202 | return node; 203 | } 204 | 205 | std::unique_ptr Transformer::visit( 206 | std::unique_ptr node) { 207 | return node; 208 | } 209 | 210 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 211 | node->cond = this->visit(std::move(node->cond)); 212 | 213 | std::vector> new_true_body; 214 | for (auto&& item : node->true_body) { 215 | new_true_body.push_back(this->visit(std::move(item))); 216 | } 217 | node->true_body = std::move(new_true_body); 218 | 219 | std::vector, 220 | std::vector>>> 221 | new_else_ifs; 222 | for (auto&& item : node->else_ifs) { 223 | std::vector> new_body; 224 | for (auto&& inner_statement : item.second) { 225 | new_body.push_back(this->visit(std::move(inner_statement))); 226 | } 227 | new_else_ifs.push_back( 228 | {this->visit(std::move(item.first)), std::move(new_body)}); 229 | } 230 | node->else_ifs = std::move(new_else_ifs); 231 | 232 | std::vector> new_else_body; 233 | for (auto&& item : node->else_body) { 234 | new_else_body.push_back(this->visit(std::move(item))); 235 | } 236 | node->else_body = std::move(new_else_body); 237 | 238 | return node; 239 | } 240 | 241 | std::unique_ptr Transformer::visit( 242 | std::unique_ptr node) { 243 | return node; 244 | } 245 | 246 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 247 | std::vector, 248 | std::unique_ptr>> 249 | new_true_body; 250 | for (auto&& item : node->true_body) { 251 | new_true_body.push_back(this->visit(std::move(item))); 252 | } 253 | node->true_body = std::move(new_true_body); 254 | std::vector, 255 | std::unique_ptr>> 256 | new_else_body; 257 | for (auto&& item : node->else_body) { 258 | new_else_body.push_back(this->visit(std::move(item))); 259 | } 260 | node->else_body = std::move(new_else_body); 261 | return node; 262 | } 263 | 264 | std::unique_ptr Transformer::visit( 265 | std::unique_ptr node) { 266 | for (auto&& conn : *node->connections) { 267 | conn.second = this->visit(std::move(conn.second)); 268 | } 269 | for (auto&& param : node->parameters) { 270 | param.first = this->visit(std::move(param.first)); 271 | param.second = this->visit(std::move(param.second)); 272 | } 273 | return node; 274 | } 275 | 276 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 277 | node->value = this->visit(std::move(node->value)); 278 | return node; 279 | } 280 | 281 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 282 | node->value = this->visit(std::move(node->value)); 283 | return node; 284 | } 285 | 286 | std::unique_ptr Transformer::visit( 287 | std::unique_ptr node) { 288 | node->target = this->visit(std::move(node->target)); 289 | node->value = this->visit(std::move(node->value)); 290 | return node; 291 | } 292 | 293 | std::unique_ptr Transformer::visit( 294 | std::unique_ptr node) { 295 | if (auto ptr = dynamic_cast(node.get())) { 296 | node.release(); 297 | return this->visit(std::unique_ptr(ptr)); 298 | } 299 | if (auto ptr = dynamic_cast(node.get())) { 300 | node.release(); 301 | return this->visit(std::unique_ptr(ptr)); 302 | } 303 | throw std::runtime_error("Unreachable"); // LCOV_EXCL_LINE 304 | return node; // LCOV_EXCL_LINE 305 | } 306 | 307 | std::unique_ptr Transformer::visit( 308 | std::unique_ptr node) { 309 | if (auto ptr = dynamic_cast(node.get())) { 310 | node.release(); 311 | return this->visit(std::unique_ptr(ptr)); 312 | } 313 | if (auto ptr = dynamic_cast(node.get())) { 314 | node.release(); 315 | return this->visit(std::unique_ptr(ptr)); 316 | } 317 | if (auto ptr = dynamic_cast(node.get())) { 318 | node.release(); 319 | return this->visit(std::unique_ptr(ptr)); 320 | } 321 | if (auto ptr = dynamic_cast(node.get())) { 322 | node.release(); 323 | return this->visit(std::unique_ptr(ptr)); 324 | } 325 | if (auto ptr = dynamic_cast(node.get())) { 326 | node.release(); 327 | return this->visit(std::unique_ptr(ptr)); 328 | } 329 | if (auto ptr = dynamic_cast(node.get())) { 330 | node.release(); 331 | return this->visit(std::unique_ptr(ptr)); 332 | } 333 | throw std::runtime_error("Unreachable"); // LCOV_EXCL_LINE 334 | return node; // LCOV_EXCL_LINE 335 | } 336 | 337 | std::unique_ptr Transformer::visit( 338 | std::unique_ptr node) { 339 | node->target = this->visit(std::move(node->target)); 340 | node->value = this->visit(std::move(node->value)); 341 | return node; 342 | } 343 | 344 | std::unique_ptr Transformer::visit( 345 | std::unique_ptr node) { 346 | node->target = this->visit(std::move(node->target)); 347 | node->value = this->visit(std::move(node->value)); 348 | return node; 349 | } 350 | 351 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 352 | std::vector> new_args; 353 | for (auto&& expr : node->args) { 354 | new_args.push_back(this->visit(std::move(expr))); 355 | } 356 | node->args = std::move(new_args); 357 | return node; 358 | } 359 | 360 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 361 | return node; 362 | } 363 | 364 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 365 | std::vector< 366 | std::variant, std::unique_ptr, 367 | std::unique_ptr, std::unique_ptr>> 368 | new_sensitivity_list; 369 | for (auto&& item : node->sensitivity_list) { 370 | new_sensitivity_list.push_back(this->visit(std::move(item))); 371 | } 372 | node->sensitivity_list = std::move(new_sensitivity_list); 373 | std::vector> new_body; 374 | for (auto&& item : node->body) { 375 | new_body.push_back(this->visit(std::move(item))); 376 | } 377 | node->body = std::move(new_body); 378 | return node; 379 | } 380 | 381 | std::unique_ptr Transformer::visit( 382 | std::unique_ptr node) { 383 | if (auto ptr = dynamic_cast(node.get())) { 384 | node.release(); 385 | return this->visit(std::unique_ptr(ptr)); 386 | } 387 | if (auto ptr = dynamic_cast(node.get())) { 388 | node.release(); 389 | return this->visit(std::unique_ptr(ptr)); 390 | } 391 | throw std::runtime_error("Unreachable"); // LCOV_EXCL_LINE 392 | return node; // LCOV_EXCL_LINE 393 | } 394 | 395 | std::unique_ptr Transformer::visit( 396 | std::unique_ptr node) { 397 | if (auto ptr = dynamic_cast(node.get())) { 398 | node.release(); 399 | return this->visit(std::unique_ptr(ptr)); 400 | } 401 | if (auto ptr = dynamic_cast(node.get())) { 402 | node.release(); 403 | return this->visit(std::unique_ptr(ptr)); 404 | } 405 | if (auto ptr = dynamic_cast(node.get())) { 406 | node.release(); 407 | return this->visit(std::unique_ptr(ptr)); 408 | } 409 | if (auto ptr = dynamic_cast(node.get())) { 410 | node.release(); 411 | return this->visit(std::unique_ptr(ptr)); 412 | } 413 | if (auto ptr = dynamic_cast(node.get())) { 414 | node.release(); 415 | return this->visit(std::unique_ptr(ptr)); 416 | } 417 | if (auto ptr = dynamic_cast(node.get())) { 418 | node.release(); 419 | return this->visit(std::unique_ptr(ptr)); 420 | } 421 | if (auto ptr = dynamic_cast(node.get())) { 422 | node.release(); 423 | return this->visit(std::unique_ptr(ptr)); 424 | } 425 | throw std::runtime_error("Unreachable"); // LCOV_EXCL_LINE 426 | return node; // LCOV_EXCL_LINE 427 | } 428 | 429 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 430 | std::vector> new_ports; 431 | for (auto&& item : node->ports) { 432 | new_ports.push_back(this->visit(std::move(item))); 433 | } 434 | node->ports = std::move(new_ports); 435 | for (auto&& param : node->parameters) { 436 | param.first = this->visit(std::move(param.first)); 437 | param.second = this->visit(std::move(param.second)); 438 | } 439 | std::vector, 440 | std::unique_ptr>> 441 | new_body; 442 | for (auto&& item : node->body) { 443 | new_body.push_back(this->visit(std::move(item))); 444 | } 445 | node->body = std::move(new_body); 446 | return node; 447 | } 448 | 449 | std::unique_ptr Transformer::visit( 450 | std::unique_ptr node) { 451 | std::vector> new_ports; 452 | for (auto&& item : node->ports) { 453 | new_ports.push_back(this->visit(std::move(item))); 454 | } 455 | node->ports = std::move(new_ports); 456 | for (auto&& param : node->parameters) { 457 | param.first = this->visit(std::move(param.first)); 458 | param.second = this->visit(std::move(param.second)); 459 | } 460 | return node; 461 | } 462 | 463 | std::unique_ptr Transformer::visit( 464 | std::unique_ptr node) { 465 | return node; 466 | } 467 | 468 | std::unique_ptr Transformer::visit( 469 | std::unique_ptr node) { 470 | if (auto ptr = dynamic_cast(node.get())) { 471 | node.release(); 472 | return this->visit(std::unique_ptr(ptr)); 473 | } 474 | if (auto ptr = dynamic_cast(node.get())) { 475 | node.release(); 476 | return this->visit(std::unique_ptr(ptr)); 477 | } 478 | if (auto ptr = dynamic_cast(node.get())) { 479 | node.release(); 480 | return this->visit(std::unique_ptr(ptr)); 481 | } 482 | throw std::runtime_error("Unreachable"); // LCOV_EXCL_LINE 483 | return node; // LCOV_EXCL_LINE 484 | } 485 | 486 | std::unique_ptr Transformer::visit(std::unique_ptr node) { 487 | std::vector> new_modules; 488 | for (auto&& item : node->modules) { 489 | new_modules.push_back(this->visit(std::move(item))); 490 | } 491 | node->modules = std::move(new_modules); 492 | return node; 493 | } 494 | 495 | } // namespace verilogAST 496 | -------------------------------------------------------------------------------- /src/verilogAST.cpp: -------------------------------------------------------------------------------- 1 | #include "verilogAST.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | std::string variant_to_string(std::variant &value) { 9 | return std::visit( 10 | [](auto &&value) -> std::string { return value->toString(); }, value); 11 | } 12 | 13 | // Helper function to join a vector of strings with a specified separator ala 14 | // Python's ",".join(...) 15 | std::string join(std::vector vec, std::string separator) { 16 | std::string result; 17 | for (size_t i = 0; i < vec.size(); i++) { 18 | if (i > 0) result += separator; 19 | result += vec[i]; 20 | } 21 | return result; 22 | } 23 | 24 | namespace verilogAST { 25 | 26 | std::string expr_to_string_with_parens(std::unique_ptr &expr) { 27 | // FIXME: For now we just do naive precedence logic 28 | std::string expr_str = expr->toString(); 29 | if (dynamic_cast(expr.get())) { 30 | } else if (dynamic_cast(expr.get())) { 31 | } else if (dynamic_cast(expr.get())) { 32 | } else if (dynamic_cast(expr.get())) { 33 | } else if (dynamic_cast(expr.get())) { 34 | } else { 35 | expr_str = "(" + expr_str + ")"; 36 | } 37 | return expr_str; 38 | } 39 | 40 | std::string NumericLiteral::toString() { 41 | std::string signed_str = _signed ? "s" : ""; 42 | 43 | std::string radix_str; 44 | switch (radix) { 45 | case BINARY: 46 | radix_str = "b"; 47 | break; 48 | case OCTAL: 49 | radix_str = "o"; 50 | break; 51 | case HEX: 52 | radix_str = "h"; 53 | break; 54 | case DECIMAL: 55 | radix_str = ""; 56 | break; 57 | } 58 | std::string size_str = std::to_string(size); 59 | if (size_str == "32" && !always_codegen_size) { 60 | size_str = ""; 61 | } 62 | if (size_str != "" && radix_str == "") { 63 | // verilator needs decimal explicitly 64 | radix_str = "d"; 65 | } 66 | 67 | std::string separator = ""; 68 | if (size_str + signed_str + radix_str != "") { 69 | separator = "'"; 70 | } 71 | return size_str + separator + signed_str + radix_str + value; 72 | } 73 | 74 | Identifier::Identifier(std::string value) { 75 | static std::unordered_set sKeywords{ 76 | // clang-format off 77 | "accept_on", "dist", "local", "randomize", "task", 78 | "alias", "do", "localparam", "randsequence", "this", 79 | "always", "edge", "logic", "rcmos", "time", 80 | "always_comb", "else", "longint", "real", "timeprecision", 81 | "always_ff", "end", "macromodule", "realtime", "timeunit", 82 | "always_latch", "enum", "matches", "ref", "tran", 83 | "and", "event", "modport", "reg", "tranif0", 84 | "assert", "eventually", "module", "reject_on", "tranif1", 85 | "assign", "expect", "nand", "release", "tri", 86 | "assume", "export", "negedge", "repeat", "tri0", 87 | "automatic", "extends", "nettype", "restrict", "tri1", 88 | "begin", "extern", "new", "return", "triand", 89 | "bind", "final", "nexttime", "rnmos", "trior", 90 | "bins", "first_match", "nmos", "rpmos", "trireg", 91 | "binsof", "for", "nor", "rtran", "type", 92 | "bit", "force", "noshowcancelled", "rtranif0", "type_option", 93 | "break", "foreach", "not", "rtranif1", "typedef", 94 | "buf", "forever", "notif0", "s_always", "union", 95 | "bufif0", "fork", "notif1", "s_eventually", "unique", 96 | "bufif1", "function", "null", "s_nexttime", "unique0", 97 | "byte", "generate", "option", "scalared", "unsigned", 98 | "case", "genvar", "or", "sequence", "untyped", 99 | "casex", "global", "output", "shortint", "use", 100 | "casez", "if", "package", "shortreal", "uwire", 101 | "cell", "iff", "packed", "showcancelled", "var", 102 | "chandle", "ifnone", "parameter", "signed", "vectored", 103 | "checker", "ignore_bins", "pmos", "soft", "virtual", 104 | "class", "illegal_bins", "posedge", "solve", "void", 105 | "clocking", "implements", "primitive", "specify", "wait", 106 | "cmos", "import", "priority", "specparam", "wait_order", 107 | "config", "initial", "program", "static", "wand", 108 | "const", "inout", "property", "std", "weak", 109 | "constraint", "input", "property_expr", "string", "weak0", 110 | "context", "instance", "protected", "strong", "weak1", 111 | "continue", "int", "pull0", "strong0", "while", 112 | "cover", "integer", "pull1", "strong1", "wildcard", 113 | "covergroup", "interconnect", "pulldown", "struct", "wire", 114 | "coverpoint", "interface", "pullup", "super", "with", 115 | "cross", "intersect", "pulsestyle_ondetect", "supply0", "wor", 116 | "deassign", "join", "pulsestyle_onevent", "supply1", "xnor", 117 | "default", "join_any", "pure", "sync_accept_on", "xor", 118 | "defparam", "join_none", "rand", "sync_reject_on", 119 | "design", "let", "randc", "table", 120 | "disable", "liblist", "randcase", "tagged", 121 | // clang-format on 122 | }; 123 | static std::regex sSimpleIdentifierRE{"^[a-zA-Z$_][a-zA-Z$_0-9]*$"}; 124 | if (sKeywords.count(value) || !std::regex_match(value, sSimpleIdentifierRE)) { 125 | value = "\\" + value + " "; 126 | } 127 | this->value = value; 128 | } 129 | 130 | std::string Identifier::toString() { return this->value; } 131 | 132 | std::string Cast::toString() { 133 | return std::to_string(this->width) + "'(" + this->expr->toString() + ")"; 134 | } 135 | 136 | std::string Attribute::toString() { 137 | return variant_to_string(this->value) + "." + this->attr; 138 | } 139 | 140 | std::string String::toString() { return "\"" + value + "\""; } 141 | 142 | std::string Index::toString() { 143 | return variant_to_string(value) + '[' + index->toString() + ']'; 144 | } 145 | 146 | std::string Slice::toString() { 147 | std::string expr_str = expr_to_string_with_parens(expr); 148 | return expr_str + '[' + high_index->toString() + ':' + low_index->toString() + 149 | ']'; 150 | } 151 | 152 | std::string Vector::toString() { 153 | return "[" + msb->toString() + ':' + lsb->toString() + "] " + id->toString(); 154 | } 155 | 156 | std::string NDVector::toString() { 157 | std::string s = Vector::toString() + " "; 158 | for (auto &dim : outer_dims) { 159 | s += "[" + dim.first->toString() + ":" + dim.second->toString() + "]"; 160 | } 161 | return s; 162 | } 163 | 164 | std::string PackedNDVector::toString() { 165 | std::string s = ""; 166 | for (auto &dim : outer_dims) { 167 | s += "[" + dim.first->toString() + ":" + dim.second->toString() + "]"; 168 | } 169 | return (s + Vector::toString()); 170 | } 171 | 172 | std::string BinaryOp::toString() { 173 | std::string op_str; 174 | switch (op) { 175 | case BinOp::LSHIFT: 176 | op_str = "<<"; 177 | break; 178 | case BinOp::RSHIFT: 179 | op_str = ">>"; 180 | break; 181 | case BinOp::AND: 182 | op_str = "&"; 183 | break; 184 | case BinOp::LAND: 185 | op_str = "&&"; 186 | break; 187 | case BinOp::OR: 188 | op_str = "|"; 189 | break; 190 | case BinOp::LOR: 191 | op_str = "||"; 192 | break; 193 | case BinOp::XOR: 194 | op_str = "^"; 195 | break; 196 | case BinOp::EQ: 197 | op_str = "=="; 198 | break; 199 | case BinOp::NEQ: 200 | op_str = "!="; 201 | break; 202 | case BinOp::ADD: 203 | op_str = "+"; 204 | break; 205 | case BinOp::SUB: 206 | op_str = "-"; 207 | break; 208 | case BinOp::MUL: 209 | op_str = "*"; 210 | break; 211 | case BinOp::DIV: 212 | op_str = "/"; 213 | break; 214 | case BinOp::POW: 215 | op_str = "**"; 216 | break; 217 | case BinOp::MOD: 218 | op_str = "%"; 219 | break; 220 | case BinOp::ALSHIFT: 221 | op_str = "<<<"; 222 | break; 223 | case BinOp::ARSHIFT: 224 | op_str = ">>>"; 225 | break; 226 | case BinOp::LT: 227 | op_str = "<"; 228 | break; 229 | case BinOp::LTE: 230 | op_str = "<="; 231 | break; 232 | case BinOp::GT: 233 | op_str = ">"; 234 | break; 235 | case BinOp::GTE: 236 | op_str = ">="; 237 | break; 238 | } 239 | std::string lstr = expr_to_string_with_parens(left); 240 | std::string rstr = expr_to_string_with_parens(right); 241 | return lstr + ' ' + op_str + ' ' + rstr; 242 | } 243 | 244 | std::string UnaryOp::toString() { 245 | std::string op_str; 246 | switch (op) { 247 | case UnOp::NOT: 248 | op_str = "!"; 249 | break; 250 | case UnOp::INVERT: 251 | op_str = "~"; 252 | break; 253 | case UnOp::AND: 254 | op_str = "&"; 255 | break; 256 | case UnOp::NAND: 257 | op_str = "~&"; 258 | break; 259 | case UnOp::OR: 260 | op_str = "|"; 261 | break; 262 | case UnOp::NOR: 263 | op_str = "~|"; 264 | break; 265 | case UnOp::XOR: 266 | op_str = "^"; 267 | break; 268 | case UnOp::NXOR: 269 | op_str = "~^"; 270 | break; 271 | case UnOp::XNOR: 272 | op_str = "^~"; 273 | break; 274 | case UnOp::PLUS: 275 | op_str = "+"; 276 | break; 277 | case UnOp::MINUS: 278 | op_str = "-"; 279 | break; 280 | } 281 | std::string operand_str = expr_to_string_with_parens(operand); 282 | return op_str + ' ' + operand_str; 283 | } 284 | 285 | std::string TernaryOp::toString() { 286 | return cond->toString() + " ? " + true_value->toString() + " : " + 287 | false_value->toString(); 288 | } 289 | 290 | std::string Concat::toString() { 291 | std::vector arg_strs; 292 | for (auto &arg : args) { 293 | arg_strs.push_back(arg->toString()); 294 | } 295 | std::string prefix = ""; 296 | if (this->unpacked) { 297 | prefix = "'"; 298 | } 299 | return prefix + "{" + join(arg_strs, ",") + "}"; 300 | } 301 | 302 | std::string Replicate::toString() { 303 | // TODO: Insert parens using precedence logic 304 | return "{(" + num->toString() + "){" + value->toString() + "}" + "}"; 305 | } 306 | 307 | std::string NegEdge::toString() { return "negedge " + value->toString(); } 308 | 309 | std::string PosEdge::toString() { return "posedge " + value->toString(); } 310 | 311 | std::string Call::toString() { 312 | std::vector arg_strs; 313 | for (auto &arg : args) { 314 | arg_strs.push_back(arg->toString()); 315 | } 316 | return func + "(" + join(arg_strs, ", ") + ")"; 317 | } 318 | 319 | std::string Port::toString() { 320 | std::string value_str = 321 | variant_to_string, std::unique_ptr>( 322 | value); 323 | std::string direction_str; 324 | switch (direction) { 325 | case INPUT: 326 | direction_str = "input"; 327 | break; 328 | case OUTPUT: 329 | direction_str = "output"; 330 | break; 331 | case INOUT: 332 | direction_str = "inout"; 333 | break; 334 | } 335 | 336 | std::string data_type_str; 337 | switch (data_type) { 338 | case WIRE: 339 | data_type_str = ""; 340 | break; 341 | case REG: 342 | data_type_str = "reg "; 343 | break; 344 | } 345 | return direction_str + " " + data_type_str + value_str; 346 | } 347 | 348 | std::string Module::emitModuleHeader() { 349 | std::string module_header_str = "module " + name; 350 | 351 | // emit parameter string 352 | if (!parameters.empty()) { 353 | module_header_str += " #(\n "; 354 | std::vector param_strs; 355 | for (auto &it : parameters) { 356 | param_strs.push_back("parameter " + variant_to_string(it.first) + " = " + 357 | it.second->toString()); 358 | } 359 | module_header_str += join(param_strs, ",\n "); 360 | module_header_str += "\n)"; 361 | } 362 | 363 | // emit port string 364 | module_header_str += " (\n "; 365 | std::vector ports_strs; 366 | for (auto &it : ports) ports_strs.push_back(it->toString()); 367 | module_header_str += join(ports_strs, ",\n "); 368 | module_header_str += "\n);\n"; 369 | return module_header_str; 370 | } 371 | 372 | std::string Module::toString() { 373 | std::string module_str = ""; 374 | module_str += emitModuleHeader(); 375 | 376 | // emit body 377 | for (auto &statement : body) { 378 | module_str += variant_to_string, 379 | std::unique_ptr>(statement) + 380 | "\n"; 381 | } 382 | 383 | module_str += "endmodule\n"; 384 | return module_str; 385 | } 386 | 387 | std::string StringBodyModule::toString() { 388 | std::string module_str = ""; 389 | module_str += emitModuleHeader(); 390 | module_str += body; 391 | module_str += "\nendmodule\n"; 392 | return module_str; 393 | } 394 | 395 | std::string ModuleInstantiation::toString() { 396 | std::string module_inst_str = ""; 397 | module_inst_str += module_name; 398 | if (!parameters.empty()) { 399 | module_inst_str += " #(\n "; 400 | std::vector param_strs; 401 | for (auto &it : parameters) { 402 | param_strs.push_back("." + variant_to_string(it.first) + "(" + 403 | it.second->toString() + ")"); 404 | } 405 | module_inst_str += join(param_strs, ",\n "); 406 | module_inst_str += "\n)"; 407 | } 408 | module_inst_str += " " + instance_name + " (\n "; 409 | if (!connections->empty()) { 410 | std::vector param_strs; 411 | for (auto &it : *connections) { 412 | param_strs.push_back("." + it.first + "(" + it.second->toString() + ")"); 413 | } 414 | module_inst_str += join(param_strs, ",\n "); 415 | } 416 | module_inst_str += "\n);"; 417 | return module_inst_str; 418 | } 419 | 420 | std::string IfMacro::toString() { 421 | std::string s = this->getMacroString(); 422 | s += this->condition_str + "\n"; 423 | for (auto &statement : this->true_body) { 424 | s += variant_to_string(statement) + "\n"; 425 | } 426 | if (this->else_body.size() > 0) { 427 | s += "`else\n"; 428 | for (auto &statement : this->else_body) { 429 | s += variant_to_string(statement) + "\n"; 430 | } 431 | } 432 | return s + "`endif"; 433 | } 434 | 435 | std::string Declaration::toString() { 436 | return decl + " " + variant_to_string(value) + ";"; 437 | } 438 | 439 | std::string Assign::toString() { 440 | return prefix + variant_to_string(target) + " " + symbol + " " + 441 | value->toString() + ";"; 442 | } 443 | 444 | std::string Always::toString() { 445 | std::string always_str = ""; 446 | always_str += "always @("; 447 | 448 | // emit sensitivity string 449 | std::vector sensitivity_strs; 450 | for (auto &it : sensitivity_list) { 451 | sensitivity_strs.push_back(variant_to_string(it)); 452 | } 453 | always_str += join(sensitivity_strs, ", "); 454 | always_str += ") begin\n"; 455 | 456 | // emit body 457 | for (auto &statement : body) { 458 | always_str += statement->toString() + "\n"; 459 | } 460 | 461 | always_str += "end\n"; 462 | return always_str; 463 | } 464 | 465 | std::string add_tab(std::string block) { 466 | // Indents each line by four spaces, adds an extra newline at the end 467 | std::istringstream block_stream(block); 468 | std::string new_block; 469 | while (!block_stream.eof()) { 470 | std::string line; 471 | std::getline(block_stream, line); 472 | new_block += " " + line + "\n"; 473 | } 474 | return new_block; 475 | } 476 | 477 | std::string If::toString() { 478 | std::string if_str = ""; 479 | if_str += "if ("; 480 | if_str += this->cond->toString(); 481 | if_str += ") begin\n"; 482 | 483 | for (auto &statement : this->true_body) { 484 | if_str += add_tab(statement->toString()); 485 | } 486 | 487 | if_str += "end"; 488 | 489 | for (auto &entry : this->else_ifs) { 490 | if_str += " else if (" + entry.first->toString() + ") begin\n"; 491 | for (auto &statement : entry.second) { 492 | if_str += add_tab(statement->toString()); 493 | } 494 | if_str += "end"; 495 | } 496 | 497 | if (this->else_body.size()) { 498 | if_str += " else begin\n"; 499 | for (auto &statement : else_body) { 500 | if_str += add_tab(statement->toString()); 501 | } 502 | if_str += "end"; 503 | } 504 | return if_str; 505 | } 506 | 507 | std::string File::toString() { 508 | std::string file_str = ""; 509 | 510 | std::vector file_strs; 511 | for (auto &module : modules) { 512 | file_strs.push_back(module->toString()); 513 | } 514 | 515 | return join(file_strs, "\n"); 516 | } 517 | 518 | std::unique_ptr make_id(std::string name) { 519 | return std::make_unique(name); 520 | } 521 | 522 | std::unique_ptr make_num(std::string val) { 523 | return std::make_unique(val); 524 | } 525 | 526 | std::unique_ptr make_binop(std::unique_ptr left, 527 | BinOp::BinOp op, 528 | std::unique_ptr right) { 529 | return std::make_unique(std::move(left), op, std::move(right)); 530 | } 531 | 532 | std::unique_ptr make_port( 533 | std::variant, std::unique_ptr> value, 534 | Direction direction, PortType data_type) { 535 | return std::make_unique(std::move(value), direction, data_type); 536 | } 537 | 538 | std::unique_ptr make_vector(std::unique_ptr id, 539 | std::unique_ptr msb, 540 | std::unique_ptr lsb) { 541 | return std::make_unique(std::move(id), std::move(msb), 542 | std::move(lsb)); 543 | } 544 | 545 | std::string SingleLineComment::toString() { 546 | std::string result = ""; 547 | if (this->statement) { 548 | result += this->statement->toString() + " "; 549 | } 550 | return result + "// " + value; 551 | } 552 | 553 | } // namespace verilogAST 554 | -------------------------------------------------------------------------------- /src/zext_coalescer.cpp: -------------------------------------------------------------------------------- 1 | #include "verilogAST/zext_coalescer.hpp" 2 | #include 3 | 4 | namespace verilogAST { 5 | 6 | namespace { 7 | 8 | using ConcatArg = std::unique_ptr; 9 | using ConcatArgs = std::vector; 10 | 11 | std::pair num_zeros(Expression* const expr) { 12 | auto ptr = dynamic_cast(expr); 13 | if (not ptr) return {false, 0}; 14 | switch (ptr->radix) { 15 | // TODO(rsetaluri): This is conservative in that it will only perform the 16 | // logic for decimal zero's. This should be expanded to support binary, hex, 17 | // etc. zero's as well. 18 | case DECIMAL: { 19 | auto value = std::atoi(ptr->value.c_str()); 20 | if (value == 0) return {true, ptr->size}; 21 | return {false, 0}; 22 | break; 23 | } 24 | default: { 25 | return {false, 0}; 26 | } 27 | } 28 | } 29 | 30 | std::pair processArguments( 31 | const ConcatArgs& args) { 32 | int zeros = 0; 33 | auto it = args.begin(); 34 | for (; it != args.end(); it++) { 35 | auto res = num_zeros(it->get()); 36 | if (not res.first) break; 37 | zeros += res.second; 38 | } 39 | return {zeros, it}; 40 | } 41 | 42 | } // namespace 43 | 44 | std::unique_ptr ZextCoalescer::visit( 45 | std::unique_ptr node) { 46 | auto ptr = dynamic_cast(node.get()); 47 | // This pass only operates on non-empty Concat nodes. 48 | if (not ptr or ptr->args.size() == 0) return node; 49 | auto res = processArguments(ptr->args); 50 | if (res.first == 0) { 51 | assert(res.second == ptr->args.begin()); 52 | return node; 53 | } 54 | ConcatArgs args; 55 | if (not elide_) { 56 | args.emplace_back(new NumericLiteral("0", res.first)); 57 | } 58 | for (auto it = res.second; it != ptr->args.end(); it++) { 59 | args.push_back((*it)->clone()); 60 | } 61 | return std::make_unique(std::move(args)); 62 | } 63 | 64 | } // namespace verilogAST 65 | -------------------------------------------------------------------------------- /tests/basic.cpp: -------------------------------------------------------------------------------- 1 | #include "common.cpp" 2 | #include "gtest/gtest.h" 3 | #include "verilogAST.hpp" 4 | 5 | namespace vAST = verilogAST; 6 | 7 | namespace { 8 | 9 | TEST(BasicTests, TestNumericLiteral) { 10 | vAST::NumericLiteral n0("23", 16, false, vAST::DECIMAL); 11 | EXPECT_EQ(n0.toString(), "16'd23"); 12 | 13 | vAST::NumericLiteral n1("DEADBEEF", 32, false, vAST::HEX); 14 | EXPECT_EQ(n1.toString(), "'hDEADBEEF"); 15 | 16 | vAST::NumericLiteral n2("011001", 6, false, vAST::BINARY); 17 | EXPECT_EQ(n2.toString(), "6'b011001"); 18 | 19 | vAST::NumericLiteral n3("764", 24, false, vAST::OCTAL); 20 | EXPECT_EQ(n3.toString(), "24'o764"); 21 | 22 | vAST::NumericLiteral n4("764", 8, false); 23 | EXPECT_EQ(n4.toString(), "8'd764"); 24 | 25 | vAST::NumericLiteral n5("764", 8); 26 | EXPECT_EQ(n5.toString(), "8'd764"); 27 | 28 | vAST::NumericLiteral n6("764"); 29 | EXPECT_EQ(n6.toString(), "764"); 30 | 31 | vAST::NumericLiteral n7("764", 8, true); 32 | EXPECT_EQ(n7.toString(), "8'sd764"); 33 | 34 | vAST::NumericLiteral n8("z", vAST::Radix::HEX); 35 | EXPECT_EQ(n8.toString(), "'hz"); 36 | 37 | // Test always codegen prefix 38 | vAST::NumericLiteral n9("DEADBEEF", 32, false, vAST::HEX, true); 39 | EXPECT_EQ(n9.toString(), "32'hDEADBEEF"); 40 | } 41 | 42 | TEST(BasicTests, TestIdentifier) { 43 | vAST::Identifier id("x"); 44 | EXPECT_EQ(id.toString(), "x"); 45 | } 46 | 47 | TEST(BasicTests, TestCast) { 48 | vAST::NumericLiteral n8("z", vAST::Radix::HEX); 49 | vAST::Cast cast(5, vAST::make_id("x")); 50 | 51 | EXPECT_EQ(cast.toString(), "5'(x)"); 52 | } 53 | 54 | TEST(BasicTests, TestAttribute) { 55 | vAST::Attribute attr(vAST::make_id("x"), "y"); 56 | EXPECT_EQ(attr.toString(), "x.y"); 57 | vAST::Attribute attr2( 58 | std::make_unique(vAST::make_id("a"), "b"), "c"); 59 | EXPECT_EQ(attr2.toString(), "a.b.c"); 60 | } 61 | 62 | TEST(BasicTests, TestIdentifierEscaped) { 63 | vAST::Identifier id("instance[5]"); 64 | EXPECT_EQ(id.toString(), "\\instance[5] "); 65 | } 66 | 67 | TEST(BasicTests, TestIdentifierKeyword) { 68 | vAST::Identifier id("or"); 69 | EXPECT_EQ(id.toString(), "\\or "); 70 | } 71 | 72 | TEST(BasicTests, TestString) { 73 | vAST::String str("mystring"); 74 | EXPECT_EQ(str.toString(), "\"mystring\""); 75 | } 76 | 77 | TEST(BasicTests, TestIndex) { 78 | vAST::Index index(vAST::make_id("x"), vAST::make_num("0")); 79 | EXPECT_EQ(index.toString(), "x[0]"); 80 | 81 | vAST::Index index2( 82 | std::make_unique(vAST::make_id("x"), vAST::make_num("3"), 83 | vAST::make_num("0")), 84 | vAST::make_num("0")); 85 | EXPECT_EQ(index2.toString(), "x[3:0][0]"); 86 | 87 | vAST::Index index3(std::make_unique(vAST::make_id("x"), "y"), 88 | vAST::make_num("0")); 89 | EXPECT_EQ(index3.toString(), "x.y[0]"); 90 | } 91 | 92 | TEST(BasicTests, TestSlice) { 93 | vAST::Identifier id("x"); 94 | vAST::Slice slice(vAST::make_id("x"), vAST::make_num("31"), 95 | vAST::make_num("0")); 96 | EXPECT_EQ(slice.toString(), "x[31:0]"); 97 | 98 | std::unique_ptr x = std::make_unique( 99 | std::make_unique(vAST::make_id("x"), vAST::make_num("31"), 100 | vAST::make_num("0")), 101 | std::make_unique("b"), 102 | std::make_unique("c")); 103 | EXPECT_EQ(x->toString(), "x[31:0][b:c]"); 104 | std::unique_ptr x2 = std::make_unique( 105 | 106 | std::make_unique(vAST::make_id("x"), vAST::make_num("0")), 107 | std::make_unique("b"), 108 | std::make_unique("c")); 109 | EXPECT_EQ(x2->toString(), "x[0][b:c]"); 110 | std::unique_ptr x3 = std::make_unique( 111 | 112 | std::make_unique(vAST::make_id("x"), vAST::BinOp::ADD, 113 | vAST::make_id("y")), 114 | std::make_unique("b"), 115 | std::make_unique("c")); 116 | EXPECT_EQ(x3->toString(), "(x + y)[b:c]"); 117 | } 118 | 119 | TEST(BasicTests, TestVector) { 120 | vAST::Vector slice(vAST::make_id("x"), vAST::make_num("31"), 121 | vAST::make_num("0")); 122 | EXPECT_EQ(slice.toString(), "[31:0] x"); 123 | } 124 | 125 | TEST(BasicTests, TestNDVector) { 126 | std::vector, 127 | std::unique_ptr>> 128 | outer_dims; 129 | outer_dims.push_back({vAST::make_num("7"), vAST::make_num("0")}); 130 | outer_dims.push_back({vAST::make_num("15"), vAST::make_num("0")}); 131 | vAST::NDVector slice(vAST::make_id("x"), vAST::make_num("31"), 132 | vAST::make_num("0"), std::move(outer_dims)); 133 | EXPECT_EQ(slice.toString(), "[31:0] x [7:0][15:0]"); 134 | } 135 | 136 | TEST(BasicTests, TestPackedNDVector) { 137 | std::vector, 138 | std::unique_ptr>> 139 | outer_dims; 140 | outer_dims.push_back({vAST::make_num("7"), vAST::make_num("0")}); 141 | outer_dims.push_back({vAST::make_num("15"), vAST::make_num("0")}); 142 | vAST::PackedNDVector slice(vAST::make_id("x"), vAST::make_num("31"), 143 | vAST::make_num("0"), std::move(outer_dims)); 144 | EXPECT_EQ(slice.toString(), "[7:0][15:0][31:0] x"); 145 | } 146 | 147 | TEST(BasicTests, TestBinaryOp) { 148 | std::vector> ops; 149 | ops.push_back(std::make_pair(vAST::BinOp::LSHIFT, "<<")); 150 | ops.push_back(std::make_pair(vAST::BinOp::RSHIFT, ">>")); 151 | ops.push_back(std::make_pair(vAST::BinOp::LAND, "&&")); 152 | ops.push_back(std::make_pair(vAST::BinOp::LOR, "||")); 153 | ops.push_back(std::make_pair(vAST::BinOp::EQ, "==")); 154 | ops.push_back(std::make_pair(vAST::BinOp::NEQ, "!=")); 155 | ops.push_back(std::make_pair(vAST::BinOp::ADD, "+")); 156 | ops.push_back(std::make_pair(vAST::BinOp::SUB, "-")); 157 | ops.push_back(std::make_pair(vAST::BinOp::MUL, "*")); 158 | ops.push_back(std::make_pair(vAST::BinOp::DIV, "/")); 159 | ops.push_back(std::make_pair(vAST::BinOp::POW, "**")); 160 | ops.push_back(std::make_pair(vAST::BinOp::MOD, "%")); 161 | ops.push_back(std::make_pair(vAST::BinOp::ALSHIFT, "<<<")); 162 | ops.push_back(std::make_pair(vAST::BinOp::ARSHIFT, ">>>")); 163 | ops.push_back(std::make_pair(vAST::BinOp::LT, "<")); 164 | ops.push_back(std::make_pair(vAST::BinOp::LTE, "<=")); 165 | ops.push_back(std::make_pair(vAST::BinOp::GT, ">")); 166 | ops.push_back(std::make_pair(vAST::BinOp::GTE, ">=")); 167 | ops.push_back(std::make_pair(vAST::BinOp::XOR, "^")); 168 | ops.push_back(std::make_pair(vAST::BinOp::AND, "&")); 169 | ops.push_back(std::make_pair(vAST::BinOp::OR, "|")); 170 | for (auto it : ops) { 171 | vAST::BinOp::BinOp op = it.first; 172 | std::string op_str = it.second; 173 | vAST::BinaryOp bin_op(vAST::make_id("x"), op, vAST::make_id("y")); 174 | EXPECT_EQ(bin_op.toString(), "x " + op_str + " y"); 175 | } 176 | } 177 | 178 | TEST(BasicTests, TestUnaryOp) { 179 | std::vector> ops; 180 | ops.push_back(std::make_pair(vAST::UnOp::NOT, "!")); 181 | ops.push_back(std::make_pair(vAST::UnOp::INVERT, "~")); 182 | ops.push_back(std::make_pair(vAST::UnOp::AND, "&")); 183 | ops.push_back(std::make_pair(vAST::UnOp::NAND, "~&")); 184 | ops.push_back(std::make_pair(vAST::UnOp::OR, "|")); 185 | ops.push_back(std::make_pair(vAST::UnOp::NOR, "~|")); 186 | ops.push_back(std::make_pair(vAST::UnOp::XOR, "^")); 187 | ops.push_back(std::make_pair(vAST::UnOp::NXOR, "~^")); 188 | ops.push_back(std::make_pair(vAST::UnOp::XNOR, "^~")); 189 | ops.push_back(std::make_pair(vAST::UnOp::PLUS, "+")); 190 | ops.push_back(std::make_pair(vAST::UnOp::MINUS, "-")); 191 | for (auto it : ops) { 192 | vAST::UnOp::UnOp op = it.first; 193 | std::string op_str = it.second; 194 | vAST::UnaryOp un_op(vAST::make_id("x"), op); 195 | EXPECT_EQ(un_op.toString(), op_str + " x"); 196 | } 197 | } 198 | 199 | TEST(BasicTests, TestUnaryParens) { 200 | vAST::UnaryOp un_op(vAST::make_binop(vAST::make_id("x"), vAST::BinOp::ADD, 201 | vAST::make_id("y")), 202 | vAST::UnOp::INVERT); 203 | EXPECT_EQ(un_op.toString(), "~ (x + y)"); 204 | } 205 | 206 | TEST(BasicTests, TestTernaryOp) { 207 | vAST::UnaryOp un_op(std::make_unique("x"), 208 | vAST::UnOp::INVERT); 209 | vAST::TernaryOp tern_op( 210 | std::make_unique(vAST::make_id("x"), vAST::UnOp::INVERT), 211 | vAST::make_num("1"), vAST::make_num("0")); 212 | EXPECT_EQ(tern_op.toString(), "~ x ? 1 : 0"); 213 | } 214 | 215 | TEST(BasicTests, TestConcat) { 216 | std::vector> args; 217 | args.push_back(vAST::make_id("x")); 218 | args.push_back(vAST::make_id("y")); 219 | vAST::Concat concat(std::move(args)); 220 | EXPECT_EQ(concat.toString(), "{x,y}"); 221 | 222 | std::vector> args2; 223 | args2.push_back(vAST::make_id("x")); 224 | args2.push_back(vAST::make_id("y")); 225 | vAST::Concat concat2(std::move(args2), true); 226 | EXPECT_EQ(concat2.toString(), "'{x,y}"); 227 | } 228 | 229 | TEST(BasicTests, TestReplicate) { 230 | vAST::Replicate replicate(vAST::make_num("3"), vAST::make_num("4")); 231 | EXPECT_EQ(replicate.toString(), "{(3){4}}"); 232 | } 233 | 234 | TEST(BasicTests, TestReplicateExpr) { 235 | vAST::Replicate replicate( 236 | vAST::make_binop(vAST::make_id("x"), vAST::BinOp::ADD, 237 | vAST::make_id("y")), 238 | vAST::make_num("4")); 239 | EXPECT_EQ(replicate.toString(), "{(x + y){4}}"); 240 | } 241 | 242 | TEST(BasicTests, TestNegEdge) { 243 | vAST::NegEdge neg_edge(vAST::make_id("clk")); 244 | 245 | EXPECT_EQ(neg_edge.toString(), "negedge clk"); 246 | } 247 | 248 | TEST(BasicTests, TestPosEdge) { 249 | vAST::PosEdge pos_edge(vAST::make_id("clk")); 250 | 251 | EXPECT_EQ(pos_edge.toString(), "posedge clk"); 252 | } 253 | 254 | TEST(BasicTests, TestCallExpr0) { 255 | std::vector> args; 256 | args.push_back(vAST::make_id("x")); 257 | args.push_back(vAST::make_id("y")); 258 | vAST::CallExpr my_func("my_func", std::move(args)); 259 | EXPECT_EQ(my_func.toString(), "my_func(x, y)"); 260 | } 261 | 262 | TEST(BasicTests, TestCallExpr1) { 263 | std::vector> args; 264 | args.push_back(vAST::make_num("7")); 265 | vAST::CallExpr clog2("$clog2", std::move(args)); 266 | EXPECT_EQ(clog2.toString(), "$clog2(7)"); 267 | } 268 | 269 | TEST(BasicTests, TestCallExprNoArgs) { 270 | vAST::CallExpr foo("$foo"); 271 | EXPECT_EQ(foo.toString(), "$foo()"); 272 | } 273 | 274 | TEST(BasicTests, TestCallStmt0) { 275 | std::vector> args; 276 | args.push_back(vAST::make_id("x")); 277 | args.push_back(vAST::make_id("y")); 278 | vAST::CallStmt my_func("my_func", std::move(args)); 279 | EXPECT_EQ(my_func.toString(), "my_func(x, y);"); 280 | } 281 | 282 | TEST(BasicTests, TestCallStmt1) { 283 | std::vector> args; 284 | args.push_back(vAST::make_num("7")); 285 | vAST::CallStmt clog2("$clog2", std::move(args)); 286 | EXPECT_EQ(clog2.toString(), "$clog2(7);"); 287 | } 288 | 289 | TEST(BasicTests, TestCallStmtNoArgs) { 290 | vAST::CallStmt foo("$foo"); 291 | EXPECT_EQ(foo.toString(), "$foo();"); 292 | } 293 | 294 | TEST(BasicTests, TestPort) { 295 | vAST::Port i_port(vAST::make_id("i"), vAST::INPUT, vAST::WIRE); 296 | 297 | EXPECT_EQ(i_port.toString(), "input i"); 298 | 299 | vAST::Port o_port(vAST::make_id("o"), vAST::OUTPUT, vAST::WIRE); 300 | 301 | EXPECT_EQ(o_port.toString(), "output o"); 302 | 303 | vAST::Port io_port(vAST::make_id("io"), vAST::INOUT, vAST::WIRE); 304 | 305 | EXPECT_EQ(io_port.toString(), "inout io"); 306 | 307 | vAST::Port o_reg_port(vAST::make_id("o"), vAST::OUTPUT, vAST::REG); 308 | 309 | EXPECT_EQ(o_reg_port.toString(), "output reg o"); 310 | } 311 | 312 | TEST(BasicTests, TestStringPort) { 313 | vAST::StringPort port("output reg [width-1:0] I"); 314 | 315 | EXPECT_EQ(port.toString(), "output reg [width-1:0] I"); 316 | } 317 | 318 | TEST(BasicTests, TestModuleInst) { 319 | std::string module_name = "test_module"; 320 | 321 | vAST::Parameters parameters = make_simple_params(); 322 | 323 | std::string instance_name = "test_module_inst"; 324 | 325 | vAST::ModuleInstantiation module_inst(module_name, std::move(parameters), 326 | instance_name, 327 | make_simple_connections()); 328 | 329 | EXPECT_EQ(module_inst.toString(), 330 | "test_module #(\n" 331 | " .param0(0),\n" 332 | " .param1(1)\n" 333 | ") test_module_inst (\n" 334 | " .a(a),\n" 335 | " .b(b[0]),\n" 336 | " .c(c[31:0])\n" 337 | ");"); 338 | } 339 | 340 | TEST(BasicTests, TestModule) { 341 | std::string name = "test_module"; 342 | 343 | vAST::Parameters parameters; 344 | parameters.push_back(std::make_pair( 345 | std::make_unique(vAST::make_id("param1"), 346 | vAST::make_num("3"), vAST::make_num("0")), 347 | vAST::make_num("1"))); 348 | vAST::Module module(name, make_simple_ports(), make_simple_body(), 349 | std::move(parameters)); 350 | 351 | std::string expected_str = 352 | "module test_module #(\n" 353 | " parameter [3:0] param1 = 1\n" 354 | ") (\n" 355 | " input i,\n" 356 | " output o\n" 357 | ");\n" 358 | "other_module #(\n" 359 | " .param0(0),\n" 360 | " .param1(1)\n" 361 | ") other_module_inst (\n" 362 | " .a(a),\n" 363 | " .b(b[0]),\n" 364 | " .c(c[31:0])\n" 365 | ");\n" 366 | "endmodule\n"; 367 | EXPECT_EQ(module.toString(), expected_str); 368 | } 369 | 370 | TEST(BasicTests, TestParamModule) { 371 | std::string name = "test_module"; 372 | 373 | vAST::Module module_with_params(name, make_simple_ports(), make_simple_body(), 374 | make_simple_params()); 375 | 376 | std::string expected_str = 377 | "module test_module #(\n" 378 | " parameter param0 = 0,\n" 379 | " parameter param1 = 1\n" 380 | ") (\n" 381 | " input i,\n" 382 | " output o\n" 383 | ");\n" 384 | "other_module #(\n" 385 | " .param0(0),\n" 386 | " .param1(1)\n" 387 | ") other_module_inst (\n" 388 | " .a(a),\n" 389 | " .b(b[0]),\n" 390 | " .c(c[31:0])\n" 391 | ");\n" 392 | "endmodule\n"; 393 | EXPECT_EQ(module_with_params.toString(), expected_str); 394 | } 395 | 396 | TEST(BasicTests, TestStringBodyModule) { 397 | std::string name = "test_module"; 398 | 399 | std::string module_name = "other_module"; 400 | 401 | std::string string_body = "reg d;\nassign d = a + b;\nassign c = d;"; 402 | vAST::StringBodyModule string_body_module(name, make_simple_ports(), 403 | string_body, make_simple_params()); 404 | std::string expected_str = 405 | "module test_module #(\n" 406 | " parameter param0 = 0,\n" 407 | " parameter param1 = 1\n" 408 | ") (\n" 409 | " input i,\n" 410 | " output o\n" 411 | ");\n" 412 | "reg d;\n" 413 | "assign d = a + b;\n" 414 | "assign c = " 415 | "d;\n" 416 | "endmodule\n"; 417 | EXPECT_EQ(string_body_module.toString(), expected_str); 418 | 419 | vAST::StringModule string_module(expected_str); 420 | EXPECT_EQ(string_module.toString(), expected_str); 421 | } 422 | 423 | TEST(BasicTests, TestDeclaration) { 424 | vAST::Wire wire(std::make_unique("a")); 425 | EXPECT_EQ(wire.toString(), "wire a;"); 426 | 427 | vAST::Reg reg(std::make_unique("a")); 428 | EXPECT_EQ(reg.toString(), "reg a;"); 429 | 430 | vAST::Reg reg_slice(std::make_unique( 431 | std::make_unique("x"), 432 | std::make_unique("31"), 433 | std::make_unique("0"))); 434 | EXPECT_EQ(reg_slice.toString(), "reg x[31:0];"); 435 | 436 | vAST::Reg reg_index(std::make_unique( 437 | std::make_unique("x"), 438 | std::make_unique("31"))); 439 | EXPECT_EQ(reg_index.toString(), "reg x[31];"); 440 | 441 | vAST::Reg reg_vec(std::make_unique( 442 | std::make_unique("x"), 443 | std::make_unique("31"), 444 | std::make_unique("0"))); 445 | EXPECT_EQ(reg_vec.toString(), "reg [31:0] x;"); 446 | } 447 | 448 | TEST(BasicTests, TestAssign) { 449 | vAST::ContinuousAssign cont_assign(std::make_unique("a"), 450 | std::make_unique("b")); 451 | EXPECT_EQ(cont_assign.toString(), "assign a = b;"); 452 | 453 | vAST::BlockingAssign blocking_assign(std::make_unique("a"), 454 | std::make_unique("b")); 455 | EXPECT_EQ(blocking_assign.toString(), "a = b;"); 456 | 457 | vAST::NonBlockingAssign non_blocking_assign( 458 | std::make_unique("a"), 459 | std::make_unique("b")); 460 | EXPECT_EQ(non_blocking_assign.toString(), "a <= b;"); 461 | } 462 | 463 | TEST(BasicTests, TestAlways) { 464 | std::vector, std::unique_ptr, 466 | std::unique_ptr, std::unique_ptr>> 467 | sensitivity_list; 468 | sensitivity_list.push_back(std::make_unique("a")); 469 | sensitivity_list.push_back( 470 | std::make_unique(std::make_unique("b"))); 471 | sensitivity_list.push_back( 472 | std::make_unique(std::make_unique("c"))); 473 | vAST::Always always(std::move(sensitivity_list), make_simple_always_body()); 474 | std::string expected_str = 475 | "always @(a, posedge b, negedge c) begin\n" 476 | "a = b;\n" 477 | "b <= c;\n" 478 | "$display(\"b=%d, c=%d\", b, c);\n" 479 | "if (b) begin\n" 480 | " e = f;\n" 481 | "end else if (x0) begin\n" 482 | " e = g0;\n" 483 | "end else if (x1) begin\n" 484 | " e = g1;\n" 485 | "end else begin\n" 486 | " e = g;\n" 487 | "end\n" 488 | "end\n"; 489 | EXPECT_EQ(always.toString(), expected_str); 490 | } 491 | 492 | TEST(BasicTests, TestAlwaysStar) { 493 | std::vector, std::unique_ptr, 495 | std::unique_ptr, std::unique_ptr>> 496 | sensitivity_list; 497 | sensitivity_list.push_back(std::make_unique()); 498 | 499 | vAST::Always always_star(std::move(sensitivity_list), 500 | make_simple_always_body()); 501 | std::string expected_str = 502 | "always @(*) begin\n" 503 | "a = b;\n" 504 | "b <= c;\n" 505 | "$display(\"b=%d, c=%d\", b, c);\n" 506 | "if (b) begin\n" 507 | " e = f;\n" 508 | "end else if (x0) begin\n" 509 | " e = g0;\n" 510 | "end else if (x1) begin\n" 511 | " e = g1;\n" 512 | "end else begin\n" 513 | " e = g;\n" 514 | "end\n" 515 | "end\n"; 516 | EXPECT_EQ(always_star.toString(), expected_str); 517 | } 518 | 519 | TEST(BasicTests, TestAlwaysEmpty) { 520 | std::vector, std::unique_ptr, 522 | std::unique_ptr, std::unique_ptr>> 523 | sensitivity_list; 524 | std::vector> body; 525 | 526 | ASSERT_THROW( 527 | vAST::Always always_empty(std::move(sensitivity_list), std::move(body)), 528 | std::runtime_error); 529 | } 530 | 531 | TEST(BasicTests, File) { 532 | std::vector> modules; 533 | vAST::Parameters parameters0; 534 | modules.push_back(std::make_unique( 535 | "test_module0", make_simple_ports(), make_simple_body(), 536 | std::move(parameters0))); 537 | 538 | modules.push_back( 539 | std::make_unique("test_module1", make_simple_ports(), 540 | make_simple_body(), make_simple_params())); 541 | 542 | vAST::File file(modules); 543 | 544 | std::string expected_str = 545 | "module test_module0 (\n" 546 | " input i,\n" 547 | " output o\n" 548 | ");\n" 549 | "other_module #(\n" 550 | " .param0(0),\n" 551 | " .param1(1)\n" 552 | ") other_module_inst (\n" 553 | " .a(a),\n" 554 | " .b(b[0]),\n" 555 | " .c(c[31:0])\n" 556 | ");\n" 557 | "endmodule\n\n" 558 | "module test_module1 #(\n" 559 | " parameter param0 = 0,\n" 560 | " parameter param1 = 1\n" 561 | ") (\n" 562 | " input i,\n" 563 | " output o\n" 564 | ");\n" 565 | "other_module #(\n" 566 | " .param0(0),\n" 567 | " .param1(1)\n" 568 | ") other_module_inst (\n" 569 | " .a(a),\n" 570 | " .b(b[0]),\n" 571 | " .c(c[31:0])\n" 572 | ");\n" 573 | "endmodule\n"; 574 | EXPECT_EQ(file.toString(), expected_str); 575 | } 576 | TEST(BasicTests, Comment) { 577 | vAST::SingleLineComment single_line_comment("Test comment"); 578 | EXPECT_EQ(single_line_comment.toString(), "// Test comment"); 579 | vAST::BlockComment block_comment("Test comment\non multiple lines"); 580 | EXPECT_EQ(block_comment.toString(), 581 | "/*\nTest comment\non multiple lines\n*/"); 582 | std::unique_ptr cont_assign = 583 | std::make_unique( 584 | std::make_unique("a"), 585 | std::make_unique("b")); 586 | vAST::SingleLineComment stmt_with_comment("Test comment", 587 | std::move(cont_assign)); 588 | EXPECT_EQ(stmt_with_comment.toString(), "assign a = b; // Test comment"); 589 | std::unique_ptr> port_with_comment = 590 | vAST::AddComment(std::make_unique(vAST::make_id("i"), 591 | vAST::INPUT, vAST::WIRE), 592 | "verilator_public"); 593 | EXPECT_EQ(port_with_comment->toString(), "input i/*verilator_public*/"); 594 | } 595 | TEST(BasicTests, InlineVerilog) { 596 | vAST::InlineVerilog inline_verilog( 597 | "logic [1:0] x;\n" 598 | "assign x = 2'b10;\n"); 599 | EXPECT_EQ(inline_verilog.toString(), 600 | "logic [1:0] x;\n" 601 | "assign x = 2'b10;\n"); 602 | } 603 | 604 | TEST(BasicTests, TestNumCopy) { 605 | std::unique_ptr x = 606 | std::make_unique("32'hDEADBEEF"); 607 | std::unique_ptr x1 = 608 | std::make_unique(*x); 609 | EXPECT_EQ(x->toString(), "32'hDEADBEEF"); 610 | EXPECT_EQ(x1->toString(), "32'hDEADBEEF"); 611 | x1->value = "3b010"; 612 | EXPECT_EQ(x->toString(), "32'hDEADBEEF"); 613 | EXPECT_EQ(x1->toString(), "3b010"); 614 | } 615 | 616 | TEST(BasicTests, TestIdentifierCopy) { 617 | std::unique_ptr x = std::make_unique("x"); 618 | std::unique_ptr x1 = std::make_unique(*x); 619 | EXPECT_EQ(x->toString(), "x"); 620 | EXPECT_EQ(x1->toString(), "x"); 621 | x1->value = "y"; 622 | EXPECT_EQ(x->toString(), "x"); 623 | EXPECT_EQ(x1->toString(), "y"); 624 | } 625 | 626 | TEST(BasicTests, TestStringCopy) { 627 | std::unique_ptr x = std::make_unique("str"); 628 | std::unique_ptr x1 = std::make_unique(*x); 629 | EXPECT_EQ(x->toString(), "\"str\""); 630 | EXPECT_EQ(x1->toString(), "\"str\""); 631 | x1->value = "bar"; 632 | EXPECT_EQ(x->toString(), "\"str\""); 633 | EXPECT_EQ(x1->toString(), "\"bar\""); 634 | } 635 | 636 | TEST(BasicTests, TestIndexCopy) { 637 | std::unique_ptr x = 638 | std::make_unique(std::make_unique("x"), 639 | std::make_unique("y")); 640 | 641 | std::unique_ptr x1 = std::make_unique(*x); 642 | EXPECT_EQ(x->toString(), "x[y]"); 643 | EXPECT_EQ(x1->toString(), "x[y]"); 644 | x1->value = vAST::make_id("z"); 645 | x1->index = std::make_unique("a"); 646 | EXPECT_EQ(x->toString(), "x[y]"); 647 | EXPECT_EQ(x1->toString(), "z[a]"); 648 | } 649 | 650 | TEST(BasicTests, TestSliceCopy) { 651 | std::unique_ptr x = 652 | std::make_unique(std::make_unique("x"), 653 | std::make_unique("y"), 654 | std::make_unique("z")); 655 | 656 | std::unique_ptr x1 = std::make_unique(*x); 657 | EXPECT_EQ(x->toString(), "x[y:z]"); 658 | EXPECT_EQ(x1->toString(), "x[y:z]"); 659 | x1->expr = std::make_unique("a"); 660 | x1->high_index = std::make_unique("b"); 661 | x1->low_index = std::make_unique("c"); 662 | EXPECT_EQ(x->toString(), "x[y:z]"); 663 | EXPECT_EQ(x1->toString(), "a[b:c]"); 664 | } 665 | 666 | TEST(BasicTests, TestBinOpCopy) { 667 | std::unique_ptr x = std::make_unique( 668 | std::make_unique("x"), vAST::BinOp::ADD, 669 | std::make_unique("z")); 670 | 671 | std::unique_ptr x1 = std::make_unique(*x); 672 | EXPECT_EQ(x->toString(), "x + z"); 673 | EXPECT_EQ(x1->toString(), "x + z"); 674 | x1->left = std::make_unique("a"); 675 | x1->right = std::make_unique("b"); 676 | x1->op = vAST::BinOp::SUB; 677 | EXPECT_EQ(x->toString(), "x + z"); 678 | EXPECT_EQ(x1->toString(), "a - b"); 679 | } 680 | 681 | TEST(BasicTests, TestUnOpCopy) { 682 | std::unique_ptr x = std::make_unique( 683 | std::make_unique("z"), vAST::UnOp::INVERT); 684 | 685 | std::unique_ptr x1 = std::make_unique(*x); 686 | EXPECT_EQ(x->toString(), "~ z"); 687 | EXPECT_EQ(x1->toString(), "~ z"); 688 | x1->operand = std::make_unique("b"); 689 | x1->op = vAST::UnOp::MINUS; 690 | EXPECT_EQ(x->toString(), "~ z"); 691 | EXPECT_EQ(x1->toString(), "- b"); 692 | } 693 | 694 | TEST(BasicTests, TestTernaryOpCopy) { 695 | std::unique_ptr x = std::make_unique( 696 | std::make_unique("a"), 697 | std::make_unique("b"), 698 | std::make_unique("c")); 699 | 700 | std::unique_ptr x1 = std::make_unique(*x); 701 | EXPECT_EQ(x->toString(), "a ? b : c"); 702 | EXPECT_EQ(x1->toString(), "a ? b : c"); 703 | x1->cond = std::make_unique("x"); 704 | x1->true_value = std::make_unique("y"); 705 | x1->false_value = std::make_unique("z"); 706 | EXPECT_EQ(x->toString(), "a ? b : c"); 707 | EXPECT_EQ(x1->toString(), "x ? y : z"); 708 | } 709 | 710 | TEST(BasicTests, TestConcatCopy) { 711 | std::vector> args; 712 | args.push_back(vAST::make_id("x")); 713 | args.push_back(vAST::make_id("y")); 714 | args.push_back(vAST::make_id("z")); 715 | std::unique_ptr x = 716 | std::make_unique(std::move(args)); 717 | 718 | std::unique_ptr x1 = std::make_unique(*x); 719 | EXPECT_EQ(x->toString(), "{x,y,z}"); 720 | EXPECT_EQ(x1->toString(), "{x,y,z}"); 721 | x1->args[0] = vAST::make_id("a"); 722 | x1->args[1] = vAST::make_id("b"); 723 | x1->args[2] = vAST::make_id("c"); 724 | EXPECT_EQ(x->toString(), "{x,y,z}"); 725 | EXPECT_EQ(x1->toString(), "{a,b,c}"); 726 | } 727 | 728 | TEST(BasicTests, TestReplicateCopy) { 729 | std::unique_ptr x = 730 | std::make_unique(vAST::make_id("a"), vAST::make_id("b")); 731 | 732 | std::unique_ptr x1 = std::make_unique(*x); 733 | EXPECT_EQ(x->toString(), "{(a){b}}"); 734 | EXPECT_EQ(x1->toString(), "{(a){b}}"); 735 | x1->num = vAST::make_id("x"); 736 | x1->value = vAST::make_id("y"); 737 | EXPECT_EQ(x->toString(), "{(a){b}}"); 738 | EXPECT_EQ(x1->toString(), "{(x){y}}"); 739 | } 740 | 741 | TEST(BasicTests, TestCallExprCopy) { 742 | std::vector> args; 743 | args.push_back(vAST::make_id("x")); 744 | args.push_back(vAST::make_id("y")); 745 | std::unique_ptr x = 746 | std::make_unique("foo", std::move(args)); 747 | 748 | std::unique_ptr x1 = std::make_unique(*x); 749 | EXPECT_EQ(x->toString(), "foo(x, y)"); 750 | EXPECT_EQ(x1->toString(), "foo(x, y)"); 751 | x1->func = "bar"; 752 | x1->args[0] = vAST::make_id("a"); 753 | x1->args[1] = vAST::make_id("b"); 754 | EXPECT_EQ(x->toString(), "foo(x, y)"); 755 | EXPECT_EQ(x1->toString(), "bar(a, b)"); 756 | EXPECT_EQ(x1->toString(), x1->clone()->toString()); 757 | } 758 | 759 | TEST(BasicTests, TestIfDef) { 760 | std::string module_name = "test_module"; 761 | 762 | vAST::Parameters parameters = make_simple_params(); 763 | 764 | std::string instance_name = "test_module_inst"; 765 | 766 | std::unique_ptr module_inst = 767 | std::make_unique(module_name, 768 | std::move(parameters), 769 | instance_name, 770 | make_simple_connections()); 771 | std::vector, 772 | std::unique_ptr>> 773 | body; 774 | body.push_back(std::move(module_inst)); 775 | vAST::IfDef if_def("ASSERT_ON", std::move(body)); 776 | EXPECT_EQ(if_def.toString(), 777 | "`ifdef ASSERT_ON\n" 778 | "test_module #(\n" 779 | " .param0(0),\n" 780 | " .param1(1)\n" 781 | ") test_module_inst (\n" 782 | " .a(a),\n" 783 | " .b(b[0]),\n" 784 | " .c(c[31:0])\n" 785 | ");\n" 786 | "`endif"); 787 | } 788 | 789 | TEST(BasicTests, TestIfDefInvert) { 790 | std::string module_name = "test_module"; 791 | 792 | vAST::Parameters parameters = make_simple_params(); 793 | 794 | std::string instance_name = "test_module_inst"; 795 | 796 | std::unique_ptr module_inst = 797 | std::make_unique(module_name, 798 | std::move(parameters), 799 | instance_name, 800 | make_simple_connections()); 801 | std::vector, 802 | std::unique_ptr>> 803 | body; 804 | body.push_back(std::move(module_inst)); 805 | vAST::IfNDef if_def("ASSERT_ON", std::move(body)); 806 | EXPECT_EQ(if_def.toString(), 807 | "`ifndef ASSERT_ON\n" 808 | "test_module #(\n" 809 | " .param0(0),\n" 810 | " .param1(1)\n" 811 | ") test_module_inst (\n" 812 | " .a(a),\n" 813 | " .b(b[0]),\n" 814 | " .c(c[31:0])\n" 815 | ");\n" 816 | "`endif"); 817 | } 818 | 819 | TEST(BasicTests, TestIfDefElse) { 820 | std::string module_name = "test_module"; 821 | 822 | std::unique_ptr module_inst0 = 823 | std::make_unique(module_name, 824 | make_simple_params(), 825 | "test_module_inst0", 826 | make_simple_connections()); 827 | std::vector, 828 | std::unique_ptr>> 829 | true_body; 830 | true_body.push_back(std::move(module_inst0)); 831 | 832 | std::unique_ptr module_inst1 = 833 | std::make_unique(module_name, 834 | make_simple_params(), 835 | "test_module_inst1", 836 | make_simple_connections()); 837 | std::vector, 838 | std::unique_ptr>> 839 | else_body; 840 | else_body.push_back(std::move(module_inst1)); 841 | vAST::IfNDef if_def("ASSERT_ON", std::move(true_body), std::move(else_body)); 842 | EXPECT_EQ(if_def.toString(), 843 | "`ifndef ASSERT_ON\n" 844 | "test_module #(\n" 845 | " .param0(0),\n" 846 | " .param1(1)\n" 847 | ") test_module_inst0 (\n" 848 | " .a(a),\n" 849 | " .b(b[0]),\n" 850 | " .c(c[31:0])\n" 851 | ");\n" 852 | "`else\n" 853 | "test_module #(\n" 854 | " .param0(0),\n" 855 | " .param1(1)\n" 856 | ") test_module_inst1 (\n" 857 | " .a(a),\n" 858 | " .b(b[0]),\n" 859 | " .c(c[31:0])\n" 860 | ");\n" 861 | "`endif"); 862 | } 863 | 864 | } // namespace 865 | 866 | int main(int argc, char **argv) { 867 | ::testing::InitGoogleTest(&argc, argv); 868 | return RUN_ALL_TESTS(); 869 | } 870 | -------------------------------------------------------------------------------- /tests/common.cpp: -------------------------------------------------------------------------------- 1 | #include "verilogAST.hpp" 2 | 3 | namespace vAST = verilogAST; 4 | 5 | vAST::Parameters make_simple_params() { 6 | vAST::Parameters parameters; 7 | parameters.push_back( 8 | std::make_pair(vAST::make_id("param0"), vAST::make_num("0"))); 9 | parameters.push_back( 10 | std::make_pair(vAST::make_id("param1"), vAST::make_num("1"))); 11 | return parameters; 12 | } 13 | 14 | std::unique_ptr make_simple_connections() { 15 | std::unique_ptr connections = 16 | std::make_unique(); 17 | connections->insert("a", vAST::make_id("a")); 18 | connections->insert("b", std::make_unique(vAST::make_id("b"), 19 | vAST::make_num("0"))); 20 | connections->insert( 21 | "c", std::make_unique( 22 | vAST::make_id("c"), vAST::make_num("31"), vAST::make_num("0"))); 23 | 24 | return connections; 25 | } 26 | 27 | std::vector> make_simple_ports() { 28 | std::vector> ports; 29 | ports.push_back(std::make_unique(vAST::make_id("i"), vAST::INPUT, 30 | vAST::WIRE)); 31 | ports.push_back(std::make_unique(vAST::make_id("o"), vAST::OUTPUT, 32 | vAST::WIRE)); 33 | return ports; 34 | } 35 | 36 | std::vector, 37 | std::unique_ptr>> 38 | make_simple_body() { 39 | std::vector, 40 | std::unique_ptr>> 41 | body; 42 | 43 | std::string module_name = "other_module"; 44 | std::string instance_name = "other_module_inst"; 45 | 46 | body.push_back(std::make_unique( 47 | module_name, make_simple_params(), instance_name, 48 | make_simple_connections())); 49 | return body; 50 | } 51 | 52 | std::vector> 53 | make_simple_always_body() { 54 | std::vector> body; 55 | body.push_back(std::make_unique( 56 | std::make_unique("a"), 57 | std::make_unique("b"))); 58 | body.push_back(std::make_unique( 59 | std::make_unique("b"), 60 | std::make_unique("c"))); 61 | std::vector> args; 62 | args.push_back(std::make_unique("b=%d, c=%d")); 63 | args.push_back(std::make_unique("b")); 64 | args.push_back(std::make_unique("c")); 65 | body.push_back(std::make_unique("$display", std::move(args))); 66 | 67 | std::vector> true_body; 68 | true_body.push_back(std::make_unique( 69 | std::make_unique("e"), 70 | std::make_unique("f"))); 71 | 72 | std::vector< 73 | std::pair, 74 | std::vector>>> 75 | else_ifs; 76 | for (int i = 0; i < 2; i++) { 77 | std::unique_ptr cond = 78 | vAST::make_id("x" + std::to_string(i)); 79 | std::vector> body; 80 | body.push_back(std::make_unique( 81 | std::make_unique("e"), 82 | std::make_unique("g" + std::to_string(i)))); 83 | else_ifs.push_back({std::move(cond), std::move(body)}); 84 | } 85 | 86 | std::vector> else_body; 87 | else_body.push_back(std::make_unique( 88 | std::make_unique("e"), 89 | std::make_unique("g"))); 90 | 91 | body.push_back( 92 | std::make_unique(vAST::make_id("b"), std::move(true_body), 93 | std::move(else_ifs), std::move(else_body))); 94 | 95 | return body; 96 | } 97 | -------------------------------------------------------------------------------- /tests/concat_coalescer.cpp: -------------------------------------------------------------------------------- 1 | #include "verilogAST/concat_coalescer.hpp" 2 | #include "common.cpp" 3 | #include "gtest/gtest.h" 4 | #include 5 | 6 | namespace vAST = verilogAST; 7 | 8 | namespace { 9 | 10 | using BodyElement = std::variant, 11 | std::unique_ptr>; 12 | 13 | auto makeVector(std::string name, int hi, int lo) { 14 | return std::make_unique(vAST::make_id(name), 15 | vAST::make_num(std::to_string(hi)), 16 | vAST::make_num(std::to_string(lo))); 17 | } 18 | 19 | void runTest(std::array indices, std::string pre, std::string post) { 20 | std::vector> ports; 21 | ports.push_back(std::make_unique(makeVector("I", 7, 0), 22 | vAST::INPUT, 23 | vAST::WIRE)); 24 | ports.push_back(std::make_unique(makeVector("O", 7, 0), 25 | vAST::OUTPUT, 26 | vAST::WIRE)); 27 | std::vector body; 28 | 29 | std::vector> args = {}; 30 | for (int i = 7; i >= 0; i--) { 31 | args.emplace_back( 32 | new vAST::Index( 33 | vAST::make_id("I"), 34 | vAST::make_num(std::to_string(indices[i])))); 35 | } 36 | std::unique_ptr rhs(new vAST::Concat(std::move(args))); 37 | 38 | body.push_back(std::make_unique( 39 | std::make_unique("O"), std::move(rhs))); 40 | 41 | std::unique_ptr module = std::make_unique( 42 | "test_module", 43 | std::move(ports), 44 | std::move(body)); 45 | 46 | EXPECT_EQ(module->toString(), pre); 47 | 48 | // Run ConcatCoalescer transformer. 49 | vAST::ConcatCoalescer transformer; 50 | module = transformer.visit(std::move(module)); 51 | 52 | EXPECT_EQ(module->toString(), post); 53 | } 54 | 55 | TEST(ConcatCoalescerTests, TestBasic) { 56 | auto pre = 57 | "module test_module (\n" 58 | " input [7:0] I,\n" 59 | " output [7:0] O\n" 60 | ");\n" 61 | "assign O = {I[7],I[6],I[5],I[4],I[3],I[2],I[1],I[0]};\n" 62 | "endmodule\n"; 63 | auto post = 64 | "module test_module (\n" 65 | " input [7:0] I,\n" 66 | " output [7:0] O\n" 67 | ");\n" 68 | "assign O = I[7:0];\n" 69 | "endmodule\n"; 70 | runTest({0, 1, 2, 3, 4, 5, 6, 7}, pre, post); 71 | } 72 | 73 | TEST(ConcatCoalescerTests, TestMultipleRuns) { 74 | auto pre = 75 | "module test_module (\n" 76 | " input [7:0] I,\n" 77 | " output [7:0] O\n" 78 | ");\n" 79 | "assign O = {I[7],I[6],I[5],I[2],I[1],I[0],I[4],I[3]};\n" 80 | "endmodule\n"; 81 | auto post = 82 | "module test_module (\n" 83 | " input [7:0] I,\n" 84 | " output [7:0] O\n" 85 | ");\n" 86 | "assign O = {I[7:5],I[2:0],I[4:3]};\n" 87 | "endmodule\n"; 88 | runTest({3, 4, 0, 1, 2, 5, 6, 7}, pre, post); 89 | } 90 | 91 | TEST(ConcatCoalescerTests, TestNoRuns) { 92 | auto pre = 93 | "module test_module (\n" 94 | " input [7:0] I,\n" 95 | " output [7:0] O\n" 96 | ");\n" 97 | "assign O = {I[7],I[5],I[3],I[1],I[6],I[4],I[2],I[0]};\n" 98 | "endmodule\n"; 99 | auto post = 100 | "module test_module (\n" 101 | " input [7:0] I,\n" 102 | " output [7:0] O\n" 103 | ");\n" 104 | "assign O = {I[7],I[5],I[3],I[1],I[6],I[4],I[2],I[0]};\n" 105 | "endmodule\n"; 106 | // Sequence has no contiguous runs. 107 | runTest({0, 2, 4, 6, 1, 3, 5, 7}, pre, post); 108 | } 109 | 110 | TEST(ConcatCoalescerTests, ReverseRun) { 111 | auto pre = 112 | "module test_module (\n" 113 | " input [7:0] I,\n" 114 | " output [7:0] O\n" 115 | ");\n" 116 | "assign O = {I[4],I[5],I[6],I[7],I[3],I[2],I[1],I[0]};\n" 117 | "endmodule\n"; 118 | // ConcatCoalescer doesn't coalese reverse runs right now. 119 | auto post = 120 | "module test_module (\n" 121 | " input [7:0] I,\n" 122 | " output [7:0] O\n" 123 | ");\n" 124 | "assign O = {I[4],I[5],I[6],I[7],I[3:0]};\n" 125 | "endmodule\n"; 126 | runTest({0, 1, 2, 3, 7, 6, 5, 4}, pre, post); 127 | } 128 | 129 | TEST(ConcatCoalescerTests, MultipleNames) { 130 | auto pre = 131 | "module test_module (\n" 132 | " input [7:0] I0,\n" 133 | " input [7:0] I1,\n" 134 | " output [7:0] O\n" 135 | ");\n" 136 | "assign O = {I0[7],I0[6],I0[5],I0[4],I1[3],I1[2],I1[1],I1[0]};\n" 137 | "endmodule\n"; 138 | auto post = 139 | "module test_module (\n" 140 | " input [7:0] I0,\n" 141 | " input [7:0] I1,\n" 142 | " output [7:0] O\n" 143 | ");\n" 144 | "assign O = {I0[7:4],I1[3:0]};\n" 145 | "endmodule\n"; 146 | std::vector> ports; 147 | ports.push_back(std::make_unique(makeVector("I0", 7, 0), 148 | vAST::INPUT, 149 | vAST::WIRE)); 150 | ports.push_back(std::make_unique(makeVector("I1", 7, 0), 151 | vAST::INPUT, 152 | vAST::WIRE)); 153 | ports.push_back(std::make_unique(makeVector("O", 7, 0), 154 | vAST::OUTPUT, 155 | vAST::WIRE)); 156 | std::vector body; 157 | 158 | std::vector> args = {}; 159 | for (int i = 7; i >= 0; i--) { 160 | auto id = i > 3 ? "I0" : "I1"; 161 | args.emplace_back( 162 | new vAST::Index( 163 | vAST::make_id(id), 164 | vAST::make_num(std::to_string(i)))); 165 | } 166 | std::unique_ptr rhs(new vAST::Concat(std::move(args))); 167 | 168 | body.push_back(std::make_unique( 169 | std::make_unique("O"), std::move(rhs))); 170 | 171 | std::unique_ptr module = std::make_unique( 172 | "test_module", 173 | std::move(ports), 174 | std::move(body)); 175 | 176 | EXPECT_EQ(module->toString(), pre); 177 | 178 | // Run ConcatCoalescer transformer. 179 | vAST::ConcatCoalescer transformer; 180 | module = transformer.visit(std::move(module)); 181 | 182 | EXPECT_EQ(module->toString(), post); 183 | } 184 | 185 | } // namespace 186 | 187 | int main(int argc, char **argv) { 188 | ::testing::InitGoogleTest(&argc, argv); 189 | return RUN_ALL_TESTS(); 190 | } 191 | -------------------------------------------------------------------------------- /tests/make_packed.cpp: -------------------------------------------------------------------------------- 1 | #include "verilogAST/make_packed.hpp" 2 | #include "common.cpp" 3 | #include "gtest/gtest.h" 4 | 5 | namespace vAST = verilogAST; 6 | 7 | namespace { 8 | 9 | using BodyElement = std::variant, 10 | std::unique_ptr>; 11 | using Dim = std::pair, 12 | std::unique_ptr>; 13 | 14 | 15 | Dim makeDim(std::unique_ptr hi, 16 | std::unique_ptr lo) { 17 | return std::make_pair(std::move(hi), std::move(lo)); 18 | } 19 | 20 | TEST(MakePackedTests, TestBasic) { 21 | std::vector> ports; 22 | 23 | auto make_dims = []() { 24 | std::vector dims; 25 | dims.push_back(makeDim(vAST::make_num("7"), vAST::make_num("0"))); 26 | dims.push_back(makeDim(vAST::make_num("15"), vAST::make_num("0"))); 27 | return dims; 28 | }; 29 | ports.push_back( 30 | std::make_unique( 31 | std::make_unique( 32 | vAST::make_id("I"), 33 | vAST::make_num("31"), 34 | vAST::make_num("0"), 35 | make_dims()), 36 | vAST::INPUT, 37 | vAST::WIRE)); 38 | 39 | std::vector body; 40 | 41 | std::unique_ptr module = std::make_unique( 42 | "test_module", 43 | std::move(ports), 44 | std::move(body)); 45 | 46 | auto pre = 47 | "module test_module (\n" 48 | " input [31:0] I [7:0][15:0]\n" 49 | ");\n" 50 | "endmodule\n"; 51 | EXPECT_EQ(module->toString(), pre); 52 | 53 | // Run MakePacked transformer. 54 | vAST::MakePacked transformer {}; 55 | module = transformer.visit(std::move(module)); 56 | 57 | auto post = 58 | "module test_module (\n" 59 | " input [7:0][15:0][31:0] I\n" 60 | ");\n" 61 | "endmodule\n"; 62 | EXPECT_EQ(module->toString(), post); 63 | } 64 | 65 | } // namespace 66 | 67 | int main(int argc, char **argv) { 68 | ::testing::InitGoogleTest(&argc, argv); 69 | return RUN_ALL_TESTS(); 70 | } 71 | -------------------------------------------------------------------------------- /tests/parameterized_module.cpp: -------------------------------------------------------------------------------- 1 | #include "common.cpp" 2 | #include "gtest/gtest.h" 3 | #include "verilogAST.hpp" 4 | 5 | using namespace std; 6 | 7 | namespace vAST = verilogAST; 8 | 9 | /* 10 | module coreir_eq #(parameter width=1) ( 11 | input [width-1:0] in0, 12 | input [width-1:0] in1, 13 | output [width-1:0] out 14 | ); 15 | assign out = in0 & in1; 16 | 17 | endmodule // coreir_eq 18 | */ 19 | 20 | namespace { 21 | 22 | TEST(ParameterizedModuleTests, TestEq) { 23 | std::string name = "coreir_eq"; 24 | 25 | std::vector> ports; 26 | ports.push_back(vAST::make_port( 27 | vAST::make_vector(vAST::make_id("in0"), 28 | vAST::make_binop(vAST::make_id("width"), 29 | vAST::BinOp::SUB, vAST::make_num("1")), 30 | vAST::make_num("0")), 31 | vAST::INPUT, vAST::WIRE)); 32 | ports.push_back(vAST::make_port( 33 | vAST::make_vector(vAST::make_id("in1"), 34 | vAST::make_binop(vAST::make_id("width"), 35 | vAST::BinOp::SUB, vAST::make_num("1")), 36 | vAST::make_num("0")), 37 | vAST::INPUT, vAST::WIRE)); 38 | ports.push_back( 39 | vAST::make_port(vAST::make_id("out"), vAST::OUTPUT, vAST::WIRE)); 40 | 41 | std::vector, 42 | std::unique_ptr>> 43 | body; 44 | 45 | std::unique_ptr eq_assign = 46 | std::make_unique( 47 | vAST::make_id("out"), 48 | vAST::make_binop(vAST::make_id("in0"), vAST::BinOp::EQ, 49 | vAST::make_id("in1"))); 50 | 51 | body.push_back(std::move(eq_assign)); 52 | 53 | vAST::Parameters parameters; 54 | parameters.push_back( 55 | std::make_pair(vAST::make_id("width"), vAST::make_num("1"))); 56 | std::unique_ptr coreir_eq = std::make_unique( 57 | name, std::move(ports), std::move(body), std::move(parameters)); 58 | 59 | cout << "//coreir_eq" << endl << coreir_eq->toString() << endl; 60 | std::string expected_str = 61 | "module coreir_eq #(\n" 62 | " parameter width = 1\n" 63 | ") (\n" 64 | " input [width - 1:0] in0,\n" 65 | " input [width - 1:0] in1,\n" 66 | " output out\n" 67 | ");\n" 68 | "assign out = in0 == in1;\n" 69 | "endmodule\n"; 70 | EXPECT_EQ(coreir_eq->toString(), expected_str); 71 | } 72 | 73 | } // namespace 74 | 75 | int main(int argc, char **argv) { 76 | ::testing::InitGoogleTest(&argc, argv); 77 | return RUN_ALL_TESTS(); 78 | } 79 | -------------------------------------------------------------------------------- /tests/transformer.cpp: -------------------------------------------------------------------------------- 1 | #include "verilogAST/transformer.hpp" 2 | #include "common.cpp" 3 | #include "gtest/gtest.h" 4 | 5 | namespace vAST = verilogAST; 6 | 7 | class XtoZ : public vAST::Transformer { 8 | public: 9 | using vAST::Transformer::visit; 10 | virtual std::unique_ptr visit( 11 | std::unique_ptr node) { 12 | if (node->value == "x") { 13 | return vAST::make_id("z"); 14 | } 15 | return node; 16 | }; 17 | }; 18 | 19 | class ReplaceNameWithExpr : public vAST::Transformer { 20 | public: 21 | using vAST::Transformer::visit; 22 | virtual std::unique_ptr visit( 23 | std::unique_ptr node) { 24 | if (auto ptr = dynamic_cast(node.get())) { 25 | node.release(); 26 | std::unique_ptr id(ptr); 27 | if (id->value == "x") { 28 | return vAST::make_binop(vAST::make_id("z"), vAST::BinOp::SUB, 29 | vAST::make_id("w")); 30 | } 31 | return vAST::Transformer::visit(std::move(id)); 32 | } 33 | return vAST::Transformer::visit(std::move(node)); 34 | }; 35 | }; 36 | 37 | class AlwaysTransformer : public vAST::Transformer { 38 | public: 39 | using vAST::Transformer::visit; 40 | virtual std::unique_ptr visit( 41 | std::unique_ptr node) { 42 | if (node->value == "a") { 43 | return vAST::make_id("z"); 44 | } else if (node->value == "b") { 45 | return vAST::make_id("y"); 46 | } else if (node->value == "e") { 47 | return vAST::make_id("w"); 48 | } 49 | return node; 50 | }; 51 | }; 52 | 53 | class ModuleTransformer : public vAST::Transformer { 54 | public: 55 | using vAST::Transformer::visit; 56 | virtual std::unique_ptr visit( 57 | std::unique_ptr node) { 58 | if (node->value == "c") { 59 | return vAST::make_id("g"); 60 | } else if (node->value == "param0") { 61 | return vAST::make_id("y"); 62 | } 63 | return node; 64 | }; 65 | }; 66 | 67 | class FileTransformer : public vAST::Transformer { 68 | public: 69 | using vAST::Transformer::visit; 70 | virtual std::unique_ptr visit( 71 | std::unique_ptr node) { 72 | if (node->value == "o") { 73 | return vAST::make_id("d"); 74 | } else if (node->value == "param0") { 75 | return vAST::make_id("y"); 76 | } 77 | return node; 78 | }; 79 | }; 80 | 81 | namespace { 82 | TEST(TransformerTests, TestXtoZ) { 83 | std::vector> concat_args; 84 | concat_args.push_back(vAST::make_id("x")); 85 | concat_args.push_back(vAST::make_id("b")); 86 | std::vector> call_args; 87 | call_args.push_back(std::make_unique( 88 | std::make_unique(std::move(concat_args)), 89 | vAST::make_binop( 90 | std::make_unique( 91 | std::make_unique(vAST::make_id("x"), "j"), 92 | vAST::make_num("3"), vAST::make_num("1")), 93 | vAST::BinOp::ADD, 94 | std::make_unique( 95 | std::make_unique(vAST::make_id("y"), 96 | vAST::make_num("1")), 97 | vAST::UnOp::INVERT)), 98 | std::make_unique(vAST::make_num("2"), 99 | vAST::make_id("x")))); 100 | call_args.push_back(std::make_unique(5, vAST::make_id("x"))); 101 | std::unique_ptr expr = 102 | std::make_unique("my_func", std::move(call_args)); 103 | XtoZ transformer; 104 | EXPECT_EQ(transformer.visit(std::move(expr))->toString(), 105 | "my_func({z,b} ? z.j[3:1] + (~ y[1]) : {(2){z}}, 5'(z))"); 106 | } 107 | TEST(TransformerTests, TestReplaceNameWithExpr) { 108 | std::unique_ptr expr = vAST::make_binop( 109 | vAST::make_id("x"), vAST::BinOp::MUL, vAST::make_id("y")); 110 | ReplaceNameWithExpr transformer; 111 | EXPECT_EQ(transformer.visit(std::move(expr))->toString(), "(z - w) * y"); 112 | } 113 | TEST(TransformerTests, TestAlways) { 114 | std::vector, std::unique_ptr, 116 | std::unique_ptr, std::unique_ptr>> 117 | sensitivity_list; 118 | sensitivity_list.push_back(std::make_unique("a")); 119 | sensitivity_list.push_back( 120 | std::make_unique(std::make_unique("b"))); 121 | sensitivity_list.push_back( 122 | std::make_unique(std::make_unique("c"))); 123 | sensitivity_list.push_back(std::make_unique()); 124 | 125 | std::vector> always_body = 126 | make_simple_always_body(); 127 | always_body.push_back( 128 | std::make_unique("Test comment")); 129 | always_body.push_back( 130 | std::make_unique("Test comment\non multiple lines")); 131 | 132 | std::unique_ptr always = std::make_unique( 133 | std::move(sensitivity_list), std::move(always_body)); 134 | std::string expected_str = 135 | "always @(z, posedge y, negedge c, *) begin\n" 136 | "z = y;\n" 137 | "y <= c;\n" 138 | "$display(\"b=%d, c=%d\", y, c);\n" 139 | "if (y) begin\n" 140 | " w = f;\n" 141 | "end else if (x0) begin\n" 142 | " w = g0;\n" 143 | "end else if (x1) begin\n" 144 | " w = g1;\n" 145 | "end else begin\n" 146 | " w = g;\n" 147 | "end\n" 148 | "// Test comment\n" 149 | "/*\nTest comment\non multiple lines\n*/\n" 150 | "end\n"; 151 | AlwaysTransformer transformer; 152 | EXPECT_EQ(transformer.visit(std::move(always))->toString(), expected_str); 153 | } 154 | TEST(TransformerTests, TestModule) { 155 | std::vector> ports; 156 | ports.push_back(std::make_unique(vAST::make_id("i"), vAST::INPUT, 157 | vAST::WIRE)); 158 | std::vector, 159 | std::unique_ptr>> 160 | outer_dims; 161 | outer_dims.push_back({vAST::make_num("7"), vAST::make_num("0")}); 162 | outer_dims.push_back({vAST::make_id("c"), vAST::make_num("0")}); 163 | ports.push_back(std::make_unique( 164 | std::make_unique(vAST::make_id("o"), vAST::make_num("3"), 165 | vAST::make_id("c"), 166 | std::move(outer_dims)), 167 | vAST::OUTPUT, vAST::WIRE)); 168 | 169 | ports.push_back( 170 | std::make_unique("output reg [width-1:0] k")); 171 | 172 | std::vector, 173 | std::unique_ptr>> 174 | body = make_simple_body(); 175 | 176 | body.push_back(std::make_unique( 177 | std::make_unique("c"), 178 | std::make_unique("b"))); 179 | 180 | body.push_back( 181 | std::make_unique(std::make_unique("c"))); 182 | 183 | body.push_back( 184 | std::make_unique(std::make_unique("c"))); 185 | 186 | std::vector, std::unique_ptr, 188 | std::unique_ptr, std::unique_ptr>> 189 | sensitivity_list; 190 | sensitivity_list.push_back(std::make_unique("a")); 191 | 192 | body.push_back(std::make_unique(std::move(sensitivity_list), 193 | make_simple_always_body())); 194 | 195 | body.push_back(std::make_unique("Test comment")); 196 | body.push_back( 197 | std::make_unique("Test comment\non multiple lines")); 198 | 199 | body.push_back( 200 | std::make_unique("// Test inline verilog")); 201 | 202 | std::unique_ptr module = std::make_unique( 203 | "test_module0", std::move(ports), std::move(body), make_simple_params()); 204 | std::string expected_str = 205 | "module test_module0 #(\n" 206 | " parameter y = 0,\n" 207 | " parameter param1 = 1\n" 208 | ") (\n" 209 | " input i,\n" 210 | " output [3:g] o [7:0][g:0],\n" 211 | " output reg [width-1:0] k\n" 212 | ");\n" 213 | "other_module #(\n" 214 | " .y(0),\n" 215 | " .param1(1)\n" 216 | ") other_module_inst (\n" 217 | " .a(a),\n" 218 | " .b(b[0]),\n" 219 | " .c(g[31:0])\n" 220 | ");\n" 221 | "assign g = b;\n" 222 | "wire g;\n" 223 | "reg g;\n" 224 | "always @(a) begin\n" 225 | "a = b;\n" 226 | "b <= g;\n" 227 | "$display(\"b=%d, c=%d\", b, g);\n" 228 | "if (b) begin\n" 229 | " e = f;\n" 230 | "end else if (x0) begin\n" 231 | " e = g0;\n" 232 | "end else if (x1) begin\n" 233 | " e = g1;\n" 234 | "end else begin\n" 235 | " e = g;\n" 236 | "end\n" 237 | "end\n\n" 238 | "// Test comment\n" 239 | "/*\nTest comment\non multiple lines\n*/\n" 240 | "// Test inline verilog\n" 241 | "endmodule\n"; 242 | 243 | ModuleTransformer transformer; 244 | EXPECT_EQ(transformer.visit(std::move(module))->toString(), expected_str); 245 | } 246 | TEST(TransformerTests, File) { 247 | std::vector> modules; 248 | vAST::Parameters parameters0; 249 | std::string name = "test_module"; 250 | 251 | std::string module_name = "other_module"; 252 | 253 | std::string string_body = "reg d;\nassign d = a + b;\nassign c = d;"; 254 | modules.push_back(std::make_unique( 255 | name, make_simple_ports(), string_body, make_simple_params())); 256 | 257 | std::string module_str = 258 | "module string_module #(\n" 259 | " parameter param0 = 0,\n" 260 | " parameter param1 = 1\n" 261 | ") (\n" 262 | " input i,\n" 263 | " output o\n" 264 | ");\n" 265 | "reg d;\n" 266 | "assign d = a + b;\n" 267 | "assign c = d;\n" 268 | "endmodule\n"; 269 | modules.push_back(std::make_unique(module_str)); 270 | 271 | std::unique_ptr file = std::make_unique(modules); 272 | 273 | std::string expected_str = 274 | "module test_module #(\n" 275 | " parameter y = 0,\n" 276 | " parameter param1 = 1\n" 277 | ") (\n" 278 | " input i,\n" 279 | " output d\n" 280 | ");\n" 281 | "reg d;\n" 282 | "assign d = a + b;\n" 283 | "assign c = d;\n" 284 | "endmodule\n\n" 285 | "module string_module #(\n" 286 | " parameter param0 = 0,\n" 287 | " parameter param1 = 1\n" 288 | ") (\n" 289 | " input i,\n" 290 | " output o\n" 291 | ");\n" 292 | "reg d;\n" 293 | "assign d = a + b;\n" 294 | "assign c = d;\n" 295 | "endmodule\n"; 296 | FileTransformer transformer; 297 | EXPECT_EQ(transformer.visit(std::move(file))->toString(), expected_str); 298 | } 299 | } // namespace 300 | 301 | int main(int argc, char **argv) { 302 | ::testing::InitGoogleTest(&argc, argv); 303 | return RUN_ALL_TESTS(); 304 | } 305 | -------------------------------------------------------------------------------- /tests/zext_coalescer.cpp: -------------------------------------------------------------------------------- 1 | #include "verilogAST/zext_coalescer.hpp" 2 | #include "common.cpp" 3 | #include "gtest/gtest.h" 4 | 5 | namespace vAST = verilogAST; 6 | 7 | namespace { 8 | 9 | using BodyElement = std::variant, 10 | std::unique_ptr>; 11 | 12 | auto makeVector(std::string name, int hi, int lo) { 13 | return std::make_unique(vAST::make_id(name), 14 | vAST::make_num(std::to_string(hi)), 15 | vAST::make_num(std::to_string(lo))); 16 | } 17 | 18 | void runTest(std::vector prefix, 19 | std::string pre, 20 | std::string post, 21 | bool elide = false) { 22 | std::vector> ports; 23 | ports.push_back(std::make_unique(makeVector("I", 7, 0), 24 | vAST::INPUT, 25 | vAST::WIRE)); 26 | ports.push_back(std::make_unique(makeVector("O", 7, 0), 27 | vAST::OUTPUT, 28 | vAST::WIRE)); 29 | std::vector body; 30 | 31 | std::vector> args = {}; 32 | int remaining_size = 8; 33 | for (const auto& it : prefix) { 34 | args.emplace_back(new vAST::NumericLiteral("0", it)); 35 | remaining_size -= it; 36 | } 37 | args.emplace_back( 38 | new vAST::Slice( 39 | vAST::make_id("I"), 40 | vAST::make_num(std::to_string(remaining_size - 1)), 41 | vAST::make_num("0"))); 42 | std::unique_ptr rhs(new vAST::Concat(std::move(args))); 43 | 44 | body.push_back(std::make_unique( 45 | std::make_unique("O"), std::move(rhs))); 46 | 47 | std::unique_ptr module = std::make_unique( 48 | "test_module", 49 | std::move(ports), 50 | std::move(body)); 51 | 52 | EXPECT_EQ(module->toString(), pre); 53 | 54 | // Run ZextCoalescer transformer. 55 | vAST::ZextCoalescer transformer(elide); 56 | module = transformer.visit(std::move(module)); 57 | 58 | EXPECT_EQ(module->toString(), post); 59 | } 60 | 61 | TEST(ZextCoalescerTests, TestBasic) { 62 | auto pre = 63 | "module test_module (\n" 64 | " input [7:0] I,\n" 65 | " output [7:0] O\n" 66 | ");\n" 67 | "assign O = {1'd0,2'd0,I[4:0]};\n" 68 | "endmodule\n"; 69 | auto post = 70 | "module test_module (\n" 71 | " input [7:0] I,\n" 72 | " output [7:0] O\n" 73 | ");\n" 74 | "assign O = {3'd0,I[4:0]};\n" 75 | "endmodule\n"; 76 | runTest({1, 2}, pre, post); 77 | } 78 | 79 | TEST(ZextCoalescerTests, TestElide) { 80 | auto pre = 81 | "module test_module (\n" 82 | " input [7:0] I,\n" 83 | " output [7:0] O\n" 84 | ");\n" 85 | "assign O = {1'd0,2'd0,I[4:0]};\n" 86 | "endmodule\n"; 87 | auto post = 88 | "module test_module (\n" 89 | " input [7:0] I,\n" 90 | " output [7:0] O\n" 91 | ");\n" 92 | "assign O = {I[4:0]};\n" 93 | "endmodule\n"; 94 | runTest({1, 2}, pre, post, true /* elide */); 95 | } 96 | 97 | TEST(ZextCoalescerTests, TestNoop) { 98 | auto pre = 99 | "module test_module (\n" 100 | " input [7:0] I,\n" 101 | " output [7:0] O\n" 102 | ");\n" 103 | "assign O = {I[7:0]};\n" 104 | "endmodule\n"; 105 | auto post = 106 | "module test_module (\n" 107 | " input [7:0] I,\n" 108 | " output [7:0] O\n" 109 | ");\n" 110 | "assign O = {I[7:0]};\n" 111 | "endmodule\n"; 112 | runTest({}, pre, post); 113 | } 114 | 115 | } // namespace 116 | 117 | int main(int argc, char **argv) { 118 | ::testing::InitGoogleTest(&argc, argv); 119 | return RUN_ALL_TESTS(); 120 | } 121 | --------------------------------------------------------------------------------