Add support for the wild compare operators ==? and !=?

This commit is contained in:
Cary R 2017-11-17 19:32:09 -08:00
parent d23b046203
commit 3fc9ad2db0
28 changed files with 465 additions and 51 deletions

View File

@ -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;
@ -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 << ">=";
@ -1652,6 +1661,9 @@ void NetEBinary::dump(ostream&o) const
case 'N':
o << "!==";
break;
case 'W':
o << "!=?";
break;
case 'o':
o << "||";
break;

View File

@ -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:
@ -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;
}

View File

@ -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) {
@ -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)) {
@ -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;
@ -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;
@ -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;

View File

@ -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));

View File

@ -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
@ -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,

View File

@ -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; }

View File

@ -2365,6 +2365,8 @@ class NetCaseCmp : public NetNode {
enum kind_t {
EEQ, // ===
NEQ, // !==
WEQ, // ==?
WNE, // !=?
XEQ, // casex guard tests
ZEQ // casez guard tests
};
@ -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;
};
/*

View File

@ -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

14
parse.y
View File

@ -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
@ -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 '+' '-'
@ -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);
@ -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);

View File

@ -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:
@ -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:
@ -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:

View File

@ -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;

View File

@ -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
@ -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;
@ -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;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2014 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2011-2017 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
@ -44,8 +44,10 @@ static expr_sign_t expr_get_binary_sign_type(ivl_expr_t expr)
switch (ivl_expr_opcode(expr)) {
case 'E':
case 'e':
case 'w':
case 'N':
case 'n':
case 'W':
case '<':
case 'L':
case '>':
@ -417,8 +419,10 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
case 'p': oper = "**"; break;
case 'E': oper = "==="; break;
case 'e': oper = "=="; break;
case 'w': oper = "==?"; break;
case 'N': oper = "!=="; break;
case 'n': oper = "!="; break;
case 'W': oper = "!=?"; break;
case '<': oper = "<"; break;
case 'L': oper = "<="; break;
case '>': oper = ">"; break;
@ -465,6 +469,14 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
fprintf(vlog_out, " %s ", oper);
emit_expr(scope, oper2, wid, 0, can_skip_unsigned, is_full_prec);
break;
case 'w':
case 'W':
fprintf(stderr, "%s:%u: vlog95 error: The wild equality operators "
"cannot be converted.\n",
ivl_expr_file(expr),
ivl_expr_lineno(expr));
vlog_errors += 1;
case 'E':
case 'e':
case 'N':

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2016 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2011-2017 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
@ -398,6 +398,8 @@ static ivl_nexus_t get_lpm_output(ivl_scope_t scope, ivl_lpm_t lpm)
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_CONCAT:
case IVL_LPM_CONCATZ:
case IVL_LPM_DIVIDE:
@ -1194,19 +1196,19 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm,
fprintf(vlog_out, ")");
break;
case IVL_LPM_CMP_EQX:
// HERE: Need to heck that this is not a real nexus.
// HERE: Need to check that this is not a real nexus.
fprintf(vlog_out, "(");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0, 0);
fprintf(vlog_out, " ==? ");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0);
fprintf(vlog_out, ")");
fprintf(stderr, "%s:%u: vlog95 error: Compare wildcard equal "
fprintf(stderr, "%s:%u: vlog95 error: Compare wildcard equal (caseX) "
"operator is not supported.\n",
ivl_lpm_file(lpm), ivl_lpm_lineno(lpm));
vlog_errors += 1;
break;
case IVL_LPM_CMP_EQZ:
// HERE: Need to heck that this is not a real nexus.
// HERE: Need to check that this is not a real nexus.
fprintf(vlog_out, "(");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0, 0);
fprintf(vlog_out, " == ");
@ -1245,6 +1247,28 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm,
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0);
fprintf(vlog_out, ")");
break;
case IVL_LPM_CMP_WEQ:
fprintf(vlog_out, "(");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0, 0);
fprintf(vlog_out, " ==? ");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0);
fprintf(vlog_out, ")");
fprintf(stderr, "%s:%u: vlog95 error: Wild equality "
"operator is not supported.\n",
ivl_lpm_file(lpm), ivl_lpm_lineno(lpm));
vlog_errors += 1;
break;
case IVL_LPM_CMP_WNE:
fprintf(vlog_out, "(");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0, 0);
fprintf(vlog_out, " !=? ");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0);
fprintf(vlog_out, ")");
fprintf(stderr, "%s:%u: vlog95 error: Wild inequality "
"operator is not supported.\n",
ivl_lpm_file(lpm), ivl_lpm_lineno(lpm));
vlog_errors += 1;
break;
/* A concat-Z should never be generated, but report it as an
* error if one is generated. */
case IVL_LPM_CONCATZ:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-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
@ -398,6 +398,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
case IVL_LPM_CONCATZ:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_EQ:
case IVL_LPM_CMP_WEQ:
case IVL_LPM_CMP_WNE:
case IVL_LPM_CMP_EQX:
case IVL_LPM_CMP_EQZ:
case IVL_LPM_CMP_GE:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003-2013 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-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
@ -57,6 +57,8 @@ static void draw_binary_real(ivl_expr_t expr)
switch (ivl_expr_opcode(expr)) {
case 'E':
case 'N':
case 'w':
case 'W':
case 'l':
case 'r':
case 'R':

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2013-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
@ -385,8 +385,7 @@ static void draw_binary_vec4_compare(ivl_expr_t expr)
fprintf(vvp_out, " %%flag_get/vec4 4;\n");
break;
case 'n': /* != */
fprintf(vvp_out, " %%cmp/e;\n");
fprintf(vvp_out, " %%flag_inv 4;\n");
fprintf(vvp_out, " %%cmp/ne;\n");
fprintf(vvp_out, " %%flag_get/vec4 4;\n");
break;
case 'E': /* === */
@ -394,10 +393,17 @@ static void draw_binary_vec4_compare(ivl_expr_t expr)
fprintf(vvp_out, " %%flag_get/vec4 6;\n");
break;
case 'N': /* !== */
fprintf(vvp_out, " %%cmp/e;\n");
fprintf(vvp_out, " %%flag_inv 6;\n");
fprintf(vvp_out, " %%cmp/ne;\n");
fprintf(vvp_out, " %%flag_get/vec4 6;\n");
break;
case 'w': /* ==? */
fprintf(vvp_out, " %%cmp/we;\n");
fprintf(vvp_out, " %%flag_get/vec4 4;\n");
break;
case 'W': /* !=? */
fprintf(vvp_out, " %%cmp/wne;\n");
fprintf(vvp_out, " %%flag_get/vec4 4;\n");
break;
default:
assert(0);
}
@ -689,8 +695,10 @@ static void draw_binary_vec4(ivl_expr_t expr)
case 'e': /* == */
case 'E': /* === */
case 'n': /* !== */
case 'n': /* != */
case 'N': /* !== */
case 'w': /* ==? */
case 'W': /* !=? */
draw_binary_vec4_compare(expr);
break;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-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
@ -1521,6 +1521,16 @@ static void draw_lpm_cmp(ivl_lpm_t net)
type = "nee";
signed_string = "";
break;
case IVL_LPM_CMP_WEQ:
assert(dtc != IVL_VT_REAL); /* Should never get here! */
type = "weq";
signed_string = "";
break;
case IVL_LPM_CMP_WNE:
assert(dtc != IVL_VT_REAL); /* Should never get here! */
type = "wne";
signed_string = "";
break;
default:
assert(0);
}
@ -2143,6 +2153,8 @@ static void draw_lpm_in_scope(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:
draw_lpm_cmp(net);
return;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2017 Stephen Williams (steve@icarus.com)
*
*/
@ -684,6 +684,8 @@ similar:
<label> .cmp/gt <wid>, <A>, <B>;
<label> .cmp/ge.s <wid>, <A>, <B>;
<label> .cmp/gt.s <wid>, <A>, <B>;
<label> .cmp/weq <wid>, <A>, <B>;
<label> .cmp/wne <wid>, <A>, <B>;
Whereas the arithmetic statements generate an output the width of
<wid>, the comparisons produce a single bit vector result. The plain

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-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
@ -868,6 +868,76 @@ void vvp_cmp_gt::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
recv_vec4_base_(ptr, bit, BIT4_0);
}
vvp_cmp_weq::vvp_cmp_weq(unsigned wid)
: vvp_arith_(wid)
{
}
void vvp_cmp_weq::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_context_t)
{
dispatch_operand_(ptr, bit);
vvp_vector4_t eeq (1);
eeq.set_bit(0, BIT4_1);
assert(op_a_.size() == op_b_.size());
for (unsigned idx = 0 ; idx < op_a_.size() ; idx += 1) {
vvp_bit4_t a = op_a_.value(idx);
vvp_bit4_t b = op_b_.value(idx);
if (b == BIT4_X)
continue;
else if (b == BIT4_Z)
continue;
else if (a == BIT4_X)
eeq.set_bit(0, BIT4_X);
else if (a == BIT4_Z)
eeq.set_bit(0, BIT4_X);
else if (a != b) {
eeq.set_bit(0, BIT4_0);
break;
}
}
vvp_net_t*net = ptr.ptr();
net->send_vec4(eeq, 0);
}
vvp_cmp_wne::vvp_cmp_wne(unsigned wid)
: vvp_arith_(wid)
{
}
void vvp_cmp_wne::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_context_t)
{
dispatch_operand_(ptr, bit);
vvp_vector4_t eeq (1);
eeq.set_bit(0, BIT4_0);
assert(op_a_.size() == op_b_.size());
for (unsigned idx = 0 ; idx < op_a_.size() ; idx += 1) {
vvp_bit4_t a = op_a_.value(idx);
vvp_bit4_t b = op_b_.value(idx);
if (b == BIT4_X)
continue;
else if (b == BIT4_Z)
continue;
else if (a == BIT4_X)
eeq.set_bit(0, BIT4_X);
else if (a == BIT4_Z)
eeq.set_bit(0, BIT4_X);
else if (a != b) {
eeq.set_bit(0, BIT4_1);
break;
}
}
vvp_net_t*net = ptr.ptr();
net->send_vec4(eeq, 0);
}
vvp_shiftl::vvp_shiftl(unsigned wid)
: vvp_arith_(wid)

