From c003bcc59a5caf0d182152e94f48dc95d95fa773 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 7 Jul 2020 23:23:39 -0700 Subject: [PATCH] Add support for <-> in constant and procedural contexts --- PExpr.cc | 4 +-- design_dump.cc | 6 +++++ elab_expr.cc | 4 ++- eval_tree.cc | 64 ++++++++++++++++----------------------------- expr_synth.cc | 10 ++++++- lexor.lex | 3 ++- netlist.h | 1 - netmisc.cc | 10 ++++--- parse.y | 20 +++++++++++--- tgt-vlog95/expr.c | 13 ++++++++- tgt-vvp/eval_vec4.c | 40 +++++++++++++++++++++++++++- 11 files changed, 118 insertions(+), 57 deletions(-) diff --git a/PExpr.cc b/PExpr.cc index af9a1999c..51c0de605 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2019 Stephen Williams + * Copyright (c) 1998-2020 Stephen Williams * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -168,7 +168,7 @@ PEBComp::~PEBComp() PEBLogic::PEBLogic(char op, PExpr*l, PExpr*r) : PEBinary(op, l, r) { - assert(op == 'a' || op == 'o'); + assert(op == 'a' || op == 'o' || op == 'q' || op == 'Q'); } PEBLogic::~PEBLogic() diff --git a/design_dump.cc b/design_dump.cc index 82551cdc6..582eb628c 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1714,6 +1714,12 @@ void NetEBinary::dump(ostream&o) const case 'p': o << "**"; break; + case 'q': + o << "->"; + break; + case 'Q': + o << "<->"; + break; case 'r': o << ">>"; break; diff --git a/elab_expr.cc b/elab_expr.cc index c0ccc2d7b..548aff873 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2020 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -410,6 +410,8 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des, case 'a': case 'o': + case 'q': + case 'Q': cerr << get_fileline() << ": internal error: " << "Elaboration of " << human_readable_op(op_) << " Should have been handled in NetEBLogic::elaborate." diff --git a/eval_tree.cc b/eval_tree.cc index 2e2fac3f1..9f89559e7 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2020 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -808,44 +808,10 @@ NetExpr* NetEBDiv::eval_arguments_(const NetExpr*l, const NetExpr*r) const return tmp; } -NetEConst* NetEBLogic::eval_tree_real_(const NetExpr*l, const NetExpr*r) const -{ - double lval; - double rval; - - bool flag = get_real_arguments(l, r, lval, rval); - if (! flag) return 0; - - verinum::V res; - switch (op_) { - case 'a': // Logical AND (&&) - if ((lval != 0.0) && (rval != 0.0)) - res = verinum::V1; - else - res = verinum::V0; - break; - - case 'o': // Logical OR (||) - if ((lval != 0.0) || (rval != 0.0)) - res = verinum::V1; - else - res = verinum::V0; - break; - - default: - return 0; - } - - NetEConst*tmp = new NetEConst(verinum(res, 1)); - ivl_assert(*this, tmp); - eval_debug(this, tmp, true); - return tmp; -} - NetEConst* NetEBLogic::eval_arguments_(const NetExpr*l, const NetExpr*r) const { - if (l->expr_type() == IVL_VT_REAL || r->expr_type() == IVL_VT_REAL) - return eval_tree_real_(l,r); + // NetEBLogic arguments should have already been reduced so real is not possible. + ivl_assert(*this, (l->expr_type() != IVL_VT_REAL) && (r->expr_type() != IVL_VT_REAL)); assert(expr_type() == IVL_VT_LOGIC); const NetEConst*lc = dynamic_cast(l); @@ -878,25 +844,39 @@ NetEConst* NetEBLogic::eval_arguments_(const NetExpr*l, const NetExpr*r) const case 'a': // Logical AND (&&) if ((lv == verinum::V0) || (rv == verinum::V0)) res = verinum::V0; - else if ((lv == verinum::V1) && (rv == verinum::V1)) res = verinum::V1; - else res = verinum::Vx; - break; case 'o': // Logical OR (||) if ((lv == verinum::V1) || (rv == verinum::V1)) res = verinum::V1; - else if ((lv == verinum::V0) && (rv == verinum::V0)) res = verinum::V0; - else res = verinum::Vx; + break; + case 'q': // Logical implication (->) + if ((lv == verinum::V0) || (rv == verinum::V1)) + res = verinum::V1; + else if ((lv == verinum::V1) && (rv == verinum::V0)) + res = verinum::V0; + else + res = verinum::Vx; + break; + + case 'Q': // Logical equivalence (<->) + if (((lv == verinum::V0) && (rv == verinum::V0)) || + ((lv == verinum::V1) && (rv == verinum::V1))) + res = verinum::V1; + else if (((lv == verinum::V0) && (rv == verinum::V1)) || + ((lv == verinum::V1) && (rv == verinum::V0))) + res = verinum::V0; + else + res = verinum::Vx; break; default: diff --git a/expr_synth.cc b/expr_synth.cc index c3860ee94..fddb2e371 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2018 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2020 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -545,6 +545,14 @@ NetNet* NetEBLogic::synthesize(Design*des, NetScope*scope, NetExpr*root) return 0; } + if ((op() == 'q') || (op() == 'Q')) { + cerr << get_fileline() << ": sorry: " + << human_readable_op(op_) + << " is not currently supported in this context." << endl; + des->errors += 1; + return 0; + } + netvector_t*osig_tmp = new netvector_t(expr_type()); NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::IMPLICIT, osig_tmp); diff --git a/lexor.lex b/lexor.lex index f69ed6dca..7f1134b6c 100644 --- a/lexor.lex +++ b/lexor.lex @@ -4,7 +4,7 @@ %{ /* - * Copyright (c) 1998-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2020 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -208,6 +208,7 @@ TU [munpf] "!=?" { return K_WNE; } "||" { return K_LOR; } "&&" { return K_LAND; } +"<->" { return K_LEQUIV; } "&&&" { return K_TAND; } "~|" { return K_NOR; } "~^" { return K_NXOR; } diff --git a/netlist.h b/netlist.h index 1ec6abe8f..264e793b6 100644 --- a/netlist.h +++ b/netlist.h @@ -4258,7 +4258,6 @@ class NetEBLogic : public NetEBinary { private: NetEConst* eval_arguments_(const NetExpr*l, const NetExpr*r) const; - NetEConst* eval_tree_real_(const NetExpr*l, const NetExpr*r) const; }; /* diff --git a/netmisc.cc b/netmisc.cc index d09df82eb..75892b257 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2020 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -1336,9 +1336,11 @@ const char *human_readable_op(const char op, bool unary) case '|': type = "|"; break; // Bitwise OR case 'O': type = "~|"; break; // NOR - case '!': type = "!"; break; // Logical NOT - case 'a': type = "&&"; break; // Logical AND - case 'o': type = "||"; break; // Logical OR + case '!': type = "!"; break; // Logical NOT + case 'a': type = "&&"; break; // Logical AND + case 'o': type = "||"; break; // Logical OR + case 'q': type = "->"; break; // Logical implication + case 'Q': type = "<->"; break; // Logical equivalence case 'e': type = "=="; break; case 'n': type = "!="; break; diff --git a/parse.y b/parse.y index d498b0c89..24053919d 100644 --- a/parse.y +++ b/parse.y @@ -476,7 +476,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %token K_CONTRIBUTE %token K_PO_POS K_PO_NEG K_POW %token K_PSTAR K_STARP K_DOTSTAR -%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER +%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER K_LEQUIV %token K_SCOPE_RES %token K_edge_descriptor @@ -688,8 +688,9 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type genvar_iteration %token K_TAND -%right K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ -%right K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ +%nonassoc K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ +%nonassoc K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ +%right K_TRIGGER K_LEQUIV %right '?' ':' K_inside %left K_LOR %left K_LAND @@ -3689,6 +3690,19 @@ expression FILE_NAME(tmp, @2); $$ = tmp; } +/* + FIXME: This creates shift/reduce issues that need to be solved + | expression K_TRIGGER attribute_list_opt expression + { PEBinary*tmp = new PEBLogic('q', $1, $4); + FILE_NAME(tmp, @2); + $$ = tmp; + } +*/ + | expression K_LEQUIV attribute_list_opt expression + { PEBinary*tmp = new PEBLogic('Q', $1, $4); + FILE_NAME(tmp, @2); + $$ = tmp; + } | expression '?' attribute_list_opt expression ':' expression { PETernary*tmp = new PETernary($1, $4, $6); FILE_NAME(tmp, @2); diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index e0fcbad7f..c3265391c 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2019 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2020 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -500,6 +500,17 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid, fprintf(vlog_out, " %s ", oper); emit_expr(scope, oper2, ivl_expr_width(oper2), 0, 1, 0); break; + case 'q': // The arguments have already been reduced + fprintf(vlog_out, "!"); + emit_expr(scope, oper1, ivl_expr_width(oper1), 0, 1, 0); + fprintf(vlog_out, " || "); + emit_expr(scope, oper2, ivl_expr_width(oper2), 0, 1, 0); + break; + case 'Q': // The arguments have already been reduced + emit_expr(scope, oper1, ivl_expr_width(oper1), 0, 1, 0); + fprintf(vlog_out, " ~^ "); + emit_expr(scope, oper2, ivl_expr_width(oper2), 0, 1, 0); + break; case 'R': if (! allow_signed) { fprintf(stderr, "%s:%u: vlog95 error: >>> operator is not " diff --git a/tgt-vvp/eval_vec4.c b/tgt-vvp/eval_vec4.c index 899ee478b..0a097f4cb 100644 --- a/tgt-vvp/eval_vec4.c +++ b/tgt-vvp/eval_vec4.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 2013-2020 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -409,6 +409,36 @@ static void draw_binary_vec4_compare(ivl_expr_t expr) } } +static void draw_binary_vec4_limpl(ivl_expr_t expr) +{ + fprintf(stderr, "vvp.tgt sorry: No support for logical implication (%s:%u).\n", + ivl_expr_file(expr), ivl_expr_lineno(expr)); + assert(0); +} + +static void draw_binary_vec4_lequiv(ivl_expr_t expr) +{ + ivl_expr_t le = ivl_expr_oper1(expr); + ivl_expr_t re = ivl_expr_oper2(expr); + + /* Push the left expression. Reduce it to a single bit if + necessary. */ + draw_eval_vec4(le); + if (ivl_expr_width(le) > 1) + fprintf(vvp_out, " %%or/r;\n"); + + /* Now push the right expression. Again, reduce to a single + bit if necessary. */ + draw_eval_vec4(re); + if (ivl_expr_width(re) > 1) + fprintf(vvp_out, " %%or/r;\n"); + + fprintf(vvp_out, " %%xnor;\n"); + + if (ivl_expr_width(expr) > 1) + fprintf(vvp_out, " %%pad/u %u;\n", ivl_expr_width(expr)); +} + static void draw_binary_vec4_land(ivl_expr_t expr) { ivl_expr_t le = ivl_expr_oper1(expr); @@ -719,6 +749,14 @@ static void draw_binary_vec4(ivl_expr_t expr) draw_binary_vec4_lor(expr); break; + case 'q': /* -> (logical implication) */ + draw_binary_vec4_limpl(expr); + break; + + case 'Q': /* <-> (logical equivalence) */ + draw_binary_vec4_lequiv(expr); + break; + default: fprintf(stderr, "vvp.tgt error: unsupported binary (%c)\n", ivl_expr_opcode(expr));