diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 2623edf92..a8b6caf2b 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -163,6 +163,9 @@ void ExpArithmetic::dump(ostream&out, int indent) const case POW: fun_name = "**"; break; + case CONCAT: + fun_name = "&"; + break; } out << setw(indent) << "" << "Arithmetic " << fun_name @@ -183,6 +186,16 @@ void ExpBinary::dump_operands(ostream&out, int indent) const operand2_->dump(out, indent); } +void ExpBitstring::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "Bit string " << value_.size() + << "b\""; + for (size_t idx = value_.size() ; idx > 0 ; idx -= 1) { + out << value_[idx-1]; + } + out << "\""; +} + void ExpCharacter::dump(ostream&out, int indent) const { out << setw(indent) << "" << "Character '" << value_ << "'" diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 912e21a16..af95ba537 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -21,6 +21,7 @@ # include "scope.h" # include # include +# include # include using namespace std; @@ -161,11 +162,27 @@ bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const return false; case POW: return false; + case CONCAT: + return false; } return true; } +/* + * Store bitstrings in little-endian order. + */ +ExpBitstring::ExpBitstring(const char*val) +: value_(strlen(val)) +{ + for (size_t idx = value_.size() ; idx > 0 ; idx -= 1) + value_[idx-1] = *val++; +} + +ExpBitstring::~ExpBitstring() +{ +} + ExpCharacter::ExpCharacter(char val) : value_(val) { diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index c04b17bfb..018b7e2a6 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -22,6 +22,7 @@ # include "StringHeap.h" # include "LineInfo.h" # include +# include class Entity; class Architecture; @@ -146,7 +147,7 @@ class ExpBinary : public Expression { class ExpArithmetic : public ExpBinary { public: - enum fun_t { PLUS, MINUS, MULT, DIV, MOD, REM, POW }; + enum fun_t { PLUS, MINUS, MULT, DIV, MOD, REM, POW, CONCAT }; public: ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2); @@ -177,6 +178,19 @@ class ExpAttribute : public Expression { perm_string name_; }; +class ExpBitstring : public Expression { + + public: + explicit ExpBitstring(const char*); + ~ExpBitstring(); + + int emit(ostream&out, Entity*ent, Architecture*arc); + void dump(ostream&out, int indent = 0) const; + + private: + std::vectorvalue_; +}; + class ExpCharacter : public Expression { public: diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 545c7df08..2557196e4 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -101,6 +101,9 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc) case REM: out << " /* ?remainder? */ "; break; + case CONCAT: + out << " /* ?concat? */ "; + break; } errors += emit_operand2(out, ent, arc); @@ -108,6 +111,13 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } +int ExpBitstring::emit(ostream&out, Entity*, Architecture*) +{ + int errors = 0; + errors += 1; + return errors; +} + int ExpCharacter::emit(ostream&out, Entity*, Architecture*) { const VType*etype = peek_type(); diff --git a/vhdlpp/lexor.lex b/vhdlpp/lexor.lex index 4aa64c19b..ed28d0d32 100644 --- a/vhdlpp/lexor.lex +++ b/vhdlpp/lexor.lex @@ -54,6 +54,7 @@ static char* escape_apostrophe_and_dup(char* text); static double make_double_from_based(char* text); static int64_t make_long_from_based(char* text); +static char* make_bitstring_literal(const char*text); static int64_t lpow(int64_t left, int64_t right); static unsigned short short_from_hex_char(char ch); @@ -175,6 +176,10 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])* } } +{integer}?[sSuU]?[xXbBoOdD]\"[^\"]+\" { + yylval.text = make_bitstring_literal(yytext); + return BITSTRING_LITERAL; +} /* Compound symbols */ "<=" { return LEQ; } @@ -381,6 +386,237 @@ static char* escape_apostrophe_and_dup(char* text) return newstr; } +static char*make_bitstring_bin(int width_prefix, bool sflag, bool, + const char*src) +{ + int src_len = strlen(src); + if (width_prefix < 0) + width_prefix = src_len; + + char*res = new char[width_prefix+1]; + char*rp = res; + + if (width_prefix > src_len) { + size_t pad = width_prefix - src_len; + for (size_t idx = 0 ; idx < pad ; idx += 1) + *rp++ = sflag? src[0] : '0'; + + } else if (src_len > width_prefix) { + src += src_len - width_prefix; + } + + while (*src) { + *rp++ = *src++; + } + + return res; +} + +static char*make_bitstring_oct(int width_prefix, bool sflag, bool, + const char*src) +{ + int src_len = strlen(src); + if (width_prefix < 0) + width_prefix = 3*src_len; + + char*res = new char[width_prefix+1]; + char*rp = res + width_prefix; + *rp = 0; + rp -= 1; + + for (const char*sp = src + src_len - 1; sp >= src ; sp -= 1) { + int val; + switch (*sp) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + val = *sp - '0'; + *rp-- = (val&1)? '1' : '0'; + if (rp >= res) *rp-- = (val&2)? '1' : '0'; + if (rp >= res) *rp-- = (val&4)? '1' : '0'; + break; + default: + *rp-- = *sp; + if (rp >= res) *rp-- = *sp; + if (rp >= res) *rp-- = *sp; + break; + } + if (rp < res) + break; + } + + if (rp >= res) { + char pad = sflag? src[0] : '0'; + while (rp >= res) + *rp-- = pad; + } + + return res; +} + +static char*make_bitstring_hex(int width_prefix, bool sflag, bool, + const char*src) +{ + int src_len = strlen(src); + if (width_prefix <= 0) + width_prefix = 4*src_len; + + char*res = new char[width_prefix+1]; + char*rp = res + width_prefix; + *rp = 0; + rp -= 1; + + for (const char*sp = src + src_len - 1; sp >= src ; sp -= 1) { + int val; + switch (*sp) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + val = *sp - '0'; + *rp-- = (val&1)? '1' : '0'; + if (rp >= res) *rp-- = (val&2)? '1' : '0'; + if (rp >= res) *rp-- = (val&4)? '1' : '0'; + if (rp >= res) *rp-- = (val&8)? '1' : '0'; + break; + case 'a': case 'A': + case 'b': case 'B': + case 'c': case 'C': + case 'd': case 'D': + case 'e': case 'E': + case 'f': case 'F': + val = 10 + toupper(*sp) - 'A'; + *rp-- = (val&1)? '1' : '0'; + if (rp >= res) *rp-- = (val&2)? '1' : '0'; + if (rp >= res) *rp-- = (val&4)? '1' : '0'; + if (rp >= res) *rp-- = (val&8)? '1' : '0'; + break; + default: + *rp-- = *sp; + if (rp >= res) *rp-- = *sp; + if (rp >= res) *rp-- = *sp; + break; + } + if (rp < res) + break; + } + + if (rp >= res) { + char pad = sflag? src[0] : '0'; + while (rp >= res) + *rp-- = pad; + } + + return res; +} + +static char*make_bitstring_dec(int, bool, bool, const char*) +{ + assert(0); + return 0; +} + +static char* make_bitstring_literal(const char*text) +{ + int width_prefix = -1; + const char*cp = text; + bool signed_flag = false; + bool unsigned_flag = false; + unsigned base = 0; + + // Parse out the explicit width, if present. + if (size_t len = strspn(cp, "0123456789")) { + width_prefix = 0; + while (len > 0) { + width_prefix *= 10; + width_prefix += *cp - '0'; + cp += 1; + } + } else { + width_prefix = -1; + } + + // Detect and s/u flags. + if (*cp == 's' || *cp == 'S') { + signed_flag = true; + cp += 1; + } else if (*cp == 'u' || *cp == 'U') { + unsigned_flag = true; + cp += 1; + } + + // Now get the base marker. + switch (*cp) { + case 'b': + case 'B': + base = 2; + break; + case 'o': + case 'O': + base = 8; + break; + case 'x': + case 'X': + base = 16; + break; + case 'd': + case 'D': + base = 10; + break; + default: + assert(0); + } + cp += 1; + + char*simplified = new char [strlen(cp) + 1]; + char*dp = simplified; + assert(*cp == '"'); + cp += 1; + + while (*cp && *cp != '"') { + if (*cp == '_') { + cp += 1; + continue; + } + + *dp++ = *cp++; + } + *dp = 0; + + char*res; + switch (base) { + case 2: + res = make_bitstring_bin(width_prefix, signed_flag, unsigned_flag, simplified); + break; + case 8: + res = make_bitstring_oct(width_prefix, signed_flag, unsigned_flag, simplified); + break; + case 10: + res = make_bitstring_dec(width_prefix, signed_flag, unsigned_flag, simplified); + break; + case 16: + res = make_bitstring_hex(width_prefix, signed_flag, unsigned_flag, simplified); + break; + default: + assert(0); + res = 0; + } + + delete[]simplified; + return res; +} + /** * This function takes a floating point based number * in form of a C-strings and converts it to a double. diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 78b97b7e2..c78a2e226 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -169,7 +169,7 @@ const VType*parse_type_by_name(perm_string name) %token IDENTIFIER %token INT_LITERAL %token REAL_LITERAL -%token STRING_LITERAL CHARACTER_LITERAL +%token STRING_LITERAL CHARACTER_LITERAL BITSTRING_LITERAL /* compound symbols */ %token LEQ GEQ VASSIGN NE BOX EXP ARROW DLT DGT @@ -275,10 +275,19 @@ architecture_statement_part ; association_element - : IDENTIFIER ARROW name + : IDENTIFIER ARROW expression { named_expr_t*tmp = new named_expr_t(lex_strings.make($1), $3); delete[]$1; $$ = tmp; + } + | IDENTIFIER ARROW K_open + { sorrymsg(@3, "Port map \"open\" not supported.\n"); + $$ = 0; + } + | IDENTIFIER ARROW error + { errormsg(@3, "Invalid target for port map association.\n"); + yyerrok; + $$ = 0; } ; @@ -443,6 +452,16 @@ concurrent_signal_assignment_statement $$ = tmp; delete $3; } + | name LEQ waveform K_when expression K_else waveform ';' + { ExpName*name = dynamic_cast ($1); + assert(name); + SignalAssignment*tmp = new SignalAssignment(name, *$3); + FILE_NAME(tmp, @1); + + $$ = tmp; + delete $3; + sorrymsg(@4, "Conditional signal assignment not supported here.\n"); + } | name LEQ error ';' { errormsg(@2, "Syntax error in signal assignment waveform.\n"); delete $1; @@ -755,15 +774,15 @@ identifier_opt : IDENTIFIER { $$ = $1; } | { $$ = 0; } ; if_statement : K_if expression K_then sequence_of_statements - if_statement_else + if_statement_elsif_list_opt if_statement_else K_end K_if ';' - { IfSequential*tmp = new IfSequential($2, $4, $5); + { IfSequential*tmp = new IfSequential($2, $4, $6); FILE_NAME(tmp, @1); $$ = tmp; } | K_if error K_then sequence_of_statements - if_statement_else + if_statement_elsif_list_opt if_statement_else K_end K_if ';' { errormsg(@2, "Error in if_statement condition expression.\n"); yyerrok; @@ -772,7 +791,7 @@ if_statement } | K_if expression K_then error K_end K_if ';' - { errormsg(@2, "Too many errors in sequence within if_statement.\n"); + { errormsg(@4, "Too many errors in sequence within if_statement.\n"); yyerrok; $$ = 0; } @@ -784,9 +803,33 @@ if_statement } ; +if_statement_elsif_list_opt + : if_statement_elsif_list + | + ; + +if_statement_elsif_list + : if_statement_elsif_list if_statement_elsif + | if_statement_elsif + ; + +if_statement_elsif + : K_elsif expression K_then sequence_of_statements + { sorrymsg(@1, "elsif sub-statements are not supported.\n"); } + | K_elsif expression K_then error + { errormsg(@4, "Too many errors in elsif sub-statements.\n"); + yyerrok; + } + ; + if_statement_else : K_else sequence_of_statements { $$ = $2; } + | K_else error + { errormsg(@2, "Too many errors in else sub-statements.\n"); + yyerrok; + $$ = 0; + } | { $$ = 0; } ; @@ -1004,8 +1047,7 @@ port_map_aspect : K_port K_map '(' association_list ')' { $$ = $4; } | K_port K_map '(' error ')' - { - errormsg(@1, "Syntax error in port map aspect.\n"); + { errormsg(@1, "Syntax error in port map aspect.\n"); } ; @@ -1053,6 +1095,12 @@ primary FILE_NAME(tmp, @1); $$ = tmp; } + | BITSTRING_LITERAL + { ExpBitstring*tmp = new ExpBitstring($1); + FILE_NAME(tmp, @1); + delete[]$1; + $$ = tmp; + } | '(' expression ')' { $$ = $2; } ; @@ -1248,6 +1296,11 @@ simple_expression FILE_NAME(tmp, @2); $$ = tmp; } + | term '&' term + { ExpArithmetic*tmp = new ExpArithmetic(ExpArithmetic::CONCAT, $1, $3); + FILE_NAME(tmp, @2); + $$ = tmp; + } ; signal_assignment_statement @@ -1257,6 +1310,12 @@ signal_assignment_statement delete $3; $$ = tmp; } + | name LEQ waveform K_when expression K_else waveform ';' + { SignalSeqAssignment*tmp = new SignalSeqAssignment($1, $3); + FILE_NAME(tmp, @1); + sorrymsg(@4, "Conditional signal assignment not supported.\n"); + $$ = tmp; + } ; subtype_declaration