View File

@ -1,7 +1,7 @@
#ifndef IVL_arith_H
#define IVL_arith_H
/*
* Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-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
@ -200,6 +200,24 @@ class vvp_cmp_ne : public vvp_arith_ {
};
class vvp_cmp_weq : public vvp_arith_ {
public:
explicit vvp_cmp_weq(unsigned wid);
void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_context_t);
};
class vvp_cmp_wne : public vvp_arith_ {
public:
explicit vvp_cmp_wne(unsigned wid);
void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_context_t);
};
/*
* This base class implements both GT and GE comparisons. The derived

View File

@ -1,7 +1,7 @@
#ifndef IVL_codes_H
#define IVL_codes_H
/*
* Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-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
@ -75,6 +75,8 @@ extern bool of_CMPIS(vthread_t thr, vvp_code_t code);
extern bool of_CMPSTR(vthread_t thr, vvp_code_t code);
extern bool of_CMPU(vthread_t thr, vvp_code_t code);
extern bool of_CMPIU(vthread_t thr, vvp_code_t code);
extern bool of_CMPWE(vthread_t thr, vvp_code_t code);
extern bool of_CMPWNE(vthread_t thr, vvp_code_t code);
extern bool of_CMPWR(vthread_t thr, vvp_code_t code);
extern bool of_CMPWS(vthread_t thr, vvp_code_t code);
extern bool of_CMPWU(vthread_t thr, vvp_code_t code);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-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
@ -117,21 +117,23 @@ static const struct opcode_table_s opcode_table[] = {
{ "%cassign/vec4", of_CASSIGN_VEC4, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%cassign/vec4/off",of_CASSIGN_VEC4_OFF,2,{OA_FUNC_PTR,OA_BIT1, OA_NONE} },
{ "%cassign/wr", of_CASSIGN_WR, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%cast2", of_CAST2, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/e", of_CMPE, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/ne", of_CMPNE, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/s", of_CMPS, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/str",of_CMPSTR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/u", of_CMPU, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/wr", of_CMPWR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/ws", of_CMPWS, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cmp/wu", of_CMPWU, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cmp/x", of_CMPX, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/z", of_CMPZ, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmpi/e", of_CMPIE, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmpi/ne",of_CMPINE, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmpi/s", of_CMPIS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmpi/u", of_CMPIU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cast2", of_CAST2, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/e", of_CMPE, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/ne", of_CMPNE, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/s", of_CMPS, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/str", of_CMPSTR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/u", of_CMPU, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/we", of_CMPWE, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/wne", of_CMPWNE, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/wr", of_CMPWR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/ws", of_CMPWS, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cmp/wu", of_CMPWU, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cmp/x", of_CMPX, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/z", of_CMPZ, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmpi/e", of_CMPIE, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmpi/ne", of_CMPINE, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmpi/s", of_CMPIS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmpi/u", of_CMPIU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%concat/str", of_CONCAT_STR, 0,{OA_NONE, OA_NONE, OA_NONE} },
{ "%concat/vec4", of_CONCAT_VEC4, 0,{OA_NONE, OA_NONE, OA_NONE} },
{ "%concati/str", of_CONCATI_STR, 1,{OA_STRING,OA_NONE, OA_NONE} },
@ -1402,6 +1404,38 @@ void compile_cmp_gt_r(char*label, unsigned argc, struct symb_s*argv)
make_arith(arith, label, argc, argv);
}
void compile_cmp_weq(char*label, long wid,
unsigned argc, struct symb_s*argv)
{
assert( wid > 0 );
if (argc != 2) {
fprintf(stderr, "%s .cmp/weq has wrong number of symbols\n",label);
compile_errors += 1;
return;
}
vvp_arith_ *arith = new vvp_cmp_weq(wid);
make_arith(arith, label, argc, argv);
}
void compile_cmp_wne(char*label, long wid,
unsigned argc, struct symb_s*argv)
{
assert( wid > 0 );
if (argc != 2) {
fprintf(stderr, "%s .cmp/wne has wrong number of symbols\n",label);
compile_errors += 1;
return;
}
vvp_arith_ *arith = new vvp_cmp_wne(wid);
make_arith(arith, label, argc, argv);
}
void compile_delay(char*label, unsigned width,
vvp_delay_t*delay, struct symb_s arg)

View File

@ -1,7 +1,7 @@
#ifndef IVL_compile_H
#define IVL_compile_H
/*
* Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-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
@ -195,6 +195,10 @@ extern void compile_cmp_ge(char*label, long width, bool signed_flag,
unsigned argc, struct symb_s*argv);
extern void compile_cmp_gt(char*label, long width, bool signed_flag,
unsigned argc, struct symb_s*argv);
extern void compile_cmp_weq(char*label, long width,
unsigned argc, struct symb_s*argv);
extern void compile_cmp_wne(char*label, long width,
unsigned argc, struct symb_s*argv);
extern void compile_arith_mult_r(char*label, unsigned argc,
struct symb_s*argv);

View File

@ -146,6 +146,8 @@ static char* strdupnew(char const *str)
".cmp/gt" { return K_CMP_GT; }
".cmp/gt.r" { return K_CMP_GT_R; }
".cmp/gt.s" { return K_CMP_GT_S; }
".cmp/weq" { return K_CMP_WEQ; }
".cmp/wne" { return K_CMP_WNE; }
".concat" { return K_CONCAT; }
".concat8" { return K_CONCAT8; }
".delay" { return K_DELAY; }

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2017 Stephen Williams (steve@icarus.com)
*
*/
@ -302,6 +302,18 @@ The %cmp/ne and %cmpi/ne variants are the same as the %cmp/e and
eliminate the need for a %flag_inv instruction to implement != and !==
operations.
* %cmp/we
* %cmp/wne
These instructions perform a wild comparison of two vectors of equal
size. Two values are pulled from the top of the stack, and not replaced.
The results are written into flag bit 4. The comparisons work like eq/ne
except an x/z bit in the r-value will match any l-value bit.
The %cmp/wne variant is the same as %cmp/we, but the 4 flag is inverted
in order to eliminate the need for a %flag_inv instruction to implement
the !=? operator.
* %cmp/wr
Compare real values for equality and less-then. This opcode pops to
@ -1299,7 +1311,7 @@ table for the xor is:
/*
* Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-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

View File

@ -1,7 +1,7 @@
%{
/*
* Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-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
@ -80,7 +80,7 @@ static struct __vpiModPath*modpath_dst = 0;
%token K_ARRAY K_ARRAY_2U K_ARRAY_2S K_ARRAY_I K_ARRAY_OBJ K_ARRAY_R K_ARRAY_S K_ARRAY_STR K_ARRAY_PORT
%token K_CAST_INT K_CAST_REAL K_CAST_REAL_S K_CAST_2
%token K_CLASS
%token K_CMP_EEQ K_CMP_EQ K_CMP_EQX K_CMP_EQZ
%token K_CMP_EEQ K_CMP_EQ K_CMP_EQX K_CMP_EQZ K_CMP_WEQ K_CMP_WNE
%token K_CMP_EQ_R K_CMP_NEE K_CMP_NE K_CMP_NE_R
%token K_CMP_GE K_CMP_GE_R K_CMP_GE_S K_CMP_GT K_CMP_GT_R K_CMP_GT_S
%token K_CONCAT K_CONCAT8 K_DEBUG K_DELAY K_DFF_N K_DFF_N_ACLR
@ -475,6 +475,16 @@ statement
compile_cmp_gt($1, $3, true, obj.cnt, obj.vect);
}
| T_LABEL K_CMP_WEQ T_NUMBER ',' symbols ';'
{ struct symbv_s obj = $5;
compile_cmp_weq($1, $3, obj.cnt, obj.vect);
}
| T_LABEL K_CMP_WNE T_NUMBER ',' symbols ';'
{ struct symbv_s obj = $5;
compile_cmp_wne($1, $3, obj.cnt, obj.vect);
}
/* Delay nodes take a set of numbers or a set of inputs. The delay
node takes two form, one with an array of constants and a single
input, and another with an array of inputs. */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-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
@ -1945,6 +1945,71 @@ bool of_CMPX(vthread_t thr, vvp_code_t)
return true;
}
static void do_CMPWE(vthread_t thr, const vvp_vector4_t&lval, const vvp_vector4_t&rval)
{
assert(rval.size() == lval.size());
if (lval.has_xz() || rval.has_xz()) {
unsigned wid = lval.size();
vvp_bit4_t eq = BIT4_1;
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
vvp_bit4_t lv = lval.value(idx);
vvp_bit4_t rv = rval.value(idx);
if (bit4_is_xz(rv))
continue;
if ((eq == BIT4_1) && bit4_is_xz(lv))
eq = BIT4_X;
if ((lv == BIT4_0) && (rv==BIT4_1))
eq = BIT4_0;
if ((lv == BIT4_1) && (rv==BIT4_0))
eq = BIT4_0;
if (eq == BIT4_0)
break;
}
thr->flags[4] = eq;
} else {
// If there are no XZ bits anywhere, then the results of
// ==? match the === test.
thr->flags[4] = (lval.eeq(rval)? BIT4_1 : BIT4_0);
}
}
bool of_CMPWE(vthread_t thr, vvp_code_t)
{
// We are going to pop these and push nothing in their
// place, but for now it is more efficient to use a constant
// reference. When we finish, pop the stack without copies.
const vvp_vector4_t&rval = thr->peek_vec4(0);
const vvp_vector4_t&lval = thr->peek_vec4(1);
do_CMPWE(thr, lval, rval);
thr->pop_vec4(2);
return true;
}
bool of_CMPWNE(vthread_t thr, vvp_code_t)
{
// We are going to pop these and push nothing in their
// place, but for now it is more efficient to use a constant
// reference. When we finish, pop the stack without copies.
const vvp_vector4_t&rval = thr->peek_vec4(0);
const vvp_vector4_t&lval = thr->peek_vec4(1);
do_CMPWE(thr, lval, rval);
thr->flags[4] = ~thr->flags[4];
thr->pop_vec4(2);
return true;
}
bool of_CMPWR(vthread_t thr, vvp_code_t)
{
double r = thr->pop_real();