Skip to content

Commit

Permalink
Add support for the wild compare operators ==? and !=?
Browse files Browse the repository at this point in the history
  • Loading branch information
caryr committed Nov 18, 2017
1 parent d23b046 commit 3fc9ad2
Show file tree
Hide file tree
Showing 28 changed files with 465 additions and 51 deletions.
18 changes: 15 additions & 3 deletions design_dump.cc
Expand Up @@ -187,9 +187,15 @@ ostream& operator << (ostream&fd, NetCaseCmp::kind_t that)
case NetCaseCmp::NEQ:
fd << "!==";
break;
case NetCaseCmp::XEQ:
case NetCaseCmp::WEQ:
fd << "==?";
break;
case NetCaseCmp::WNE:
fd << "!=?";
break;
case NetCaseCmp::XEQ:
fd << "==x?";
break;
case NetCaseCmp::ZEQ:
fd << "==z?";
break;
Expand Down Expand Up @@ -1631,11 +1637,14 @@ void NetEBinary::dump(ostream&o) const
case 'A':
o << "~&";
break;
case 'e':
o << "==";
break;
case 'E':
o << "===";
break;
case 'e':
o << "==";
case 'w':
o << "==?";
break;
case 'G':
o << ">=";
Expand All @@ -1652,6 +1661,9 @@ void NetEBinary::dump(ostream&o) const
case 'N':
o << "!==";
break;
case 'W':
o << "!=?";
break;
case 'o':
o << "||";
break;
Expand Down
14 changes: 14 additions & 0 deletions elab_expr.cc
Expand Up @@ -329,10 +329,12 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, width_mode_t&mode)
case '>': // > Should be handled by PEBComp
case 'e': // == Should be handled by PEBComp
case 'E': // === Should be handled by PEBComp
case 'w': // ==? Should be handled by PEBComp
case 'L': // <= Should be handled by PEBComp
case 'G': // >= Should be handled by PEBComp
case 'n': // != Should be handled by PEBComp
case 'N': // !== Should be handled by PEBComp
case 'W': // !=? Should be handled by PEBComp
case 'p': // ** should be handled by PEBPower
ivl_assert(*this, 0);
default:
Expand Down Expand Up @@ -668,6 +670,18 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
break;
case 'w': /* ==? */
case 'W': /* !=? */
if ((lp->expr_type() != IVL_VT_BOOL && lp->expr_type() != IVL_VT_LOGIC) ||
(rp->expr_type() != IVL_VT_BOOL && rp->expr_type() != IVL_VT_LOGIC)) {
cerr << get_fileline() << ": error: "
<< human_readable_op(op_)
<< " operator may only have INTEGRAL operands."
<< endl;
des->errors += 1;
return 0;
}
break;
default:
break;
}
Expand Down
63 changes: 61 additions & 2 deletions eval_tree.cc
Expand Up @@ -571,7 +571,8 @@ NetEConst* NetEBComp::eval_eqeq_(bool ne_flag, const NetExpr*le, const NetExpr*r

verinum::V res = eq_res;

assert(lv.len() == rv.len());
// The two expressions should already be padded to the same size.
ivl_assert(*this, lv.len() == rv.len());

for (unsigned idx = 0 ; idx < lv.len() ; idx += 1) {

Expand Down Expand Up @@ -626,7 +627,8 @@ NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr

verinum::V res = verinum::V1;

assert(lv.len() == rv.len());
// The two expressions should already be padded to the same size.
ivl_assert(*this, lv.len() == rv.len());

for (unsigned idx = 0 ; idx < lv.len() ; idx += 1)
if (lv.get(idx) != rv.get(idx)) {
Expand All @@ -644,6 +646,55 @@ NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr
return result;
}

NetEConst* NetEBComp::eval_weqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const
{
const NetEConst*lc = dynamic_cast<const NetEConst*>(le);
const NetEConst*rc = dynamic_cast<const NetEConst*>(re);
if (lc == 0 || rc == 0) return 0;

const verinum&lv = lc->value();
const verinum&rv = rc->value();

const verinum::V eq_res = ne_flag ? verinum::V0 : verinum::V1;
const verinum::V ne_res = ne_flag ? verinum::V1 : verinum::V0;

verinum::V res = eq_res;

// The two expressions should already be padded to the same size.
ivl_assert(*this, lv.len() == rv.len());

for (unsigned idx = 0 ; idx < lv.len() ; idx += 1) {
// An X or Z in the R-value matches any L-value.
switch (rv.get(idx)) {
case verinum::Vx:
case verinum::Vz:
continue;
default:
break;
}

// An X or Z in the L-value that is not matches by an R-value X/Z returns undefined.
switch (lv.get(idx)) {
case verinum::Vx:
case verinum::Vz:
res = verinum::Vx;
continue;
default:
break;
}

// A hard (0/1) mismatch gives a not-equal result.
if (rv.get(idx) != lv.get(idx)) {
res = ne_res;
break;
}
}

NetEConst*result = new NetEConst(verinum(res, 1));
ivl_assert(*this, result);
return result;
}

NetEConst* NetEBComp::eval_arguments_(const NetExpr*l, const NetExpr*r) const
{
NetEConst*res = 0;
Expand All @@ -657,6 +708,10 @@ NetEConst* NetEBComp::eval_arguments_(const NetExpr*l, const NetExpr*r) const
res = eval_eqeq_(false, l, r);
break;

case 'w': // Wild equality (==?)
res = eval_weqeq_(false, l, r);
break;

case 'G': // >=
res = eval_gteq_(l, r);
break;
Expand All @@ -673,6 +728,10 @@ NetEConst* NetEBComp::eval_arguments_(const NetExpr*l, const NetExpr*r) const
res = eval_eqeq_(true, l, r);
break;

case 'W': // Wild not-equal (!=?)
res = eval_weqeq_(true, l, r);
break;

case '<': // Less than
res = eval_less_(l, r);
break;
Expand Down
13 changes: 12 additions & 1 deletion expr_synth.cc
Expand Up @@ -274,7 +274,18 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, NetExpr*root)

if (op_ == 'E' || op_ == 'N') {
NetCaseCmp*gate = new NetCaseCmp(scope, scope->local_symbol(),
width, op_=='E'?NetCaseCmp::EEQ:NetCaseCmp::NEQ);
width, op_=='E' ? NetCaseCmp::EEQ : NetCaseCmp::NEQ);
gate->set_line(*this);
connect(gate->pin(0), osig->pin(0));
connect(gate->pin(1), lsig->pin(0));
connect(gate->pin(2), rsig->pin(0));
des->add_node(gate);
return osig;
}

if (op_ == 'w' || op_ == 'W') {
NetCaseCmp*gate = new NetCaseCmp(scope, scope->local_symbol(),
width, op_=='w' ? NetCaseCmp::WEQ : NetCaseCmp::WNE);
gate->set_line(*this);
connect(gate->pin(0), osig->pin(0));
connect(gate->pin(1), lsig->pin(0));
Expand Down
6 changes: 4 additions & 2 deletions ivl_target.h
@@ -1,7 +1,7 @@
#ifndef IVL_ivl_target_H
#define IVL_ivl_target_H
/*
* Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2017 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
Expand Down Expand Up @@ -306,8 +306,10 @@ typedef enum ivl_lpm_type_e {
IVL_LPM_CONCAT = 16,
IVL_LPM_CONCATZ = 36, /* Transparent concat */
IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */
IVL_LPM_CMP_EQX= 37, /* Wildcard EQ (==?) */
IVL_LPM_CMP_EQX= 37, /* Wildcard EQ (casex) */
IVL_LPM_CMP_EQZ= 38, /* casez EQ */
IVL_LPM_CMP_WEQ= 41,
IVL_LPM_CMP_WNE= 42,
IVL_LPM_CMP_EQ = 10,
IVL_LPM_CMP_GE = 1,
IVL_LPM_CMP_GT = 2,
Expand Down
2 changes: 2 additions & 0 deletions lexor.lex
Expand Up @@ -188,6 +188,8 @@ TU [munpf]
"!=" { return K_NE; }
"===" { return K_CEQ; }
"!==" { return K_CNE; }
"==?" { return K_WEQ; }
"!=?" { return K_WNE; }
"||" { return K_LOR; }
"&&" { return K_LAND; }
"&&&" { return K_TAND; }
Expand Down
3 changes: 3 additions & 0 deletions netlist.h
Expand Up @@ -2365,6 +2365,8 @@ class NetCaseCmp : public NetNode {
enum kind_t {
EEQ, // ===
NEQ, // !==
WEQ, // ==?
WNE, // !=?
XEQ, // casex guard tests
ZEQ // casez guard tests
};
Expand Down Expand Up @@ -4137,6 +4139,7 @@ class NetEBComp : public NetEBinary {
NetEConst*eval_gt_(const NetExpr*le, const NetExpr*re) const;
NetEConst*eval_gteq_(const NetExpr*le, const NetExpr*re) const;
NetEConst*eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const;
NetEConst*eval_weqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const;
};

/*
Expand Down
2 changes: 2 additions & 0 deletions netmisc.cc
Expand Up @@ -1260,6 +1260,8 @@ const char *human_readable_op(const char op, bool unary)
if (unary) type = "~|"; // NOR
else type = "!=="; // Case inequality
break;
case 'w': type = "==?"; break; // Wild equality
case 'W': type = "!=?"; break; // Wild inequality

case 'l': type = "<<(<)"; break; // Left shifts
case 'r': type = ">>"; break; // Logical right shift
Expand Down
14 changes: 12 additions & 2 deletions parse.y
Expand Up @@ -465,7 +465,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
%token <number> BASED_NUMBER DEC_NUMBER UNBASED_NUMBER
%token <realtime> REALTIME
%token K_PLUS_EQ K_MINUS_EQ K_INCR K_DECR
%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LP K_LS K_RS K_RSS K_SG
%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_WEQ K_WNE K_LP K_LS K_RS K_RSS K_SG
/* K_CONTRIBUTE is <+, the contribution assign. */
%token K_CONTRIBUTE
%token K_PO_POS K_PO_NEG K_POW
Expand Down Expand Up @@ -678,7 +678,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
%left '|'
%left '^' K_NXOR K_NOR
%left '&' K_NAND
%left K_EQ K_NE K_CEQ K_CNE
%left K_EQ K_NE K_CEQ K_CNE K_WEQ K_WNE
%left K_GE K_LE '<' '>'
%left K_LS K_RS K_RSS
%left '+' '-'
Expand Down Expand Up @@ -3284,6 +3284,11 @@ expression
FILE_NAME(tmp, @2);
$$ = tmp;
}
| expression K_WEQ attribute_list_opt expression
{ PEBinary*tmp = new PEBComp('w', $1, $4);
FILE_NAME(tmp, @2);
$$ = tmp;
}
| expression K_LE attribute_list_opt expression
{ PEBinary*tmp = new PEBComp('L', $1, $4);
FILE_NAME(tmp, @2);
Expand All @@ -3304,6 +3309,11 @@ expression
FILE_NAME(tmp, @2);
$$ = tmp;
}
| expression K_WNE attribute_list_opt expression
{ PEBinary*tmp = new PEBComp('W', $1, $4);
FILE_NAME(tmp, @2);
$$ = tmp;
}
| expression K_LOR attribute_list_opt expression
{ PEBinary*tmp = new PEBLogic('o', $1, $4);
FILE_NAME(tmp, @2);
Expand Down
6 changes: 6 additions & 0 deletions t-dll-api.cc
Expand Up @@ -1235,6 +1235,8 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
case IVL_LPM_CMP_GT:
case IVL_LPM_CMP_NE:
case IVL_LPM_CMP_NEE:
case IVL_LPM_CMP_WEQ:
case IVL_LPM_CMP_WNE:
case IVL_LPM_DIVIDE:
case IVL_LPM_MOD:
case IVL_LPM_MULT:
Expand Down Expand Up @@ -1390,6 +1392,8 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net)
case IVL_LPM_CMP_EQX:
case IVL_LPM_CMP_EQZ:
case IVL_LPM_CMP_NEE:
case IVL_LPM_CMP_WEQ:
case IVL_LPM_CMP_WNE:
case IVL_LPM_DIVIDE:
case IVL_LPM_MOD:
case IVL_LPM_MULT:
Expand Down Expand Up @@ -1540,6 +1544,8 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
case IVL_LPM_CMP_GT:
case IVL_LPM_CMP_NE:
case IVL_LPM_CMP_NEE:
case IVL_LPM_CMP_WEQ:
case IVL_LPM_CMP_WNE:
case IVL_LPM_DIVIDE:
case IVL_LPM_MOD:
case IVL_LPM_MULT:
Expand Down
6 changes: 6 additions & 0 deletions t-dll.cc
Expand Up @@ -1244,6 +1244,12 @@ void dll_target::net_case_cmp(const NetCaseCmp*net)
case NetCaseCmp::NEQ:
obj->type = IVL_LPM_CMP_NEE;
break;
case NetCaseCmp::WEQ:
obj->type = IVL_LPM_CMP_WEQ;
break;
case NetCaseCmp::WNE:
obj->type = IVL_LPM_CMP_WNE;
break;
case NetCaseCmp::XEQ:
obj->type = IVL_LPM_CMP_EQX;
break;
Expand Down
10 changes: 9 additions & 1 deletion tgt-stub/stub.c
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2017 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
Expand Down Expand Up @@ -394,6 +394,12 @@ static void show_lpm_cmp_eeq(ivl_lpm_t net)
case IVL_LPM_CMP_NEE:
str = "NEE";
break;
case IVL_LPM_CMP_WEQ:
str = "WEQ";
break;
case IVL_LPM_CMP_WNE:
str = "WNE";
break;
default:
assert(0);
break;
Expand Down Expand Up @@ -1043,6 +1049,8 @@ static void show_lpm(ivl_lpm_t net)
case IVL_LPM_CMP_EQX:
case IVL_LPM_CMP_EQZ:
case IVL_LPM_CMP_NEE:
case IVL_LPM_CMP_WEQ:
case IVL_LPM_CMP_WNE:
show_lpm_cmp_eeq(net);
break;

Expand Down

0 comments on commit 3fc9ad2

Please sign in to comment.