├── figures └── ll-verilog_uml_diagram.png ├── Makefile ├── filter.c ├── codegen ├── filter.c ├── Makefile ├── CodeBlock.cc ├── Argument.cc ├── DataFlow.h ├── CodeBlock.h ├── Module.h ├── Module.cc ├── DataFlow.cc ├── Argument.h └── verilog.cc ├── simpleHLS.bash ├── parser ├── Makefile ├── Type.cc ├── Type.h ├── SymbolTable.cc ├── SymbolTable.h ├── scanner.l ├── parser.h └── parser.y ├── LICENSE └── README.md /figures/ll-verilog_uml_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sabbaghm/c-ll-verilog/HEAD/figures/ll-verilog_uml_diagram.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make -C parser all 3 | make -C codegen all 4 | clean: 5 | make -C parser clean 6 | make -C codegen clean 7 | -------------------------------------------------------------------------------- /filter.c: -------------------------------------------------------------------------------- 1 | bool adder(int in1, int in2, int threshold, int mask) 2 | { 3 | 4 | return ( ( ( (in1+in2) & mask ) >> 2 ) > threshold ); 5 | } 6 | -------------------------------------------------------------------------------- /codegen/filter.c: -------------------------------------------------------------------------------- 1 | bool adder(int in1, int in2, int threshold, int mask) 2 | { 3 | 4 | return ( ( ( (in1+in2) & mask ) >> 2 ) > threshold ); 5 | } 6 | -------------------------------------------------------------------------------- /codegen/Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | INCLUDE = . 3 | CFLAGS = -I$(INCLUDE) -fPIC -shared `llvm-config --cppflags` -std=c++11 4 | 5 | ALLSRCS = *.cc 6 | 7 | TARGETALL = verilog.so 8 | 9 | all: $(TARGETALL) 10 | $(TARGETALL): $(ALLSRCS) 11 | $(CC) $(CFLAGS) $(INCLUDES) $(ALLSRCS) -o $(TARGETALL) 12 | 13 | clean: 14 | $(RM) $(TARGETBISON) $(TARGETFLEX) $(TARGETALL) 15 | -------------------------------------------------------------------------------- /simpleHLS.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 3 | ## date Dec, 2016 4 | ## @brief The c-ll-verilog tool script, usage: simpleHLS.bash 5 | ## 6 | cfile=$1 7 | file="${cfile%.*}" 8 | ./parser/parser "$file".c 2>&1 | opt -mem2reg | llvm-dis &> "$file".ll 9 | cat "$file".ll | opt -load ./codegen/verilog.so -verilog -o "$file".v &> "$file".v -------------------------------------------------------------------------------- /codegen/CodeBlock.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @file CodeBlock.cc 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief This files dumps the code block name and its contents in a proper manner. 7 | */ 8 | 9 | #include "CodeBlock.h" 10 | #include "DataFlow.h" 11 | 12 | namespace verilog 13 | { 14 | 15 | void CodeBlock::dump() 16 | { 17 | std::cout << "//" << name << ":\n"; 18 | for (DataFlow *dataflow : dataflows) 19 | { 20 | std::cout << "\t"; 21 | dataflow->dump(); 22 | } 23 | } 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /parser/Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | BISON = bison 3 | FLEX = flex 4 | INCLUDE = . 5 | CFLAGS = -I$(INCLUDE) -Wall -lLLVM-3.4 `llvm-config --cppflags` `llvm-config --ldflags` -std=c++11 6 | BISONFLAGS = -d -v --report-file=bisonreport.output 7 | BISONSRCS = parser.y 8 | FLEXSRCS = scanner.l 9 | ALLSRCS = parser.c scanner.c SymbolTable.cc Type.cc 10 | 11 | TARGETBISON = parser.c 12 | TARGETFLEX = scanner.c 13 | TARGETALL = parser 14 | 15 | bison: $(TARGETBISON) 16 | $(TARGETBISON): $(BISONSRCS) 17 | $(BISON) -o $(TARGETBISON) $(BISONSRCS) $(BISONFLAGS) 18 | 19 | flex: $(TARGETFLEX) 20 | $(TARGETFLEX): $(FLEXSRCS) 21 | $(FLEX) -o $(TARGETFLEX) $(FLEXSRCS) 22 | 23 | all: $(TARGETALL) 24 | $(TARGETALL): $(ALLSRCS) 25 | $(CC) $(CFLAGS) $(INCLUDES) $(ALLSRCS) -o $(TARGETALL) 26 | 27 | clean: 28 | $(RM) $(TARGETBISON) $(TARGETFLEX) $(TARGETALL) *.output 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 sabbaghm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /codegen/Argument.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Argument.cc 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief This files defines the methods for the verilog statement arguments class. 7 | */ 8 | 9 | #include 10 | 11 | #include "Argument.h" 12 | #include "CodeBlock.h" 13 | 14 | 15 | namespace verilog 16 | { 17 | 18 | int Wire::next_number = 0; 19 | int Register::next_number = 0; 20 | 21 | void Wire::dump() 22 | { 23 | std::cout << name; 24 | } 25 | 26 | void Register::dump() 27 | { 28 | std::cout << name; 29 | } 30 | 31 | 32 | void Constant::dump() 33 | { 34 | std::cout << value; 35 | } 36 | 37 | int Wire::getWidth() 38 | { 39 | return width; 40 | } 41 | 42 | int Register::getWidth() 43 | { 44 | return width; 45 | } 46 | 47 | 48 | int Constant::getWidth() 49 | { 50 | return width; 51 | } 52 | 53 | 54 | void Wire::setWidth(int val) 55 | { 56 | width = val; 57 | } 58 | 59 | void Register::setWidth(int val) 60 | { 61 | width = val; 62 | } 63 | 64 | void Constant::setWidth(int val) 65 | { 66 | width = val; 67 | } 68 | 69 | } 70 | 71 | -------------------------------------------------------------------------------- /parser/Type.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Type.cc 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief The Type class defines various LLVM types. 7 | */ 8 | 9 | #include 10 | 11 | #include "Type.h" 12 | #include "SymbolTable.h" 13 | 14 | void Type::dump(int indent) 15 | { 16 | // Indent 17 | std::cout << std::string(indent, ' '); 18 | 19 | // Kind 20 | std::cout << "Type: kind="; 21 | switch (kind) 22 | { 23 | case KindConstInt: std::cout << "ConstInt"; break; 24 | case KindConstFloat: std::cout << "ConstFloat"; break; 25 | case KindBool: std::cout << "Bool"; break; 26 | case KindShort: std::cout << "Short"; break; 27 | case KindInt: std::cout << "Int"; break; 28 | case KindFloat: std::cout << "Float"; break; 29 | case KindVoid: std::cout << "Void"; break; 30 | case KindArray: std::cout << "Array"; break; 31 | case KindStruct: std::cout << "Struct"; break; 32 | case KindPointer: std::cout << "Pointer"; break; 33 | case KindFunction: std::cout << "Function"; break; 34 | } 35 | 36 | // Number of elements for arrays 37 | if (kind == KindArray) 38 | std::cout << ", num_elem=" << num_elem; 39 | 40 | // Newline 41 | std::cout << '\n'; 42 | 43 | // Subtypes 44 | if (subtype) 45 | subtype->dump(indent + 2); 46 | 47 | // Symbol table 48 | if (symbol_table) 49 | symbol_table->dump(indent + 2); 50 | } 51 | -------------------------------------------------------------------------------- /codegen/DataFlow.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file DataFlow.h 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief Dataflow class contains acceptable verilog statements. 7 | */ 8 | 9 | #ifndef VERILOG_INSTRUCTION_H 10 | #define VERILOG_INSTRUCTION_H 11 | 12 | #include 13 | #include 14 | 15 | #include "Argument.h" 16 | 17 | 18 | namespace verilog 19 | { 20 | 21 | class DataFlow 22 | { 23 | public: 24 | 25 | // Instruction kinds 26 | enum Opcode 27 | { 28 | OpcodeInvalid = 0, 29 | 30 | OpcodePortListStart, 31 | OpcodeInputPortDefine, 32 | OpcodeOutputPortDefine, 33 | OpcodePortListEnd, 34 | OpcodeSignalDefine, 35 | OpcodeAssign, 36 | OpcodeAdd, 37 | OpcodeSub, 38 | OpcodeLshr, 39 | OpcodeXor, 40 | OpcodeAnd, 41 | OpcodeOr, 42 | OpcodeEq, 43 | OpcodeSgt, 44 | OpcodeEndModule, 45 | 46 | OpcodeMax 47 | }; 48 | 49 | private: 50 | 51 | // Instruction names 52 | static std::string names[OpcodeMax]; 53 | 54 | // Opcode 55 | Opcode opcode; 56 | 57 | // List of arguments 58 | std::list arguments; 59 | 60 | public: 61 | 62 | // Constructor 63 | DataFlow(Opcode opcode) : opcode(opcode) 64 | { 65 | } 66 | 67 | // Add an argument 68 | void addArgument(Argument *argument) 69 | { 70 | arguments.push_back(argument); 71 | } 72 | 73 | 74 | // Print dataflow 75 | void dump(); 76 | }; 77 | 78 | 79 | } 80 | 81 | #endif 82 | 83 | -------------------------------------------------------------------------------- /parser/Type.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Type.h 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief The Type class denotes various LLVM types. 7 | */ 8 | 9 | 10 | #ifndef TYPE_H 11 | #define TYPE_H 12 | 13 | #include 14 | #include 15 | 16 | // Forward declarations 17 | class SymbolTable; 18 | class Symbol; 19 | 20 | 21 | class Type 22 | { 23 | public: 24 | 25 | // List of possible type kinds 26 | enum Kind 27 | { 28 | KindInvalid, 29 | KindConstInt, 30 | KindConstFloat, 31 | KindBool, 32 | KindShort, 33 | KindInt, 34 | KindFloat, 35 | KindVoid, 36 | KindArray, 37 | KindStruct, 38 | KindPointer, 39 | KindFunction 40 | }; 41 | 42 | private: 43 | // Type kind 44 | Kind kind; 45 | 46 | public: 47 | 48 | /// Constructor 49 | Type(Kind kind) : kind(kind) { } 50 | 51 | /// Return the type kind 52 | Kind getKind() {return kind; } 53 | 54 | /// For types of kind 'KindArray', number of elements in array. 55 | int num_elem = 0; 56 | 57 | /// For types of kind 'KindStruct', symbol table containing the fields. 58 | SymbolTable *symbol_table = nullptr; 59 | 60 | /// Associated LLVM type 61 | llvm::Type *lltype = nullptr; 62 | 63 | /// For types of kind 'KindArray' and 'KindPointer', type of array 64 | /// elements or elements pointed to. 65 | Type *subtype = nullptr; 66 | 67 | /// For types of kind 'KindFunction' 68 | std::vector *arguments; 69 | Type *rettype = nullptr; 70 | 71 | 72 | /// Dump information about the type 73 | void dump(int indent = 0); 74 | }; 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /codegen/CodeBlock.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file CodeBlock.h 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief CodeBlock class contains interfaces for operating on a block of verilog statements. 7 | */ 8 | 9 | #ifndef VERILOG_BASIC_BLOCK_H 10 | #define VERILOG_BASIC_BLOCK_H 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | namespace verilog 18 | { 19 | 20 | // Forward declarations 21 | class DataFlow; 22 | 23 | class CodeBlock 24 | { 25 | // Label name 26 | std::string name; 27 | 28 | // List of dataFlows 29 | std::list dataflows; 30 | 31 | // List of successors and predecessors 32 | std::list succ; 33 | std::list pred; 34 | 35 | public: 36 | 37 | // Constructor 38 | CodeBlock(const std::string &name) : name(name) 39 | { 40 | } 41 | 42 | // Add dataFlow to code block 43 | void addDataFlow(DataFlow *dataflow) 44 | { 45 | dataflows.push_back(dataflow); 46 | } 47 | 48 | 49 | // Add a code block B2 to the list of successors of the current code 50 | // block B1. Also, add B1 to the list of predecessors of B2. 51 | void addSuccessor(CodeBlock *code_block) 52 | { 53 | assert(this != code_block); 54 | succ.push_back(code_block); 55 | code_block->pred.push_back(this); 56 | } 57 | 58 | 59 | // Return label name 60 | const std::string &getName() { return name; } 61 | 62 | // Print code block 63 | void dump(); 64 | }; 65 | 66 | 67 | } 68 | 69 | #endif 70 | 71 | -------------------------------------------------------------------------------- /parser/SymbolTable.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SymbolTable.h 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief The symbol table class definition for LLVM parser. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "SymbolTable.h" 13 | #include "Type.h" 14 | 15 | void Symbol::dump(int indent) 16 | { 17 | // Indent 18 | std::cout << std::string(indent, ' '); 19 | 20 | // Name, index 21 | std::cout << "Symbol: name='" << name << "', index=" << index << '\n'; 22 | 23 | // Type 24 | type->dump(indent + 2); 25 | } 26 | 27 | int Symbol::temp_index = 0; 28 | int Symbol::basic_block_index = 0; 29 | 30 | std::string Symbol::getTemp() 31 | { 32 | std::ostringstream stream; 33 | stream << "t" << temp_index++; 34 | return stream.str(); 35 | } 36 | 37 | std::string Symbol::getBasicBlock() 38 | { 39 | std::ostringstream stream; 40 | stream << "L" << basic_block_index++; 41 | return stream.str(); 42 | } 43 | 44 | 45 | Symbol *SymbolTable::getSymbol(const std::string &name) 46 | { 47 | // Search 48 | auto it = symbols.find(name); 49 | 50 | // Not found 51 | if (it == symbols.end()) 52 | return nullptr; 53 | 54 | // Return symbol 55 | return it->second; 56 | } 57 | 58 | void SymbolTable::dump(int indent) 59 | { 60 | // Indent 61 | std::cout << std::string(indent, ' '); 62 | 63 | // Scope 64 | std::cout << "Symbol table: scope="; 65 | switch (scope) 66 | { 67 | case ScopeGlobal: std::cout << "global"; break; 68 | case ScopeLocal: std::cout << "local"; break; 69 | case ScopeStruct: std::cout << "struct"; break; 70 | } 71 | 72 | 73 | // Symbols 74 | std::cout << ", symbols:\n"; 75 | for(auto it : symbols) 76 | it.second->dump(indent + 2); 77 | 78 | // Newline 79 | std::cout << '\n'; 80 | } 81 | 82 | void SymbolTable::getLLVMTypes(std::vector &types) 83 | { 84 | // Add null symbols to vector 85 | for (unsigned i = 0; i < symbols.size(); i++) 86 | types.push_back(nullptr); 87 | 88 | // Add symbols sorted by their index 89 | for (auto it : symbols) 90 | types[it.second->index] = it.second->type->lltype; 91 | 92 | } 93 | -------------------------------------------------------------------------------- /parser/SymbolTable.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SymbolTable.h 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief The symbol table class interfaces for LLVM parser. 7 | */ 8 | 9 | #ifndef SYMBOL_TABLE_H 10 | #define SYMBOL_TABLE_H 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | // Forward declaration 17 | class Type; 18 | 19 | class Symbol 20 | { 21 | // Symbol name 22 | std::string name; 23 | 24 | // Index of next temporary variable 25 | static int temp_index; 26 | 27 | // Index of next basic block 28 | static int basic_block_index; 29 | 30 | public: 31 | 32 | /// Constructor 33 | Symbol(const std::string &name) : name(name) { } 34 | 35 | /// Return the symbol name 36 | const std::string &getName() { return name; } 37 | 38 | /// Symbol type 39 | Type *type = nullptr; 40 | 41 | /// Index for a symbol in a symbol table with scope set to 42 | /// 'ScopeStruct' 43 | int index = 0; 44 | 45 | /// LLVM address of the variable for symbols in a symbol table with 46 | /// its scope set to 'ScopeGlobal' or 'ScopeLocal'. 47 | llvm::Value *lladdress = nullptr; 48 | 49 | /// Dump information about the symbol 50 | void dump(int indent = 0); 51 | 52 | /// Return the name of a new temporary variable 53 | static std::string getTemp(); 54 | 55 | /// Return the name of a new basic block 56 | static std::string getBasicBlock(); 57 | }; 58 | 59 | class SymbolTable 60 | { 61 | public: 62 | 63 | /// Possible scopes for the symbol table 64 | enum Scope 65 | { 66 | ScopeInvalid, 67 | ScopeGlobal, 68 | ScopeLocal, 69 | ScopeStruct 70 | }; 71 | 72 | private: 73 | 74 | // Symbol table scope 75 | Scope scope; 76 | 77 | // Symbols 78 | std::unordered_map symbols; 79 | 80 | public: 81 | 82 | /// Constructor 83 | SymbolTable(Scope scope) : scope( scope ) { } 84 | 85 | /// Return the symbol table scope 86 | Scope getScope() { return scope; } 87 | 88 | /// Return a symbol given its name, or nullptr if not found. 89 | Symbol *getSymbol(const std::string &name); 90 | 91 | /// Add symbol to table 92 | void addSymbol(Symbol *symbol) 93 | { 94 | symbols[symbol->getName()] = symbol; 95 | } 96 | 97 | /// Dump symbol table to standard output 98 | void dump(int indent = 0); 99 | 100 | /// Return number of symbols in the symbol table. This is useful to 101 | /// calculate the index of the next symbol in a data structure 102 | int size() { return symbols.size(); } 103 | 104 | /// Return the LLVM types of all symbols in the symbol table, sorted 105 | /// by their index. This is useful for constructing LLVM struct types. 106 | void getLLVMTypes(std::vector &types); 107 | 108 | }; 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /parser/scanner.l: -------------------------------------------------------------------------------- 1 | /** 2 | * @file scanner.l 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief The scanner description for FLEX. 7 | */ 8 | 9 | %{ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "Type.h" 16 | #include "SymbolTable.h" 17 | #include "parser.h" 18 | 19 | #define YY_DECL extern "C" int yylex() 20 | using namespace std; 21 | %} 22 | %option noyywrap 23 | %% 24 | 25 | "bool" { 26 | return TokenBool; 27 | } 28 | 29 | "short" { 30 | return TokenShort; 31 | } 32 | 33 | "int" { 34 | return TokenInt; 35 | } 36 | 37 | "float" { 38 | return TokenFloat; 39 | } 40 | 41 | "void" { 42 | return TokenVoid; 43 | } 44 | 45 | "struct" { 46 | return TokenStruct; 47 | } 48 | 49 | "if" { 50 | return TokenIf; 51 | } 52 | 53 | "else" { 54 | return TokenElse; 55 | } 56 | 57 | "while" { 58 | return TokenWhile; 59 | } 60 | 61 | "return" { 62 | return TokenReturn; 63 | } 64 | 65 | "||" { 66 | return TokenLogicalOr; 67 | } 68 | 69 | "&&" { 70 | return TokenLogicalAnd; 71 | } 72 | 73 | ">=" { 74 | return TokenGreaterEqual; 75 | } 76 | 77 | "<=" { 78 | return TokenLessEqual; 79 | } 80 | 81 | "==" { 82 | return TokenDoubleEqual; 83 | } 84 | 85 | "!=" { 86 | return TokenNotEqual; 87 | } 88 | 89 | ">>" { 90 | return TokenLogicalShiftRight; 91 | } 92 | 93 | "^" { 94 | return TokenBitwiseXor; 95 | } 96 | 97 | "&" { 98 | return TokenBitwiseAnd; 99 | } 100 | 101 | "|" { 102 | return TokenBitwiseOr; 103 | } 104 | 105 | "<" { 106 | return TokenLessThan; 107 | } 108 | 109 | ">" { 110 | return TokenGreaterThan; 111 | } 112 | 113 | "!" { 114 | return TokenLogicalNot; 115 | } 116 | 117 | "*" { 118 | return TokenMult; 119 | } 120 | 121 | "/" { 122 | return TokenDiv; 123 | } 124 | 125 | "+" { 126 | return TokenPlus; 127 | } 128 | 129 | "-" { 130 | return TokenMinus; 131 | } 132 | 133 | "." { 134 | return TokenPoint; 135 | } 136 | 137 | "[" { 138 | return TokenOpenSquare; 139 | } 140 | 141 | "]" { 142 | return TokenCloseSquare; 143 | } 144 | 145 | "{" { 146 | return TokenOpenCurly; 147 | } 148 | 149 | "}" { 150 | return TokenCloseCurly; 151 | } 152 | 153 | "(" { 154 | return TokenOpenPar; 155 | } 156 | 157 | ")" { 158 | return TokenClosePar; 159 | } 160 | 161 | ";" { 162 | return TokenSemicolon; 163 | } 164 | 165 | "," { 166 | return TokenComma; 167 | } 168 | 169 | "=" { 170 | return TokenEqual; 171 | } 172 | 173 | [a-zA-Z_][a-zA-Z_0-9]* { 174 | yylval.name = strdup(yytext); 175 | return TokenId; 176 | } 177 | 178 | [0-9]+ { 179 | yylval.value = atoi(yytext); 180 | return TokenNumber; 181 | } 182 | 183 | [ \t\n]+ { 184 | // Skip spaces, tabs, and newlines 185 | } 186 | 187 | . { 188 | std::cout << "Invalid token\n"; 189 | } 190 | %% 191 | -------------------------------------------------------------------------------- /codegen/Module.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Module.h 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief This class contains interfaces for operating on verilog modules. 7 | */ 8 | 9 | #ifndef VERILOG_FUNCTION_H 10 | #define VERILOG_FUNCTION_H 11 | 12 | 13 | #include "llvm/IR/Function.h" 14 | #include "llvm/IR/Constants.h" 15 | #include "Argument.h" 16 | 17 | #include 18 | 19 | 20 | namespace verilog 21 | { 22 | 23 | // Forward declarations 24 | class CodeBlock; 25 | class Wire; 26 | class Register; 27 | 28 | 29 | class Module 30 | { 31 | // Table of code blocks, indexed by name 32 | std::unordered_map code_block_table; 33 | 34 | // List of code blocks, preseving the LLVM order 35 | std::list code_blocks; 36 | 37 | // Entry and exit code blocks 38 | CodeBlock *entry_code_block; 39 | CodeBlock *exit_code_block; 40 | 41 | // Symbol table, associating LLVM variable names to VERILOG wires 42 | std::unordered_map wire_symbol_table; 43 | // Symbol table, associating LLVM variable names to VERILOG registers 44 | std::unordered_map register_symbol_table; 45 | 46 | public: 47 | 48 | // Constructor. It creates an entry and exit code blocks for the 49 | // function. 50 | Module(); 51 | 52 | // Add a code block 53 | void addCodeBlock(CodeBlock *code_block); 54 | 55 | // Get code block given its label, or nullptr if it doesn't exist. 56 | CodeBlock *getCodeBlock(const std::string &name); 57 | 58 | // Return entry code block 59 | CodeBlock *getEntryCodeBlock() { return entry_code_block; } 60 | 61 | // Return exit code block 62 | CodeBlock *getExitCodeBlock() { return exit_code_block; } 63 | 64 | // Add symbol to symbol table 65 | void WireAddSymbol(const std::string &name, Wire *wire) 66 | { 67 | wire_symbol_table[name] = wire; 68 | } 69 | 70 | // Add symbol to symbol table 71 | void RegisterAddSymbol(const std::string &name, Register *reg) 72 | { 73 | register_symbol_table[name] = reg; 74 | } 75 | 76 | // Lookup symbol table, and produce error if symbol not found. 77 | Wire *wirelookupSymbol(const std::string &name); 78 | 79 | // Lookup symbol table, and produce error if symbol not found. 80 | Register *registerlookupSymbol(const std::string &name); 81 | 82 | // If the given value is an LLVM variable, return a new wire 83 | // associated with the symbol as read from the symbol table. If the 84 | // value is an LLVM constant, emit an 'li' instruction in the given 85 | // code block, and return the wire that was assigned the constant. 86 | Wire *translateLLVMValueWire(CodeBlock *code_block, 87 | llvm::Value *llvm_value, 88 | Wire::Direction direction 89 | ); 90 | 91 | // If the given value is an LLVM variable, return a new register 92 | // associated with the symbol as read from the symbol table. If the 93 | // value is an LLVM constant, emit an 'li' instruction in the given 94 | // code block, and return the register that was assigned the constant. 95 | Register *translateLLVMValueRegister(CodeBlock *code_block, 96 | llvm::Value *llvm_value, 97 | Register::Direction direction, 98 | bool seqReg = false); 99 | 100 | // Print it 101 | void dump(); 102 | }; 103 | 104 | } 105 | 106 | 107 | #endif 108 | 109 | -------------------------------------------------------------------------------- /codegen/Module.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Module.cc 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief This file defines the operations on verilog modules. 7 | */ 8 | 9 | #include "CodeBlock.h" 10 | #include "Module.h" 11 | #include "DataFlow.h" 12 | 13 | 14 | namespace verilog 15 | { 16 | 17 | 18 | Module::Module() 19 | { 20 | entry_code_block = new CodeBlock("entry"); 21 | // for(auto& functionArgs : 22 | exit_code_block = new CodeBlock("exit"); 23 | } 24 | 25 | void Module::addCodeBlock(CodeBlock *code_block) 26 | { 27 | code_block_table[code_block->getName()] = code_block; 28 | code_blocks.push_back(code_block); 29 | } 30 | 31 | 32 | CodeBlock *Module::getCodeBlock(const std::string &name) 33 | { 34 | auto it = code_block_table.find(name); 35 | return it == code_block_table.end() ? nullptr : it->second; 36 | } 37 | 38 | 39 | Wire *Module::wirelookupSymbol(const std::string &name) 40 | { 41 | auto it = wire_symbol_table.find(name); 42 | if (it == wire_symbol_table.end()) 43 | { 44 | std::cerr << "Error: symbol '" << name << "' not found\n"; 45 | exit(1); 46 | } 47 | return it->second; 48 | } 49 | 50 | Register *Module::registerlookupSymbol(const std::string &name) 51 | { 52 | auto it = register_symbol_table.find(name); 53 | if (it == register_symbol_table.end()) 54 | { 55 | std::cerr << "Error: symbol '" << name << "' not found\n"; 56 | exit(1); 57 | } 58 | return it->second; 59 | } 60 | 61 | Wire *Module::translateLLVMValueWire(CodeBlock *code_block, 62 | llvm::Value *llvm_value, 63 | Wire::Direction direction) 64 | { 65 | if (llvm_value->getValueID() == llvm::Value::ConstantIntVal) 66 | { 67 | 68 | // Emit 'assign dest = constant;' 69 | DataFlow *dataflow = new DataFlow( 70 | DataFlow::OpcodeAssign); 71 | 72 | // First Argument 73 | Wire *dest = Wire::newWire(Wire::DirectionOutput); 74 | 75 | // Second argument 76 | llvm::ConstantInt *llvm_constant = llvm::cast 77 | (llvm_value); 78 | Constant *constant = new Constant(llvm_constant->getSExtValue()); 79 | verilog::DataFlow *verilog_signaldef = new verilog::DataFlow(verilog::DataFlow::OpcodeSignalDefine); 80 | 81 | llvm::Type *type = llvm_constant->getType(); 82 | if (type->isIntegerTy(32)) 83 | { 84 | dest->setWidth(32); 85 | } 86 | else if (type->isIntegerTy(16)) 87 | { 88 | dest->setWidth(16); 89 | } 90 | else if (type->isIntegerTy(8)) 91 | { 92 | dest->setWidth(8); 93 | } 94 | else if (type->isIntegerTy(1)) 95 | { 96 | dest->setWidth(1); 97 | } 98 | else 99 | { 100 | std::cerr << "Unsupported type in temporay registers\n"; 101 | exit(1); 102 | } 103 | code_block->addDataFlow(verilog_signaldef); 104 | verilog_signaldef->addArgument(dest); 105 | 106 | code_block->addDataFlow(dataflow); 107 | dataflow->addArgument(dest); 108 | dataflow->addArgument(constant); 109 | 110 | 111 | // Return copy of created register 112 | return new Wire(dest->getName(), direction); 113 | } 114 | else 115 | { 116 | Wire *wire = wirelookupSymbol(llvm_value->getName()); 117 | return new Wire(wire->getName(), direction); 118 | } 119 | } 120 | 121 | Register *Module::translateLLVMValueRegister(CodeBlock *code_block, 122 | llvm::Value *llvm_value, 123 | Register::Direction direction, 124 | bool seqReg) 125 | { 126 | if (llvm_value->getValueID() == llvm::Value::ConstantIntVal) 127 | { 128 | // Emit 'assign dest = constant;' 129 | DataFlow *dataflow = new DataFlow( 130 | DataFlow::OpcodeAssign); 131 | code_block->addDataFlow(dataflow); 132 | 133 | // First Argument 134 | Register *dest = Register::newRegister(Register::DirectionOutput); 135 | dataflow->addArgument(dest); 136 | 137 | // Second argument 138 | llvm::ConstantInt *llvm_constant = llvm::cast 139 | (llvm_value); 140 | Constant *constant = new Constant(llvm_constant->getSExtValue()); 141 | dataflow->addArgument(constant); 142 | 143 | // Return copy of created register 144 | return new Register(dest->getName(), direction, seqReg); 145 | } 146 | else 147 | { 148 | Register *reg = registerlookupSymbol(llvm_value->getName()); 149 | return new Register(reg->getName(), direction, seqReg); 150 | } 151 | } 152 | 153 | 154 | void Module::dump() 155 | { 156 | // Print all basic blocks 157 | for (CodeBlock *code_block : code_blocks) 158 | code_block->dump(); 159 | } 160 | 161 | } 162 | 163 | -------------------------------------------------------------------------------- /codegen/DataFlow.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @file DataFlow.cc 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief Dataflow class definition. 7 | */ 8 | 9 | #include "llvm/IR/Function.h" 10 | #include "DataFlow.h" 11 | 12 | 13 | namespace verilog 14 | { 15 | 16 | std::string DataFlow::names[DataFlow::OpcodeMax] = { 17 | "", 18 | "portliststart", 19 | "iportdefine", 20 | "oportdefine", 21 | "portlistend", 22 | "signaldefine", 23 | "assign", 24 | "+", 25 | "-", 26 | ">>", 27 | "^", 28 | "&", 29 | "|", 30 | "==", 31 | ">", 32 | "endmodule" 33 | }; 34 | 35 | 36 | void DataFlow::dump() 37 | { 38 | int iter = 0; 39 | 40 | // operation name 41 | std::string op = names[opcode]; 42 | std::string next_string = ";"; 43 | std::string comma = ", "; 44 | std::string assignment = " ="; 45 | 46 | if(op == "portliststart"){ 47 | std::cout << "module "; 48 | for (Argument *argument : arguments) 49 | //for (std::list::iterator argument=arguments.begin(); argument != arguments.end(); ++argument) 50 | { 51 | argument->dump(); 52 | } 53 | 54 | 55 | std::cout << " ("; 56 | 57 | } else if(op == "iportdefine"){ 58 | 59 | //std::cout << "\b\b\b\b\b\b"; 60 | for (Argument *argument : arguments) 61 | //for (std::list::iterator argument=arguments.begin(); argument != arguments.end(); ++argument) 62 | { 63 | 64 | if (argument->getWidth() == 32) 65 | { 66 | std::cout << "input wire [31:0] "; 67 | } 68 | else if (argument->getWidth() == 16) 69 | { 70 | std::cout << "input wire [15:0] "; 71 | } 72 | else if (argument->getWidth() == 8) 73 | { 74 | std::cout << "input wire [7:0] "; 75 | } 76 | else if (argument->getWidth() == 1) 77 | { 78 | std::cout << "input wire "; 79 | } 80 | else 81 | { 82 | std::cerr << "Unsupported width in module input ports\n"; 83 | exit(1); 84 | } 85 | argument->dump(); 86 | std::cout << comma; 87 | 88 | } 89 | 90 | } else if(op == "oportdefine"){ 91 | 92 | //std::cout << "\b\b\b\b\b\b"; 93 | for (Argument *argument : arguments) 94 | //for (std::list::iterator argument=arguments.begin(); argument != arguments.end(); ++argument) 95 | { 96 | 97 | if (argument->getWidth() == 32) 98 | { 99 | std::cout << "output wire [31:0] "; 100 | } 101 | else if (argument->getWidth() == 16) 102 | { 103 | std::cout << "output wire [15:0] "; 104 | } 105 | else if (argument->getWidth() == 8) 106 | { 107 | std::cout << "output wire [7:0] "; 108 | } 109 | else if (argument->getWidth() == 1) 110 | { 111 | std::cout << "output wire "; 112 | } 113 | else 114 | { 115 | std::cerr << "Unsupported width in module output port\n"; 116 | exit(1); 117 | } 118 | argument->dump(); 119 | 120 | } 121 | 122 | } else if(op == "portlistend"){ 123 | 124 | //std::cout << "\b\b\b\b"; 125 | std::cout << ");"; 126 | /* for (Argument *argument : arguments) 127 | //for (std::list::iterator argument=arguments.begin(); argument != arguments.end(); ++argument) 128 | { 129 | argument->dump(); 130 | } 131 | 132 | */ 133 | 134 | 135 | } else if(op == "signaldefine"){ 136 | 137 | for (Argument *argument : arguments) 138 | //for (std::list::iterator argument=arguments.begin(); argument != arguments.end(); ++argument) 139 | { 140 | if (argument->getWidth() == 32) 141 | { 142 | std::cout << "wire [31:0] "; 143 | } 144 | else if (argument->getWidth() == 16) 145 | { 146 | std::cout << "wire [15:0] "; 147 | } 148 | else if (argument->getWidth() == 8) 149 | { 150 | std::cout << "wire [7:0] "; 151 | } 152 | else if (argument->getWidth() == 1) 153 | { 154 | std::cout << "wire "; 155 | } 156 | else 157 | { 158 | std::cerr << "Unsupported width for internal signals\n"; 159 | exit(1); 160 | } 161 | 162 | argument->dump(); 163 | 164 | } 165 | std::cout << ";"; 166 | 167 | 168 | } else if(op != "endmodule"){ 169 | // assign 170 | std::cout << "assign "; 171 | for (Argument *argument : arguments) 172 | //for (std::list::iterator argument=arguments.begin(); argument != arguments.end(); ++argument) 173 | { 174 | 175 | argument->dump(); 176 | 177 | if(iter == 0){ 178 | std::cout << assignment; 179 | } else { 180 | next_string = (op == "assign") | (iter == (arguments.size() - 1) ) ? ";": " " + op; 181 | std::cout << next_string; 182 | } 183 | // std::cout << op << "\n"; 184 | // Print argument 185 | 186 | // Print space 187 | std::cout << " "; 188 | 189 | 190 | iter++; 191 | 192 | } 193 | 194 | } else { 195 | std::cout << op; 196 | } 197 | 198 | std::cout << "\n"; 199 | 200 | } 201 | 202 | 203 | } 204 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # c-ll-verilog 2 | An LLVM based mini-C to Verilog High-level Synthesis tool 3 | ## Overview 4 | In this project, we are proposing an LLVM based mini-C to Verilog high-level synthesis (HLS) 5 | tool, called **c-ll-verilog** (C to Verilog). HLS is a trending topic in both the academia and industry which aims to reduce the complexity of 6 | hardware design by automatically generating hardware description language (HDL) code from a higher 7 | level language such as C. An important different between programming languages like C and HDLs is 8 | that, C and similar languages are meant to be used on a predefined architectures, which usually are 9 | conventional von neumann architectures, while HDL itself (in the domain of FPGA programming) is 10 | meant to model and design the underlying architecture or hardware. There are different HLS tools which 11 | their generated HDL code can be implemented on the latest field programmable gate array (FPGA) or 12 | system-on-chips. However, due to the inherent syntax and symantec differences in general purpose high 13 | level languages such as C and HDLs and the complexity of this conversion, current HLS tools cannot yet 14 | satisfy all of the performance, area, and power requirements of the complex systems. Therefore, in the 15 | view of the author these tools are either used in a highly annotated manner (for e.g. using *PRAGMA* or 16 | compiler directives) for a specific FPGA device and application or used for experimental as well as 17 | educational purposes. In this project we investigated the HLS process using an [LLVM](http://llvm.org) based framework, 18 | and by compiling a subset of branchless C statements to dataflow modeling [Verilog](http://www.verilog.com) code. 19 | 20 | ## What's inside and how it works? 21 | The overall goal of this project was to convert a C function to a Verilog module, with the following 22 | features: 23 | * C function arguments are used as Verilog module input ports (no pointer, array, and struct 24 | support) 25 | * C function return value are used as Verilog module output port 26 | * Only a subset of branchless C statements is supported 27 | * Only a subset of arithmetic and logical operations are supported (addition, subtraction, signed greater than, equality, logical shift right, bitwise XOR, bitwise AND, and bitwise OR) 28 | * Only combinational logic with data modeling Verilog style is supported (no registers and clock) 29 | 30 | The following [UML](http://www.uml.org/) diagram represents the summarized class hierarchy use in the LLVM-to-Verilog code generator: 31 | ![LLVM-to-Verilog class hierarchy](https://github.com/sabbaghm/c-ll-verilog/blob/master/figures/ll-verilog_uml_diagram.png) 32 | 33 | ## Building the toolchain 34 | A simple LLVM parser and code generator are built upon a MIPS code generator LLVM pass. 35 | Build the c-ll-verilog tool (as `verilog` LLVM `opt` pass) in a linux machine with proper 36 | installation of LLVM framework, after cloning the repository and run `make` command in the main directory. You can clean the generated files using the `make clean` command. 37 | 38 | ## Let's go live! 39 | To run the HLS tool pass your c file to the [simpleHLS.bash](https://github.com/sabbaghm/c-ll-verilog/blob/master/simpleHLS.bash) script as below (make sure simpleHLS.bash is 40 | set to executable using the `chmod +x simpleHLS.bash` command): 41 | `./simpleHLS.bash .c` 42 | You should see the generated Verilog file in the same directory as .v. So the only thing that is needed is to pass the input C file as an argument to the script and it produces the corresponding Verilog file with the same name. 43 | 44 | Note that after the parsing process mem2reg LLVM optimization is used to simplify the LLVM code 45 | remove memory allocation and accesses as it is not supported by our simple HLS tool. 46 | An example C code ([filter.c](https://github.com/sabbaghm/c-ll-verilog/blob/master/filter.c)), 47 | ```C 48 | bool adder(int in1, int in2, int threshold, 49 | int mask) 50 | { 51 | return ( ( ( (in1+in2) & mask ) >> 2 ) > threshold ); 52 | } 53 | ``` 54 | and its synthesis to Verilog code (filter.v): 55 | 56 | ```Verilog 57 | //entry: 58 | module adder ( 59 | input wire [31:0] in1, 60 | input wire [31:0] in2, 61 | input wire [31:0] threshold, 62 | input wire [31:0] mask, 63 | output wire result 64 | ); 65 | //L0: 66 | wire [31:0] wire000; 67 | assign wire000 = in1 + in2; 68 | wire [31:0] wire001; 69 | assign wire001 = wire000 & mask; 70 | wire [31:0] wire003; 71 | assign wire003 = 2; 72 | wire [31:0] wire002; 73 | assign wire002 = wire001 >> wire003; 74 | wire wire004; 75 | assign wire004 = wire002 > threshold; 76 | assign result = wire004; 77 | //exit: 78 | endmodule 79 | ``` 80 | 81 | ## License 82 | 83 | This project is licensed under the MIT License - see the [license](https://github.com/sabbaghm/c-ll-verilog/blob/master/LICENSE) file for details 84 | 85 | ## Acknowledgments 86 | 87 | This project was based on the materials presented and taught by professor Refael Ubal for the Compilers course (EECE-7398) at Northeastern University in Fall 2016. -------------------------------------------------------------------------------- /parser/parser.h: -------------------------------------------------------------------------------- 1 | /* A Bison parser, made by GNU Bison 2.7. */ 2 | 3 | /* Bison interface for Yacc-like parsers in C 4 | 5 | Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . */ 19 | 20 | /* As a special exception, you may create a larger work that contains 21 | part or all of the Bison parser skeleton and distribute that work 22 | under terms of your choice, so long as that work isn't itself a 23 | parser generator using the skeleton or a modified version thereof 24 | as a parser skeleton. Alternatively, if you modify or redistribute 25 | the parser skeleton itself, you may (at your option) remove this 26 | special exception, which will cause the skeleton and the resulting 27 | Bison output files to be licensed under the GNU General Public 28 | License without this special exception. 29 | 30 | This special exception was added by the Free Software Foundation in 31 | version 2.2 of Bison. */ 32 | 33 | #ifndef YY_YY_PARSER_H_INCLUDED 34 | # define YY_YY_PARSER_H_INCLUDED 35 | /* Enabling traces. */ 36 | #ifndef YYDEBUG 37 | # define YYDEBUG 0 38 | #endif 39 | #if YYDEBUG 40 | extern int yydebug; 41 | #endif 42 | 43 | /* Tokens. */ 44 | #ifndef YYTOKENTYPE 45 | # define YYTOKENTYPE 46 | /* Put the tokens into the symbol table, so that GDB and other debuggers 47 | know about them. */ 48 | enum yytokentype { 49 | TokenBool = 258, 50 | TokenShort = 259, 51 | TokenInt = 260, 52 | TokenFloat = 261, 53 | TokenVoid = 262, 54 | TokenStruct = 263, 55 | TokenId = 264, 56 | TokenNumber = 265, 57 | TokenOpenCurly = 266, 58 | TokenCloseCurly = 267, 59 | TokenOpenSquare = 268, 60 | TokenCloseSquare = 269, 61 | TokenOpenPar = 270, 62 | TokenClosePar = 271, 63 | TokenSemicolon = 272, 64 | TokenComma = 273, 65 | TokenPoint = 274, 66 | TokenEqual = 275, 67 | TokenLogicalOr = 276, 68 | TokenLogicalAnd = 277, 69 | TokenLogicalNot = 278, 70 | Toke = 279, 71 | TokenGreaterThan = 280, 72 | TokenLessThan = 281, 73 | TokenGreaterEqual = 282, 74 | TokenLessEqual = 283, 75 | TokenNotEqual = 284, 76 | TokenDoubleEqual = 285, 77 | TokenBitwiseOr = 286, 78 | TokenBitwiseXor = 287, 79 | TokenBitwiseAnd = 288, 80 | TokenLogicalShiftRight = 289, 81 | TokenMinus = 290, 82 | TokenPlus = 291, 83 | TokenDiv = 292, 84 | TokenMult = 293, 85 | TokenIf = 294, 86 | TokenThen = 295, 87 | TokenElse = 296, 88 | TokenWhile = 297, 89 | TokenReturn = 298 90 | }; 91 | #endif 92 | 93 | 94 | #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED 95 | typedef union YYSTYPE 96 | { 97 | /* Line 2058 of yacc.c */ 98 | #line 78 "parser.y" 99 | 100 | char *name; 101 | llvm::Value *llvalue; 102 | int value; 103 | Type *type; 104 | std::list *indices; 105 | 106 | // For LValue 107 | struct { 108 | Type *type; 109 | llvm::Value *lladdress; 110 | std::vector *llindices; 111 | llvm::Value *llvalue; 112 | } lvalue; 113 | 114 | // For mid-rule actions in logical expressions 115 | struct { 116 | llvm::BasicBlock *lhs_basic_block; 117 | llvm::BasicBlock *rhs_basic_block; 118 | llvm::BasicBlock *end_basic_block; 119 | } logical; 120 | 121 | // For mid-rule actions in "if" statement 122 | struct { 123 | llvm::BasicBlock *then_basic_block; 124 | llvm::BasicBlock *else_basic_block; 125 | llvm::BasicBlock *end_basic_block; 126 | } if_statement; 127 | // For mid-rule actions in "while" statement 128 | struct { 129 | llvm::BasicBlock *cond_basic_block; 130 | llvm::BasicBlock *body_basic_block; 131 | llvm::BasicBlock *end_basic_block; 132 | } while_statement; 133 | 134 | // For 'FormalArguments' and 'FormalArgumentsComma' 135 | std::vector *formal_arguments; 136 | 137 | // For 'FunctionDeclaration' 138 | Symbol *symbol; 139 | 140 | // For 'ActualArguments' and 'ActualArgummentsComma' 141 | std::vector *actual_arguments; 142 | 143 | 144 | /* Line 2058 of yacc.c */ 145 | #line 146 "parser.h" 146 | } YYSTYPE; 147 | # define YYSTYPE_IS_TRIVIAL 1 148 | # define yystype YYSTYPE /* obsolescent; will be withdrawn */ 149 | # define YYSTYPE_IS_DECLARED 1 150 | #endif 151 | 152 | extern YYSTYPE yylval; 153 | 154 | #ifdef YYPARSE_PARAM 155 | #if defined __STDC__ || defined __cplusplus 156 | int yyparse (void *YYPARSE_PARAM); 157 | #else 158 | int yyparse (); 159 | #endif 160 | #else /* ! YYPARSE_PARAM */ 161 | #if defined __STDC__ || defined __cplusplus 162 | int yyparse (void); 163 | #else 164 | int yyparse (); 165 | #endif 166 | #endif /* ! YYPARSE_PARAM */ 167 | 168 | #endif /* !YY_YY_PARSER_H_INCLUDED */ 169 | -------------------------------------------------------------------------------- /codegen/Argument.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Argument.h 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief Argument class contains interfaces for proper operations on verilog statement arguments. 7 | */ 8 | 9 | #ifndef VERILOG_ARGUMENT_H 10 | #define VERILOG_ARGUMENT_H 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace verilog 17 | { 18 | 19 | // Forward declarations 20 | class CodeBlock; 21 | 22 | 23 | class Argument 24 | { 25 | public: 26 | // Dump the argument (abstract function) 27 | virtual void dump() = 0; 28 | virtual int getWidth() = 0; 29 | virtual void setWidth(int val) = 0; 30 | }; 31 | 32 | class Wire : public Argument 33 | { 34 | public: 35 | 36 | // Data-flow direction 37 | enum Direction 38 | { 39 | DirectionInvalid, 40 | DirectionLhs, 41 | DirectionRhs, 42 | DirectionInput, 43 | DirectionOutput 44 | }; 45 | //The make_string function is taken from http://stackoverflow.com/questions/8713643/how-to-generate-consecutive-c-strings 46 | static std::string make_string(const std::string& a_prefix, 47 | size_t a_suffix, 48 | size_t a_max_length) 49 | { 50 | std::ostringstream result; 51 | result << a_prefix << 52 | std::setfill('0') << 53 | std::setw(a_max_length - a_prefix.length()) << 54 | a_suffix; 55 | return result.str(); 56 | } 57 | 58 | private: 59 | 60 | // Internal, Input or output wire 61 | Direction direction = DirectionInvalid; 62 | 63 | // Wire name 64 | std::string name; 65 | 66 | // Wire width 67 | int width; 68 | 69 | // Wire ID counter 70 | static int next_number; 71 | 72 | // Make_string make_string; 73 | 74 | 75 | public: 76 | 77 | // Return a new wire argument. 78 | static Wire *newWire(Direction direction) 79 | { 80 | return new Wire(make_string("wire", next_number++, 7), direction); 81 | } 82 | 83 | // Constructor 84 | Wire(std::string name, Direction direction) : 85 | name(name), 86 | direction(direction) 87 | { 88 | } 89 | 90 | // Wire internal, input or output direction 91 | Direction getDirection() { return direction; } 92 | //Direction getDirection(); 93 | 94 | // Return wire name 95 | std::string getName() { return name; } 96 | 97 | //Return the wire width 98 | int getWidth(); 99 | 100 | //Set the wire width 101 | void setWidth(int val); 102 | 103 | // Print argument 104 | void dump(); 105 | 106 | // void test(); 107 | }; 108 | 109 | class Register : public Argument 110 | { 111 | public: 112 | 113 | // Data-flow direction 114 | enum Direction 115 | { 116 | DirectionInvalid, 117 | DirectionLhs, 118 | DirectionRhs, 119 | DirectionInput, 120 | DirectionOutput 121 | }; 122 | 123 | //The make_string function is taken from http://stackoverflow.com/questions/8713643/how-to-generate-consecutive-c-strings 124 | static std::string make_string(const std::string& a_prefix, 125 | size_t a_suffix, 126 | size_t a_max_length) 127 | { 128 | std::ostringstream result; 129 | result << a_prefix << 130 | std::setfill('0') << 131 | std::setw(a_max_length - a_prefix.length()) << 132 | a_suffix; 133 | return result.str(); 134 | } 135 | 136 | private: 137 | 138 | // Internal, Input or output register 139 | Direction direction = DirectionInvalid; 140 | 141 | // Register name 142 | std::string name; 143 | 144 | // Register width 145 | int width; 146 | 147 | // True if register is used in sequential logic (flip-flop) false if it is a wire 148 | bool seqReg = false; 149 | 150 | // Register ID counter 151 | static int next_number; 152 | 153 | // Make_string make_string; 154 | 155 | public: 156 | 157 | // Return whether a register is actually a wire. This is 158 | // used for instruction printing purposes. 159 | static bool isSeqRegister(Argument *argument) 160 | { 161 | Register *r = dynamic_cast(argument); 162 | return r && r->isSequential(); 163 | } 164 | 165 | // Return a new register argument. 166 | static Register *newRegister(Direction direction, bool seqReg = false) 167 | { 168 | return new Register(make_string("reg", next_number++, 7), direction, seqReg); 169 | } 170 | 171 | // Constructor 172 | Register(std::string name, Direction direction, bool seqReg = false) : 173 | name(name), 174 | direction(direction), 175 | seqReg(seqReg) 176 | { 177 | } 178 | 179 | // Return internal, input or output direction 180 | Direction getDirection() { return direction; } 181 | //Direction getDirection(); 182 | 183 | // Return register number 184 | std::string getName() { return name; } 185 | 186 | //Return the register width 187 | int getWidth(); 188 | 189 | //Set the register width 190 | void setWidth(int val); 191 | 192 | // Return whether register is a sequential register (flip-flop) 193 | bool isSequential() { return seqReg; } 194 | 195 | // Print argument 196 | void dump(); 197 | //void test(); 198 | }; 199 | 200 | 201 | class Constant : public Argument 202 | { 203 | // Value of the constant 204 | int value; 205 | 206 | int width; 207 | public: 208 | 209 | // Constructor 210 | Constant(int value) : value(value) 211 | { 212 | } 213 | 214 | // Return constant value 215 | int getValue() { return value; } 216 | 217 | //Return the register width 218 | int getWidth(); 219 | 220 | //Set the register width 221 | void setWidth(int val); 222 | 223 | // Print argument 224 | void dump(); 225 | // void test(); 226 | }; 227 | 228 | 229 | } 230 | #endif 231 | -------------------------------------------------------------------------------- /parser/parser.y: -------------------------------------------------------------------------------- 1 | /** 2 | * @file parser.y 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief This is the parser description for bison. 7 | */ 8 | 9 | %{ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "SymbolTable.h" 20 | #include "Type.h" 21 | 22 | extern "C" int yylex(); 23 | extern "C" int yyparse(); 24 | extern "C" FILE *yyin; 25 | void yyerror(const char *s); 26 | 27 | // Module, function, basic block, and builder 28 | llvm::Module *module; 29 | llvm::Function *function; 30 | llvm::BasicBlock *basic_block; 31 | llvm::IRBuilder<> *builder; 32 | 33 | // Environment: stack of symbol tables. It is actually implemented as a list 34 | // to facilitate the traversal of symbol tables. 35 | std::list environment; 36 | %} 37 | 38 | %token TokenBool 39 | %token TokenShort 40 | %token TokenInt 41 | %token TokenFloat 42 | %token TokenVoid 43 | %token TokenStruct 44 | %token TokenId 45 | %token TokenNumber 46 | %token TokenOpenCurly 47 | %token TokenCloseCurly 48 | %token TokenOpenSquare 49 | %token TokenCloseSquare 50 | %token TokenOpenPar 51 | %token TokenClosePar 52 | %token TokenSemicolon 53 | %token TokenComma 54 | %token TokenPoint 55 | %token TokenEqual 56 | %left TokenLogicalOr 57 | %left TokenLogicalAnd 58 | %token TokenLogicalNot 59 | %token Toke 60 | %nonassoc TokenGreaterThan 61 | %nonassoc TokenLessThan 62 | %nonassoc TokenGreaterEqual 63 | %nonassoc TokenLessEqual 64 | %nonassoc TokenNotEqual 65 | %nonassoc TokenDoubleEqual 66 | %left TokenPlus TokenMinus TokenLogicalShiftRight TokenBitwiseAnd TokenBitwiseXor TokenBitwiseOr 67 | %left TokenMult TokenDiv 68 | %token TokenIf 69 | %nonassoc TokenThen 70 | %nonassoc TokenElse 71 | %token TokenWhile 72 | %token TokenReturn 73 | 74 | %type Type 75 | %type Pointer 76 | %type Indices 77 | %type Expression 78 | %type LValue 79 | %type IfStatement 80 | %type FormalArguments 81 | %type FormalArgumentsComma 82 | %type FunctionDeclaration 83 | %type ActualArguments 84 | %type ActualArgumentsComma 85 | 86 | %union { 87 | char *name; 88 | llvm::Value *llvalue; 89 | int value; 90 | Type *type; 91 | std::list *indices; 92 | 93 | // For LValue 94 | struct { 95 | Type *type; 96 | llvm::Value *lladdress; 97 | std::vector *llindices; 98 | llvm::Value *llvalue; 99 | } lvalue; 100 | 101 | // For mid-rule actions in logical expressions 102 | struct { 103 | llvm::BasicBlock *lhs_basic_block; 104 | llvm::BasicBlock *rhs_basic_block; 105 | llvm::BasicBlock *end_basic_block; 106 | } logical; 107 | 108 | // For mid-rule actions in "if" statement 109 | struct { 110 | llvm::BasicBlock *then_basic_block; 111 | llvm::BasicBlock *else_basic_block; 112 | llvm::BasicBlock *end_basic_block; 113 | } if_statement; 114 | // For mid-rule actions in "while" statement 115 | struct { 116 | llvm::BasicBlock *cond_basic_block; 117 | llvm::BasicBlock *body_basic_block; 118 | llvm::BasicBlock *end_basic_block; 119 | } while_statement; 120 | 121 | // For 'FormalArguments' and 'FormalArgumentsComma' 122 | std::vector *formal_arguments; 123 | 124 | // For 'FunctionDeclaration' 125 | Symbol *symbol; 126 | 127 | // For 'ActualArguments' and 'ActualArgummentsComma' 128 | std::vector *actual_arguments; 129 | } 130 | 131 | %% 132 | 133 | Start: 134 | Declarations 135 | Declarations: 136 | | Declarations Declaration 137 | Declaration: 138 | Pointer TokenId Indices TokenSemicolon 139 | { 140 | // Get top symbol table 141 | SymbolTable *symbol_table = environment.back(); 142 | 143 | // Create new symbol 144 | Symbol *symbol = new Symbol($2); 145 | symbol->type = $1; 146 | symbol->index = symbol_table->size(); 147 | 148 | // Process indices 149 | for (int index : *$3) 150 | { 151 | Type *type = new Type(Type::KindArray); 152 | type->num_elem = index; 153 | type->subtype = symbol->type; 154 | type->lltype = llvm::ArrayType::get(symbol->type->lltype, index); 155 | symbol->type = type; 156 | } 157 | 158 | // Symbol in global scope 159 | if (symbol_table->getScope() == SymbolTable::ScopeGlobal) 160 | symbol->lladdress = new llvm::GlobalVariable( 161 | *module, 162 | symbol->type->lltype, 163 | false, 164 | llvm::GlobalValue::ExternalLinkage, 165 | nullptr, 166 | symbol->getName()); 167 | // Symbol in local scope 168 | else if (symbol_table->getScope() == SymbolTable::ScopeLocal) 169 | symbol->lladdress = builder->CreateAlloca(symbol->type->lltype, 170 | nullptr, Symbol::getTemp()); 171 | // Insert in symbol table 172 | symbol_table->addSymbol(symbol); 173 | } 174 | | FunctionDeclaration TokenOpenCurly 175 | { 176 | // Push new local symbol table 177 | SymbolTable *symbol_table = new SymbolTable(SymbolTable::ScopeLocal); 178 | environment.push_back(symbol_table); 179 | // Current LLVM function 180 | function = llvm::cast($1->lladdress); 181 | // Create entry basic block 182 | basic_block = llvm::BasicBlock::Create( 183 | llvm::getGlobalContext(), 184 | Symbol::getBasicBlock(), 185 | function); 186 | builder->SetInsertPoint(basic_block); 187 | 188 | // Add arguments to the stack 189 | int index = 0; 190 | for (llvm::Function::arg_iterator it = function->arg_begin(), 191 | end = function->arg_end(); 192 | it != end; 193 | ++it) 194 | { 195 | // Name argument 196 | Symbol *argument = (*$1->type->arguments)[index++]; 197 | it->setName(argument->getName()); 198 | // Create local symbol 199 | Symbol *symbol = new Symbol(argument->getName()); 200 | symbol->type = argument->type; 201 | symbol_table->addSymbol(symbol); 202 | // Emit 'alloca' instruction 203 | symbol->lladdress = builder->CreateAlloca(symbol->type->lltype, 204 | nullptr, Symbol::getTemp()); 205 | // Emit 'store' instruction 206 | builder->CreateStore(it, symbol->lladdress); 207 | } 208 | } 209 | Declarations Statements TokenCloseCurly 210 | { 211 | // Return statement, if not present 212 | if (!basic_block->getTerminator()) 213 | builder->CreateRetVoid(); 214 | // Pop local symbol table 215 | SymbolTable *symbol_table = environment.back(); 216 | environment.pop_back(); 217 | } 218 | | FunctionDeclaration TokenSemicolon 219 | FunctionDeclaration: 220 | Pointer TokenId TokenOpenPar FormalArguments TokenClosePar 221 | { 222 | // Create type 223 | Type *type = new Type(Type::KindFunction); 224 | type->rettype = $1; 225 | type->arguments = $4; 226 | // Create symbol 227 | Symbol *symbol = new Symbol($2); 228 | symbol->type = type; 229 | $$ = symbol; 230 | // Add to global symbol table 231 | SymbolTable *symbol_table = environment.front(); 232 | symbol_table->addSymbol(symbol); 233 | // Create function type 234 | std::vector types; 235 | for (Symbol *symbol : *$4) 236 | types.push_back(symbol->type->lltype); 237 | llvm::FunctionType *function_type = llvm::FunctionType::get( 238 | $1->lltype, 239 | types, 240 | false); 241 | // Insert function 242 | symbol->lladdress = module->getOrInsertFunction($2, 243 | function_type); 244 | } 245 | FormalArguments: 246 | { 247 | $$ = new std::vector(); 248 | } 249 | | FormalArgumentsComma Pointer TokenId 250 | { 251 | Symbol *symbol = new Symbol($3); 252 | symbol->type = $2; 253 | symbol->index = $1->size(); 254 | $$->push_back(symbol); 255 | } 256 | FormalArgumentsComma: 257 | { 258 | $$ = new std::vector(); 259 | } 260 | | FormalArgumentsComma Pointer TokenId TokenComma 261 | { 262 | Symbol *symbol = new Symbol($3); 263 | symbol->type = $2; 264 | symbol->index = $1->size(); 265 | $$->push_back(symbol); 266 | } 267 | Indices: 268 | { 269 | $$ = new std::list(); 270 | } 271 | | TokenOpenSquare TokenNumber TokenCloseSquare Indices 272 | { 273 | $$ = $4; 274 | $$->push_back($2); 275 | } 276 | Pointer: 277 | Type 278 | { 279 | $$ = $1; 280 | } 281 | | Pointer TokenMult 282 | { 283 | $$ = new Type(Type::KindPointer); 284 | $$->subtype = $1; 285 | $$->lltype = llvm::PointerType::get($1->lltype, 0); 286 | } 287 | Type: 288 | TokenBool 289 | { 290 | $$ = new Type(Type::KindBool); 291 | $$->lltype = llvm::Type::getInt1Ty(llvm::getGlobalContext()); 292 | } 293 | | TokenShort 294 | { 295 | $$ = new Type(Type::KindShort); 296 | $$->lltype = llvm::Type::getInt16Ty(llvm::getGlobalContext()); 297 | } 298 | | TokenInt 299 | { 300 | $$ = new Type(Type::KindInt); 301 | $$->lltype = llvm::Type::getInt32Ty(llvm::getGlobalContext()); 302 | } 303 | | TokenFloat 304 | { 305 | $$ = new Type(Type::KindFloat); 306 | $$->lltype = llvm::Type::getFloatTy(llvm::getGlobalContext()); 307 | } 308 | | TokenVoid 309 | { 310 | $$ = new Type(Type::KindVoid); 311 | $$->lltype = llvm::Type::getVoidTy(llvm::getGlobalContext()); 312 | } 313 | | TokenStruct TokenOpenCurly 314 | { 315 | // Push new symbol table to environment 316 | SymbolTable *symbol_table = new SymbolTable(SymbolTable::ScopeStruct); 317 | environment.push_back(symbol_table); 318 | // Create type 319 | $$ = new Type(Type::KindStruct); 320 | $$->symbol_table = symbol_table; 321 | } 322 | Declarations TokenCloseCurly 323 | { 324 | // Forward type 325 | $$ = $3; 326 | // LLVM structure 327 | SymbolTable *symbol_table = environment.back(); 328 | std::vector lltypes; 329 | symbol_table->getLLVMTypes(lltypes); 330 | $$->lltype = llvm::StructType::create(llvm::getGlobalContext(), lltypes); 331 | // Pop symbol table from environment 332 | environment.pop_back(); 333 | } 334 | Statements: 335 | | Statements Statement 336 | Statement: 337 | Expression TokenSemicolon 338 | | TokenReturn Expression TokenSemicolon 339 | { 340 | 341 | // Return statement, if not present 342 | if (!basic_block->getTerminator()){ 343 | 344 | // Check if the declared function return value type match the "return" value type 345 | if($2->getType() != module->begin()->getReturnType()) 346 | { 347 | std::cerr << "error: the declared function type does not match the return value type\n"; 348 | exit(1); 349 | } 350 | 351 | builder->CreateRet($2); 352 | } 353 | 354 | 355 | } 356 | | TokenMult Expression TokenEqual Expression TokenSemicolon 357 | { 358 | // Check valid pointer 359 | if (!$2->getType()->isPointerTy()) 360 | { 361 | std::cerr << "error: expression is not a pointer\n"; 362 | exit(1); 363 | } 364 | // Emit store 365 | builder->CreateStore($4, $2); 366 | } 367 | | LValue TokenEqual Expression TokenSemicolon 368 | { 369 | llvm::Value *lladdress = $1.llindices->size() > 1 ? 370 | builder->CreateGEP($1.lladdress, *$1.llindices, 371 | Symbol::getTemp()) : 372 | $1.lladdress; 373 | builder->CreateStore($3, lladdress); 374 | } 375 | | TokenOpenCurly 376 | { 377 | // Push new local symbol table 378 | SymbolTable *symbol_table = new SymbolTable(SymbolTable::ScopeLocal); 379 | environment.push_back(symbol_table); 380 | } 381 | Declarations Statements TokenCloseCurly 382 | { 383 | // Pop symbol table 384 | environment.pop_back(); 385 | } 386 | | IfStatement %prec TokenThen 387 | { 388 | // Emit unconditional to 'end' basic block 389 | builder->CreateBr($1.end_basic_block); 390 | // Move to 'end' basic block 391 | basic_block = $1.end_basic_block; 392 | builder->SetInsertPoint(basic_block); 393 | } 394 | | IfStatement TokenElse 395 | { 396 | // Create separate 'else' and 'end' basic blocks 397 | $$.then_basic_block = $1.then_basic_block; 398 | $$.else_basic_block = $1.else_basic_block; 399 | $$.end_basic_block = llvm::BasicBlock::Create( 400 | llvm::getGlobalContext(), 401 | Symbol::getBasicBlock(), 402 | function); 403 | // Emit unconditional branch to 'end' basic block 404 | builder->CreateBr($$.end_basic_block); 405 | // Move to 'else' basic block 406 | basic_block = $$.else_basic_block; 407 | builder->SetInsertPoint(basic_block); 408 | } 409 | Statement 410 | { 411 | // Emit unconditional branch to 'end' basic block 412 | builder->CreateBr($3.end_basic_block); 413 | // Move to 'end' basic block 414 | basic_block = $3.end_basic_block; 415 | builder->SetInsertPoint(basic_block); 416 | } 417 | | TokenWhile 418 | { 419 | // Create 'cond', 'body', and 'end' basic blocks 420 | $$.cond_basic_block = llvm::BasicBlock::Create( 421 | llvm::getGlobalContext(), 422 | Symbol::getBasicBlock(), 423 | function); 424 | $$.body_basic_block = llvm::BasicBlock::Create( 425 | llvm::getGlobalContext(), 426 | Symbol::getBasicBlock(), 427 | function); 428 | $$.end_basic_block = llvm::BasicBlock::Create( 429 | llvm::getGlobalContext(), 430 | Symbol::getBasicBlock(), 431 | function); 432 | // Emit unconditional branch 433 | builder->CreateBr($$.cond_basic_block); 434 | // Continue in 'cond' basic block 435 | basic_block = $$.cond_basic_block; 436 | builder->SetInsertPoint(basic_block); 437 | } 438 | TokenOpenPar Expression TokenClosePar 439 | { 440 | // Emit conditional branch 441 | builder->CreateCondBr($4, 442 | $2.body_basic_block, 443 | $2.end_basic_block); 444 | // Continue in 'body' basic block 445 | basic_block = $2.body_basic_block; 446 | builder->SetInsertPoint(basic_block); 447 | } 448 | Statement 449 | { 450 | // Emit unconditional branch 451 | builder->CreateBr($2.cond_basic_block); 452 | // Continue in 'end' basic block 453 | basic_block = $2.end_basic_block; 454 | builder->SetInsertPoint(basic_block); 455 | } 456 | IfStatement: 457 | TokenIf TokenOpenPar Expression TokenClosePar 458 | { 459 | // Create 'if' and 'else' basic blocks, assume 'end' is same as 'else'. 460 | $$.then_basic_block = llvm::BasicBlock::Create( 461 | llvm::getGlobalContext(), 462 | Symbol::getBasicBlock(), 463 | function); 464 | $$.else_basic_block = llvm::BasicBlock::Create( 465 | llvm::getGlobalContext(), 466 | Symbol::getBasicBlock(), 467 | function); 468 | $$.end_basic_block = $$.else_basic_block; 469 | // Emit conditional branch 470 | builder->CreateCondBr($3, 471 | $$.then_basic_block, 472 | $$.else_basic_block); 473 | // Continue in 'then' basic block 474 | basic_block = $$.then_basic_block; 475 | builder->SetInsertPoint(basic_block); 476 | } 477 | Statement 478 | { 479 | $$.then_basic_block = $5.then_basic_block; 480 | $$.else_basic_block = $5.else_basic_block; 481 | $$.end_basic_block = $5.end_basic_block; 482 | } 483 | Expression: 484 | LValue 485 | { 486 | llvm::Value *lladdress = $1.llindices->size() > 1 ? 487 | builder->CreateGEP($1.lladdress, *$1.llindices, 488 | Symbol::getTemp()) : 489 | $1.lladdress; 490 | $$ = builder->CreateLoad(lladdress, Symbol::getTemp()); 491 | } 492 | | TokenNumber 493 | { 494 | llvm::Type *lltype = llvm::Type::getInt32Ty(llvm::getGlobalContext()); 495 | $$ = llvm::ConstantInt::get(lltype, $1); 496 | } 497 | | TokenMult Expression 498 | { 499 | // Check valid pointer 500 | if (!$2->getType()->isPointerTy()) 501 | { 502 | std::cerr << "error: expression is not a pointer\n"; 503 | exit(1); 504 | } 505 | // Emit load 506 | $$ = builder->CreateLoad($2, Symbol::getTemp()); 507 | } 508 | | TokenMinus Expression 509 | { 510 | llvm::Type *lltype = llvm::Type::getInt32Ty(llvm::getGlobalContext()); 511 | llvm::Value *llvalue = llvm::ConstantInt::get(lltype, 0); 512 | $$ = builder->CreateBinOp(llvm::Instruction::Sub, llvalue, $2, Symbol::getTemp()); 513 | } 514 | | Expression TokenPlus Expression 515 | { 516 | $$ = builder->CreateBinOp(llvm::Instruction::Add, $1, $3, 517 | Symbol::getTemp()); 518 | } 519 | | Expression TokenMinus Expression 520 | { 521 | $$ = builder->CreateBinOp(llvm::Instruction::Sub, $1, $3, 522 | Symbol::getTemp()); 523 | } 524 | | Expression TokenLogicalShiftRight Expression 525 | { 526 | $$ = builder->CreateBinOp(llvm::Instruction::LShr, $1, $3, 527 | Symbol::getTemp()); 528 | } 529 | | Expression TokenBitwiseAnd Expression 530 | { 531 | $$ = builder->CreateBinOp(llvm::Instruction::And, $1, $3, 532 | Symbol::getTemp()); 533 | } 534 | | Expression TokenBitwiseXor Expression 535 | { 536 | $$ = builder->CreateBinOp(llvm::Instruction::Xor, $1, $3, 537 | Symbol::getTemp()); 538 | } 539 | | Expression TokenBitwiseOr Expression 540 | { 541 | $$ = builder->CreateBinOp(llvm::Instruction::Or, $1, $3, 542 | Symbol::getTemp()); 543 | } 544 | | Expression TokenMult Expression 545 | { 546 | $$ = builder->CreateBinOp(llvm::Instruction::Mul, $1, $3, 547 | Symbol::getTemp()); 548 | } 549 | | Expression TokenDiv Expression 550 | { 551 | $$ = builder->CreateBinOp(llvm::Instruction::SDiv, $1, $3, 552 | Symbol::getTemp()); 553 | } 554 | | TokenOpenPar Expression TokenClosePar 555 | { 556 | $$ = $2; 557 | } 558 | | Expression TokenGreaterThan Expression 559 | { 560 | $$ = builder->CreateICmpSGT($1, $3, Symbol::getTemp()); 561 | } 562 | | Expression TokenLessThan Expression 563 | { 564 | $$ = builder->CreateICmpSLT($1, $3, Symbol::getTemp()); 565 | } 566 | | Expression TokenGreaterEqual Expression 567 | { 568 | $$ = builder->CreateICmpSGE($1, $3, Symbol::getTemp()); 569 | } 570 | | Expression TokenLessEqual Expression 571 | { 572 | $$ = builder->CreateICmpSLE($1, $3, Symbol::getTemp()); 573 | } 574 | | Expression TokenDoubleEqual Expression 575 | { 576 | $$ = builder->CreateICmpEQ($1, $3, Symbol::getTemp()); 577 | } 578 | | Expression TokenNotEqual Expression 579 | { 580 | $$ = builder->CreateICmpNE($1, $3, Symbol::getTemp()); 581 | } 582 | | Expression TokenLogicalOr 583 | { 584 | // Save current basic block 585 | $$.lhs_basic_block = basic_block; 586 | // Create RHS and end basic blocks 587 | $$.rhs_basic_block = llvm::BasicBlock::Create( 588 | llvm::getGlobalContext(), 589 | Symbol::getBasicBlock(), 590 | function); 591 | $$.end_basic_block = llvm::BasicBlock::Create( 592 | llvm::getGlobalContext(), 593 | Symbol::getBasicBlock(), 594 | function); 595 | // Emit conditional branch 596 | builder->CreateCondBr($1, 597 | $$.end_basic_block, 598 | $$.rhs_basic_block); 599 | // Set current basic block to RHS 600 | basic_block = $$.rhs_basic_block; 601 | builder->SetInsertPoint(basic_block); 602 | } 603 | Expression 604 | { 605 | // Emit unconditional branch 606 | builder->CreateBr($3.end_basic_block); 607 | // Move to end basic block 608 | basic_block = $3.end_basic_block; 609 | builder->SetInsertPoint(basic_block); 610 | // Emit phi instruction 611 | llvm::PHINode *phi = builder->CreatePHI( 612 | llvm::IntegerType::getInt1Ty(llvm::getGlobalContext()), 613 | 2, Symbol::getTemp()); 614 | phi->addIncoming($1, $3.lhs_basic_block); 615 | phi->addIncoming($4, $3.rhs_basic_block); 616 | $$ = phi; 617 | } 618 | | Expression TokenLogicalAnd 619 | { 620 | // Save current basic block 621 | $$.lhs_basic_block = basic_block; 622 | // Create RHS and end basic blocks 623 | $$.rhs_basic_block = llvm::BasicBlock::Create( 624 | llvm::getGlobalContext(), 625 | Symbol::getBasicBlock(), 626 | function); 627 | $$.end_basic_block = llvm::BasicBlock::Create( 628 | llvm::getGlobalContext(), 629 | Symbol::getBasicBlock(), 630 | function); 631 | // Emit conditional branch 632 | builder->CreateCondBr($1, 633 | $$.rhs_basic_block, 634 | $$.end_basic_block); 635 | // Set current basic block to RHS 636 | basic_block = $$.rhs_basic_block; 637 | builder->SetInsertPoint(basic_block); 638 | } 639 | Expression 640 | { 641 | // Emit unconditional branch 642 | builder->CreateBr($3.end_basic_block); 643 | // Move to end basic block 644 | basic_block = $3.end_basic_block; 645 | builder->SetInsertPoint(basic_block); 646 | // Emit phi instruction 647 | llvm::PHINode *phi = builder->CreatePHI( 648 | llvm::IntegerType::getInt1Ty(llvm::getGlobalContext()), 649 | 2, Symbol::getTemp()); 650 | phi->addIncoming($1, $3.lhs_basic_block); 651 | phi->addIncoming($4, $3.rhs_basic_block); 652 | $$ = phi; 653 | } 654 | | TokenId TokenOpenPar ActualArguments TokenClosePar 655 | { 656 | // Search function in global scope 657 | SymbolTable *symbol_table = environment.front(); 658 | Symbol *symbol = symbol_table->getSymbol($1); 659 | // Undeclared, or not a function 660 | if (!symbol || symbol->type->getKind() != Type::KindFunction) 661 | { 662 | std::cerr << "Identifier is not a function: " << $1 << '\n'; 663 | exit(1); 664 | } 665 | // Invoke 666 | $$ = builder->CreateCall(symbol->lladdress, 667 | *$3, 668 | symbol->type->rettype->getKind() == Type::KindVoid ? 669 | "" : Symbol::getTemp()); 670 | } 671 | ActualArguments: 672 | { 673 | $$ = new std::vector(); 674 | } 675 | | ActualArgumentsComma Expression 676 | { 677 | $$ = $1; 678 | $$->push_back($2); 679 | } 680 | ActualArgumentsComma: 681 | { 682 | $$ = new std::vector(); 683 | } 684 | | ActualArgumentsComma Expression TokenComma 685 | { 686 | $$ = $1; 687 | $$->push_back($2); 688 | } 689 | LValue: 690 | TokenId 691 | { 692 | // Search symbol in environment, from the top to the bottom 693 | Symbol *symbol = nullptr; 694 | for (auto it = environment.rbegin(); 695 | it != environment.rend(); 696 | ++it) 697 | { 698 | SymbolTable *symbol_table = *it; 699 | symbol = symbol_table->getSymbol($1); 700 | if (symbol) 701 | break; 702 | } 703 | // Undeclared 704 | if (!symbol) 705 | { 706 | std::cerr << "Undeclared identifier: " << $1 << '\n'; 707 | exit(1); 708 | } 709 | // Save info 710 | $$.type = symbol->type; 711 | $$.lladdress = symbol->lladdress; 712 | $$.llindices = new std::vector(); 713 | // Add initial index set to 0 714 | llvm::Type *lltype = llvm::Type::getInt32Ty(llvm::getGlobalContext()); 715 | llvm::Value *llindex = llvm::ConstantInt::get(lltype, 0); 716 | $$.llindices->push_back(llindex); 717 | } 718 | | LValue TokenOpenSquare Expression TokenCloseSquare 719 | { 720 | // Check that L-value is array 721 | if ($1.type->getKind() != Type::KindArray) 722 | { 723 | std::cerr << "L-value is not an array\n"; 724 | exit(1); 725 | } 726 | // Add index 727 | $$.llindices = $1.llindices; 728 | $$.llindices->push_back($3); 729 | // Type and address 730 | $$.type = $1.type->subtype; 731 | $$.lladdress = $1.lladdress; 732 | } 733 | | LValue TokenPoint TokenId 734 | { 735 | // Check that L-value is a structure 736 | if ($1.type->getKind() != Type::KindStruct) 737 | { 738 | std::cerr << "L-value is not a struct\n"; 739 | exit(1); 740 | } 741 | // Find symbol in structure 742 | Symbol *symbol = $1.type->symbol_table->getSymbol($3); 743 | if (!symbol) 744 | { 745 | std::cerr << "Invalid field: " << $3 << '\n'; 746 | exit(1); 747 | } 748 | // Add index 749 | llvm::Type *lltype = llvm::Type::getInt32Ty(llvm::getGlobalContext()); 750 | llvm::Value *llindex = llvm::ConstantInt::get(lltype, symbol->index); 751 | $$.llindices = $1.llindices; 752 | $$.llindices->push_back(llindex); 753 | // Type and address 754 | $$.type = symbol->type; 755 | $$.lladdress = $1.lladdress; 756 | } 757 | %% 758 | 759 | int main(int argc, char **argv) 760 | { 761 | // Syntax 762 | if (argc != 2) 763 | { 764 | std::cerr << "Syntax: ./main \n"; 765 | exit(1); 766 | } 767 | // Open file in 'yyin' 768 | yyin = fopen(argv[1], "r"); 769 | if (!yyin) 770 | { 771 | std::cerr << "Cannot open file\n"; 772 | exit(1); 773 | } 774 | // LLVM context, builder, and module 775 | llvm::LLVMContext &context = llvm::getGlobalContext(); 776 | builder = new llvm::IRBuilder<>(context); 777 | module = new llvm::Module("TestModule", context); 778 | // Push global symbol table to environment 779 | SymbolTable *global_symbol_table = new SymbolTable(SymbolTable::ScopeGlobal); 780 | environment.push_back(global_symbol_table); 781 | // Parse input until there is no more 782 | do 783 | { 784 | yyparse(); 785 | } while (!feof(yyin)); 786 | // Dump module 787 | module->dump(); 788 | return 0; 789 | } 790 | 791 | void yyerror(const char *s) 792 | { 793 | std::cerr << s << std::endl; 794 | exit(1); 795 | } 796 | -------------------------------------------------------------------------------- /codegen/verilog.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @file verilog.cc 3 | * @Author Rafael Ubal (ubal@ece.neu.edu), Northeastern University 4 | * @Author Majid Sabbagh (sabbagh.m@husky.neu.edu), Northeastern University 5 | * @date Dec, 2016 6 | * @brief This class defines the verilog optimization pass. 7 | */ 8 | 9 | #include "llvm/Pass.h" 10 | #include "llvm/IR/Function.h" 11 | #include "llvm/IR/Instructions.h" 12 | #include "llvm/Support/raw_ostream.h" 13 | #include "llvm/Support/CFG.h" 14 | 15 | #include "CodeBlock.h" 16 | #include "Module.h" 17 | #include "DataFlow.h" 18 | 19 | #include 20 | 21 | 22 | namespace 23 | { 24 | 25 | class VERILOGPass : public llvm::FunctionPass 26 | { 27 | public: 28 | 29 | // Identifier 30 | static char ID; 31 | 32 | // verilog module 33 | verilog::Module *verilog_module; 34 | 35 | verilog::Wire *verilog_result = new verilog::Wire("result", verilog::Wire::DirectionOutput); 36 | 37 | std::string widthStr = ""; 38 | // Constructor. The first argument of the parent constructor is 39 | // a unique pass identifier. 40 | VERILOGPass() : llvm::FunctionPass(ID) { } 41 | 42 | // Virtual function overridden to implement the pass functionality. 43 | bool runOnFunction(llvm::Function &llvm_function) override; 44 | 45 | void TranslateBasicBlock(llvm::BasicBlock *llvm_basic_block, 46 | verilog::CodeBlock *verilog_code_block); 47 | 48 | void TranslateInstruction(llvm::Instruction *llvm_instruction, 49 | verilog::CodeBlock *verilog_code_block); 50 | }; 51 | 52 | 53 | bool VERILOGPass::runOnFunction(llvm::Function &llvm_function) 54 | { 55 | // Create VERILOG module 56 | verilog_module = new verilog::Module(); 57 | 58 | // Add 'entry' code block 59 | verilog::CodeBlock *verilog_entry_code_block = verilog_module->getEntryCodeBlock(); 60 | 61 | // Emit "module (ports);" 62 | verilog::DataFlow *verilog_portliststart = new verilog::DataFlow(verilog::DataFlow::OpcodePortListStart); 63 | verilog::Wire *verilog_wire = new verilog::Wire(llvm_function.getName(), verilog::Wire::DirectionInvalid); 64 | verilog_portliststart->addArgument(verilog_wire); 65 | verilog_entry_code_block->addDataFlow(verilog_portliststart); 66 | 67 | for (auto& functionArgument : llvm_function.getArgumentList()) 68 | { 69 | // Wire support, add register support later 70 | verilog::DataFlow *verilog_dataflow = new verilog::DataFlow(verilog::DataFlow::OpcodeInputPortDefine); 71 | verilog::Wire *verilog_wire = new verilog::Wire(functionArgument.getName(), verilog::Wire::DirectionInput); 72 | llvm::Type *type = functionArgument.getType(); 73 | if (type->isIntegerTy(32)) 74 | { 75 | verilog_wire->setWidth(32); 76 | } 77 | else if (type->isIntegerTy(16)) 78 | { 79 | verilog_wire->setWidth(16); 80 | } 81 | else if (type->isIntegerTy(8)) 82 | { 83 | verilog_wire->setWidth(8); 84 | } 85 | else if (type->isIntegerTy(1)) 86 | { 87 | verilog_wire->setWidth(1); 88 | } 89 | else 90 | { 91 | std::cerr << "Unsupported type in function arguments\n"; 92 | exit(1); 93 | } 94 | verilog_module->WireAddSymbol(functionArgument.getName(), verilog_wire); 95 | verilog_dataflow->addArgument(verilog_wire); 96 | verilog_entry_code_block->addDataFlow(verilog_dataflow); 97 | } 98 | 99 | verilog::DataFlow *verilog_dataflow_out = new verilog::DataFlow(verilog::DataFlow::OpcodeOutputPortDefine); 100 | llvm::Type *type = llvm_function.getReturnType(); 101 | if (type->isIntegerTy(32)) 102 | { 103 | verilog_result->setWidth(32); 104 | } 105 | else if (type->isIntegerTy(16)) 106 | { 107 | verilog_result->setWidth(16); 108 | } 109 | else if (type->isIntegerTy(8)) 110 | { 111 | verilog_result->setWidth(8); 112 | } 113 | else if (type->isIntegerTy(1)) 114 | { 115 | verilog_result->setWidth(1); 116 | } 117 | else 118 | { 119 | std::cerr << "Unsupported type in function arguments\n"; 120 | exit(1); 121 | } 122 | verilog_dataflow_out->addArgument(verilog_result); 123 | verilog_entry_code_block->addDataFlow(verilog_dataflow_out); 124 | 125 | //wrap up the module port list ");" 126 | verilog::DataFlow *verilog_portlistend = new verilog::DataFlow(verilog::DataFlow::OpcodePortListEnd); 127 | verilog_entry_code_block->addDataFlow(verilog_portlistend); 128 | 129 | verilog_module->addCodeBlock(verilog_entry_code_block); 130 | 131 | // Create all basic blocks 132 | for (llvm::Function::iterator llvm_basic_block = llvm_function.begin(), 133 | e = llvm_function.end(); 134 | llvm_basic_block != e; 135 | ++llvm_basic_block) 136 | { 137 | verilog::CodeBlock *verilog_code_block = 138 | new verilog::CodeBlock(llvm_basic_block->getName()); 139 | verilog_module->addCodeBlock(verilog_code_block); 140 | } 141 | 142 | // Set first code block as successor of module's entry basic block 143 | llvm::BasicBlock *llvm_first_basic_block = &llvm_function.getEntryBlock(); 144 | verilog::CodeBlock *verilog_first_code_block = verilog_module->getCodeBlock( 145 | llvm_first_basic_block->getName()); 146 | verilog_entry_code_block->addSuccessor(verilog_first_code_block); 147 | 148 | // Code generation for code blocks 149 | for (llvm::Function::iterator llvm_basic_block = llvm_function.begin(), 150 | e = llvm_function.end(); 151 | llvm_basic_block != e; 152 | ++llvm_basic_block) 153 | { 154 | verilog::CodeBlock *verilog_code_block = 155 | verilog_module->getCodeBlock( 156 | llvm_basic_block->getName()); 157 | TranslateBasicBlock(llvm_basic_block, verilog_code_block); 158 | } 159 | 160 | // Add 'exit' code block 161 | verilog::CodeBlock *verilog_exit_code_block = verilog_module->getExitCodeBlock(); 162 | verilog_module->addCodeBlock(verilog_exit_code_block); 163 | 164 | // Emit 'endmodule' in 'exit' code block 165 | verilog::DataFlow *verilog_dataflow = new verilog::DataFlow( 166 | verilog::DataFlow::OpcodeEndModule); 167 | verilog_exit_code_block->addDataFlow(verilog_dataflow); 168 | 169 | // Print verilog module 170 | verilog_module->dump(); 171 | 172 | // Function was not modified 173 | return false; 174 | } 175 | 176 | 177 | void VERILOGPass::TranslateBasicBlock(llvm::BasicBlock *llvm_basic_block, 178 | verilog::CodeBlock *verilog_code_block) 179 | { 180 | // Traverse instructions 181 | for (llvm::BasicBlock::iterator llvm_instruction = llvm_basic_block->begin(), 182 | e = llvm_basic_block->end(); 183 | llvm_instruction != e; 184 | ++llvm_instruction) 185 | { 186 | TranslateInstruction(llvm_instruction, verilog_code_block); 187 | } 188 | } 189 | 190 | 191 | void VERILOGPass::TranslateInstruction(llvm::Instruction *llvm_instruction, 192 | verilog::CodeBlock *verilog_code_block) 193 | { 194 | switch (llvm_instruction->getOpcode()) 195 | { 196 | case llvm::Instruction::Alloca: 197 | { 198 | // Get alloca instruction 199 | llvm::AllocaInst *alloca_inst = llvm::cast 200 | (llvm_instruction); 201 | 202 | // Check type 203 | llvm::Type *type = alloca_inst->getAllocatedType(); 204 | if (!type->isIntegerTy(32)) 205 | { 206 | std::cerr << "Unsupported type in alloca\n"; 207 | exit(1); 208 | } 209 | 210 | // Get 'entry' and 'exit' code blocks 211 | verilog::DataFlow *verilog_dataflow; 212 | verilog::CodeBlock *verilog_entry_code_block = verilog_module-> 213 | getEntryCodeBlock(); 214 | verilog::CodeBlock *verilog_exit_code_block = verilog_module-> 215 | getExitCodeBlock(); 216 | 217 | // Emit 'addi $sp, $sp, -4' in '__entry' basic block 218 | // mips_instruction = new mips::Instruction( 219 | // mips::Instruction::OpcodeAddi); 220 | // mips_instruction->addArgument(new mips::Register(29, 221 | // mips::Register::DirectionOutput)); 222 | // mips_instruction->addArgument(new mips::Register(29, 223 | // mips::Register::DirectionInput)); 224 | // mips_instruction->addArgument(new mips::Constant(-4)); 225 | // mips_entry_basic_block->addInstruction(mips_instruction); 226 | 227 | // Emit 'move $temp, $sp' in 'entry' basic block. 228 | // Store '$temp' in symbol table 229 | verilog_dataflow = new verilog::DataFlow(verilog::DataFlow::OpcodeSignalDefine); 230 | // Currently only supports wire signals, can be extended to support registers 231 | // and sequential logic 232 | verilog::Wire *dest = verilog::Wire::newWire( 233 | verilog::Wire::DirectionLhs); 234 | verilog_dataflow->addArgument(dest); 235 | verilog_dataflow->addArgument(new verilog::Wire("wire0", 236 | verilog::Wire::DirectionLhs)); 237 | verilog_entry_code_block->addDataFlow(verilog_dataflow); 238 | verilog_module->WireAddSymbol(llvm_instruction->getName(), dest); 239 | 240 | 241 | break; 242 | } 243 | 244 | case llvm::Instruction::Add: 245 | { 246 | // Destination wire 247 | verilog::Wire *verilog_dest = verilog::Wire::newWire( 248 | verilog::Wire::DirectionLhs); 249 | verilog_module->WireAddSymbol(llvm_instruction->getName(), verilog_dest); 250 | 251 | // First operand 252 | llvm::Value *llvm_src1 = llvm_instruction->getOperand(0); 253 | verilog::Wire *verilog_src1 = verilog_module->translateLLVMValueWire( 254 | verilog_code_block, 255 | llvm_src1, 256 | verilog::Wire::DirectionRhs); 257 | 258 | // Second operand 259 | llvm::Value *llvm_src2 = llvm_instruction->getOperand(1); 260 | verilog::Wire *verilog_src2 = verilog_module->translateLLVMValueWire( 261 | verilog_code_block, 262 | llvm_src2, 263 | verilog::Wire::DirectionRhs); 264 | 265 | 266 | verilog::DataFlow *verilog_signaldef = new verilog::DataFlow(verilog::DataFlow::OpcodeSignalDefine); 267 | llvm::Type *type = llvm_instruction->getType(); 268 | if (type->isIntegerTy(32)) 269 | { 270 | verilog_dest->setWidth(32); 271 | } 272 | else if (type->isIntegerTy(16)) 273 | { 274 | verilog_dest->setWidth(16); 275 | } 276 | else if (type->isIntegerTy(8)) 277 | { 278 | verilog_dest->setWidth(8); 279 | } 280 | else if (type->isIntegerTy(1)) 281 | { 282 | verilog_dest->setWidth(1); 283 | } 284 | else 285 | { 286 | std::cerr << "Unsupported type in temporay registers\n"; 287 | exit(1); 288 | } 289 | verilog_code_block->addDataFlow(verilog_signaldef); 290 | verilog_signaldef->addArgument(verilog_dest); 291 | 292 | // Emit '>' operator 293 | verilog::DataFlow *verilog_dataflow = 294 | new verilog::DataFlow( 295 | verilog::DataFlow::OpcodeAdd); 296 | verilog_code_block->addDataFlow(verilog_dataflow); 297 | verilog_dataflow->addArgument(verilog_dest); 298 | 299 | // src1 and src2 300 | verilog_dataflow->addArgument(verilog_src1); 301 | verilog_dataflow->addArgument(verilog_src2); 302 | break; 303 | } 304 | 305 | case llvm::Instruction::Sub: 306 | { 307 | // Destination wire 308 | verilog::Wire *verilog_dest = verilog::Wire::newWire( 309 | verilog::Wire::DirectionLhs); 310 | verilog_module->WireAddSymbol(llvm_instruction->getName(), verilog_dest); 311 | 312 | // First operand 313 | llvm::Value *llvm_src1 = llvm_instruction->getOperand(0); 314 | verilog::Wire *verilog_src1 = verilog_module->translateLLVMValueWire( 315 | verilog_code_block, 316 | llvm_src1, 317 | verilog::Wire::DirectionRhs); 318 | 319 | // Second operand 320 | llvm::Value *llvm_src2 = llvm_instruction->getOperand(1); 321 | verilog::Wire *verilog_src2 = verilog_module->translateLLVMValueWire( 322 | verilog_code_block, 323 | llvm_src2, 324 | verilog::Wire::DirectionRhs); 325 | 326 | 327 | verilog::DataFlow *verilog_signaldef = new verilog::DataFlow(verilog::DataFlow::OpcodeSignalDefine); 328 | llvm::Type *type = llvm_instruction->getType(); 329 | if (type->isIntegerTy(32)) 330 | { 331 | verilog_dest->setWidth(32); 332 | } 333 | else if (type->isIntegerTy(16)) 334 | { 335 | verilog_dest->setWidth(16); 336 | } 337 | else if (type->isIntegerTy(8)) 338 | { 339 | verilog_dest->setWidth(8); 340 | } 341 | else if (type->isIntegerTy(1)) 342 | { 343 | verilog_dest->setWidth(1); 344 | } 345 | else 346 | { 347 | std::cerr << "Unsupported type in temporay registers\n"; 348 | exit(1); 349 | } 350 | verilog_code_block->addDataFlow(verilog_signaldef); 351 | verilog_signaldef->addArgument(verilog_dest); 352 | 353 | // Emit '>' operator 354 | verilog::DataFlow *verilog_dataflow = 355 | new verilog::DataFlow( 356 | verilog::DataFlow::OpcodeSub); 357 | verilog_code_block->addDataFlow(verilog_dataflow); 358 | verilog_dataflow->addArgument(verilog_dest); 359 | 360 | // src1 and src2 361 | verilog_dataflow->addArgument(verilog_src1); 362 | verilog_dataflow->addArgument(verilog_src2); 363 | break; 364 | } 365 | case llvm::Instruction::LShr: 366 | { 367 | // Destination wire 368 | verilog::Wire *verilog_dest = verilog::Wire::newWire( 369 | verilog::Wire::DirectionLhs); 370 | verilog_module->WireAddSymbol(llvm_instruction->getName(), verilog_dest); 371 | 372 | // First operand 373 | llvm::Value *llvm_src1 = llvm_instruction->getOperand(0); 374 | verilog::Wire *verilog_src1 = verilog_module->translateLLVMValueWire( 375 | verilog_code_block, 376 | llvm_src1, 377 | verilog::Wire::DirectionRhs); 378 | 379 | // Second operand 380 | llvm::Value *llvm_src2 = llvm_instruction->getOperand(1); 381 | verilog::Wire *verilog_src2 = verilog_module->translateLLVMValueWire( 382 | verilog_code_block, 383 | llvm_src2, 384 | verilog::Wire::DirectionRhs); 385 | 386 | 387 | verilog::DataFlow *verilog_signaldef = new verilog::DataFlow(verilog::DataFlow::OpcodeSignalDefine); 388 | llvm::Type *type = llvm_instruction->getType(); 389 | if (type->isIntegerTy(32)) 390 | { 391 | verilog_dest->setWidth(32); 392 | } 393 | else if (type->isIntegerTy(16)) 394 | { 395 | verilog_dest->setWidth(16); 396 | } 397 | else if (type->isIntegerTy(8)) 398 | { 399 | verilog_dest->setWidth(8); 400 | } 401 | else if (type->isIntegerTy(1)) 402 | { 403 | verilog_dest->setWidth(1); 404 | } 405 | else 406 | { 407 | std::cerr << "Unsupported type in temporay registers\n"; 408 | exit(1); 409 | } 410 | verilog_code_block->addDataFlow(verilog_signaldef); 411 | verilog_signaldef->addArgument(verilog_dest); 412 | 413 | // Emit '>' operator 414 | verilog::DataFlow *verilog_dataflow = 415 | new verilog::DataFlow( 416 | verilog::DataFlow::OpcodeLshr); 417 | verilog_code_block->addDataFlow(verilog_dataflow); 418 | verilog_dataflow->addArgument(verilog_dest); 419 | 420 | // src1 and src2 421 | verilog_dataflow->addArgument(verilog_src1); 422 | verilog_dataflow->addArgument(verilog_src2); 423 | break; 424 | } 425 | case llvm::Instruction::Xor: 426 | { 427 | // Destination wire 428 | verilog::Wire *verilog_dest = verilog::Wire::newWire( 429 | verilog::Wire::DirectionLhs); 430 | verilog_module->WireAddSymbol(llvm_instruction->getName(), verilog_dest); 431 | 432 | // First operand 433 | llvm::Value *llvm_src1 = llvm_instruction->getOperand(0); 434 | verilog::Wire *verilog_src1 = verilog_module->translateLLVMValueWire( 435 | verilog_code_block, 436 | llvm_src1, 437 | verilog::Wire::DirectionRhs); 438 | 439 | // Second operand 440 | llvm::Value *llvm_src2 = llvm_instruction->getOperand(1); 441 | verilog::Wire *verilog_src2 = verilog_module->translateLLVMValueWire( 442 | verilog_code_block, 443 | llvm_src2, 444 | verilog::Wire::DirectionRhs); 445 | 446 | 447 | verilog::DataFlow *verilog_signaldef = new verilog::DataFlow(verilog::DataFlow::OpcodeSignalDefine); 448 | llvm::Type *type = llvm_instruction->getType(); 449 | if (type->isIntegerTy(32)) 450 | { 451 | verilog_dest->setWidth(32); 452 | } 453 | else if (type->isIntegerTy(16)) 454 | { 455 | verilog_dest->setWidth(16); 456 | } 457 | else if (type->isIntegerTy(8)) 458 | { 459 | verilog_dest->setWidth(8); 460 | } 461 | else if (type->isIntegerTy(1)) 462 | { 463 | verilog_dest->setWidth(1); 464 | } 465 | else 466 | { 467 | std::cerr << "Unsupported type in temporay registers\n"; 468 | exit(1); 469 | } 470 | verilog_code_block->addDataFlow(verilog_signaldef); 471 | verilog_signaldef->addArgument(verilog_dest); 472 | 473 | // Emit '>' operator 474 | verilog::DataFlow *verilog_dataflow = 475 | new verilog::DataFlow( 476 | verilog::DataFlow::OpcodeXor); 477 | verilog_code_block->addDataFlow(verilog_dataflow); 478 | verilog_dataflow->addArgument(verilog_dest); 479 | 480 | // src1 and src2 481 | verilog_dataflow->addArgument(verilog_src1); 482 | verilog_dataflow->addArgument(verilog_src2); 483 | break; 484 | } 485 | case llvm::Instruction::And: 486 | { 487 | // Destination wire 488 | verilog::Wire *verilog_dest = verilog::Wire::newWire( 489 | verilog::Wire::DirectionLhs); 490 | verilog_module->WireAddSymbol(llvm_instruction->getName(), verilog_dest); 491 | 492 | // First operand 493 | llvm::Value *llvm_src1 = llvm_instruction->getOperand(0); 494 | verilog::Wire *verilog_src1 = verilog_module->translateLLVMValueWire( 495 | verilog_code_block, 496 | llvm_src1, 497 | verilog::Wire::DirectionRhs); 498 | 499 | // Second operand 500 | llvm::Value *llvm_src2 = llvm_instruction->getOperand(1); 501 | verilog::Wire *verilog_src2 = verilog_module->translateLLVMValueWire( 502 | verilog_code_block, 503 | llvm_src2, 504 | verilog::Wire::DirectionRhs); 505 | 506 | 507 | verilog::DataFlow *verilog_signaldef = new verilog::DataFlow(verilog::DataFlow::OpcodeSignalDefine); 508 | llvm::Type *type = llvm_instruction->getType(); 509 | if (type->isIntegerTy(32)) 510 | { 511 | verilog_dest->setWidth(32); 512 | } 513 | else if (type->isIntegerTy(16)) 514 | { 515 | verilog_dest->setWidth(16); 516 | } 517 | else if (type->isIntegerTy(8)) 518 | { 519 | verilog_dest->setWidth(8); 520 | } 521 | else if (type->isIntegerTy(1)) 522 | { 523 | verilog_dest->setWidth(1); 524 | } 525 | else 526 | { 527 | std::cerr << "Unsupported type in temporay registers\n"; 528 | exit(1); 529 | } 530 | verilog_code_block->addDataFlow(verilog_signaldef); 531 | verilog_signaldef->addArgument(verilog_dest); 532 | 533 | // Emit '>' operator 534 | verilog::DataFlow *verilog_dataflow = 535 | new verilog::DataFlow( 536 | verilog::DataFlow::OpcodeAnd); 537 | verilog_code_block->addDataFlow(verilog_dataflow); 538 | verilog_dataflow->addArgument(verilog_dest); 539 | 540 | // src1 and src2 541 | verilog_dataflow->addArgument(verilog_src1); 542 | verilog_dataflow->addArgument(verilog_src2); 543 | break; 544 | } 545 | case llvm::Instruction::Or: 546 | { 547 | // Destination wire 548 | verilog::Wire *verilog_dest = verilog::Wire::newWire( 549 | verilog::Wire::DirectionLhs); 550 | verilog_module->WireAddSymbol(llvm_instruction->getName(), verilog_dest); 551 | 552 | // First operand 553 | llvm::Value *llvm_src1 = llvm_instruction->getOperand(0); 554 | verilog::Wire *verilog_src1 = verilog_module->translateLLVMValueWire( 555 | verilog_code_block, 556 | llvm_src1, 557 | verilog::Wire::DirectionRhs); 558 | 559 | // Second operand 560 | llvm::Value *llvm_src2 = llvm_instruction->getOperand(1); 561 | verilog::Wire *verilog_src2 = verilog_module->translateLLVMValueWire( 562 | verilog_code_block, 563 | llvm_src2, 564 | verilog::Wire::DirectionRhs); 565 | 566 | 567 | verilog::DataFlow *verilog_signaldef = new verilog::DataFlow(verilog::DataFlow::OpcodeSignalDefine); 568 | llvm::Type *type = llvm_instruction->getType(); 569 | if (type->isIntegerTy(32)) 570 | { 571 | verilog_dest->setWidth(32); 572 | } 573 | else if (type->isIntegerTy(16)) 574 | { 575 | verilog_dest->setWidth(16); 576 | } 577 | else if (type->isIntegerTy(8)) 578 | { 579 | verilog_dest->setWidth(8); 580 | } 581 | else if (type->isIntegerTy(1)) 582 | { 583 | verilog_dest->setWidth(1); 584 | } 585 | else 586 | { 587 | std::cerr << "Unsupported type in temporay registers\n"; 588 | exit(1); 589 | } 590 | verilog_code_block->addDataFlow(verilog_signaldef); 591 | verilog_signaldef->addArgument(verilog_dest); 592 | 593 | // Emit '>' operator 594 | verilog::DataFlow *verilog_dataflow = 595 | new verilog::DataFlow( 596 | verilog::DataFlow::OpcodeOr); 597 | verilog_code_block->addDataFlow(verilog_dataflow); 598 | verilog_dataflow->addArgument(verilog_dest); 599 | 600 | // src1 and src2 601 | verilog_dataflow->addArgument(verilog_src1); 602 | verilog_dataflow->addArgument(verilog_src2); 603 | break; 604 | } 605 | case llvm::Instruction::ICmp: 606 | { 607 | // Destination wire 608 | verilog::Wire *verilog_dest = verilog::Wire::newWire( 609 | verilog::Wire::DirectionLhs); 610 | verilog_module->WireAddSymbol(llvm_instruction->getName(), verilog_dest); 611 | 612 | // First operand 613 | llvm::Value *llvm_src1 = llvm_instruction->getOperand(0); 614 | verilog::Wire *verilog_src1 = verilog_module->translateLLVMValueWire( 615 | verilog_code_block, 616 | llvm_src1, 617 | verilog::Wire::DirectionRhs); 618 | 619 | // Second operand 620 | llvm::Value *llvm_src2 = llvm_instruction->getOperand(1); 621 | verilog::Wire *verilog_src2 = verilog_module->translateLLVMValueWire( 622 | verilog_code_block, 623 | llvm_src2, 624 | verilog::Wire::DirectionRhs); 625 | 626 | // Operation depending on condition 627 | llvm::ICmpInst *icmp_instruction = llvm::cast 628 | (llvm_instruction); 629 | llvm::CmpInst::Predicate pred = icmp_instruction->getPredicate(); 630 | switch (pred) 631 | { 632 | 633 | case llvm::CmpInst::ICMP_EQ: 634 | { 635 | 636 | verilog::DataFlow *verilog_signaldef = new verilog::DataFlow(verilog::DataFlow::OpcodeSignalDefine); 637 | llvm::Type *type = llvm_instruction->getType(); 638 | if (type->isIntegerTy(32)) 639 | { 640 | verilog_dest->setWidth(32); 641 | } 642 | else if (type->isIntegerTy(16)) 643 | { 644 | verilog_dest->setWidth(16); 645 | } 646 | else if (type->isIntegerTy(8)) 647 | { 648 | verilog_dest->setWidth(8); 649 | } 650 | else if (type->isIntegerTy(1)) 651 | { 652 | verilog_dest->setWidth(1); 653 | } 654 | else 655 | { 656 | std::cerr << "Unsupported type in temporay registers\n"; 657 | exit(1); 658 | } 659 | verilog_code_block->addDataFlow(verilog_signaldef); 660 | verilog_signaldef->addArgument(verilog_dest); 661 | 662 | // Emit '>' operator 663 | verilog::DataFlow *verilog_dataflow = 664 | new verilog::DataFlow( 665 | verilog::DataFlow::OpcodeEq); 666 | verilog_code_block->addDataFlow(verilog_dataflow); 667 | verilog_dataflow->addArgument(verilog_dest); 668 | 669 | // src1 and src2 670 | verilog_dataflow->addArgument(verilog_src1); 671 | verilog_dataflow->addArgument(verilog_src2); 672 | break; 673 | } 674 | case llvm::CmpInst::ICMP_SGT: 675 | { 676 | 677 | verilog::DataFlow *verilog_signaldef = new verilog::DataFlow(verilog::DataFlow::OpcodeSignalDefine); 678 | llvm::Type *type = llvm_instruction->getType(); 679 | if (type->isIntegerTy(32)) 680 | { 681 | verilog_dest->setWidth(32); 682 | } 683 | else if (type->isIntegerTy(16)) 684 | { 685 | verilog_dest->setWidth(16); 686 | } 687 | else if (type->isIntegerTy(8)) 688 | { 689 | verilog_dest->setWidth(8); 690 | } 691 | else if (type->isIntegerTy(1)) 692 | { 693 | verilog_dest->setWidth(1); 694 | } 695 | else 696 | { 697 | std::cerr << "Unsupported type in temporay registers\n"; 698 | exit(1); 699 | } 700 | verilog_code_block->addDataFlow(verilog_signaldef); 701 | verilog_signaldef->addArgument(verilog_dest); 702 | 703 | // Emit '>' operator 704 | verilog::DataFlow *verilog_dataflow = 705 | new verilog::DataFlow( 706 | verilog::DataFlow::OpcodeSgt); 707 | verilog_code_block->addDataFlow(verilog_dataflow); 708 | verilog_dataflow->addArgument(verilog_dest); 709 | 710 | // src1 and src2 711 | verilog_dataflow->addArgument(verilog_src1); 712 | verilog_dataflow->addArgument(verilog_src2); 713 | break; 714 | } 715 | 716 | default: 717 | 718 | std::cerr << "icmp predicate not supported\n"; 719 | exit(1); 720 | } 721 | break; 722 | } 723 | 724 | 725 | case llvm::Instruction::Ret: 726 | { 727 | // Emit 'assign output = finalresult' 728 | verilog::DataFlow *dataflow = new verilog::DataFlow( 729 | verilog::DataFlow::OpcodeAssign); 730 | // return value 731 | // verilog::Wire *verilog_dest = verilog::Wire::newWire( 732 | // verilog::Wire::DirectionOutput); 733 | verilog_module->WireAddSymbol(llvm_instruction->getName(), verilog_result); 734 | 735 | dataflow->addArgument(verilog_result); 736 | 737 | // src operand 738 | llvm::Value *llvm_src1 = llvm_instruction->getOperand(0); 739 | verilog::Wire *verilog_src1 = verilog_module->translateLLVMValueWire( 740 | verilog_code_block, 741 | llvm_src1, 742 | verilog::Wire::DirectionInput); 743 | 744 | dataflow->addArgument(verilog_src1); 745 | 746 | verilog_code_block->addDataFlow(dataflow); 747 | 748 | // Set exit basic block as successor 749 | verilog_code_block->addSuccessor(verilog_module->getExitCodeBlock()); 750 | break; 751 | } 752 | 753 | default: 754 | 755 | std::cerr << "Unsupported LLVM instruction: "; 756 | llvm_instruction->dump(); 757 | std::cerr << '\n'; 758 | exit(1); 759 | } 760 | } 761 | 762 | 763 | // Pass identifier 764 | char VERILOGPass::ID = 0; 765 | 766 | // Pass registration 767 | static llvm::RegisterPass X("verilog", 768 | "verilog code generation pass", 769 | false, 770 | false); 771 | 772 | } 773 | 774 | --------------------------------------------------------------------------------