mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-25 23:36:19 +02:00
Compare commits
132
Commits
s20141205
...
vec4-stack
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
105521b547 | ||
|
|
fd3086f0a9 | ||
|
|
77ebfcacb9 | ||
|
|
d62a307c34 | ||
|
|
011519cb5b | ||
|
|
77d1671d8f | ||
|
|
409f8c5823 | ||
|
|
03198356a5 | ||
|
|
b1d2393789 | ||
|
|
0f740289e9 | ||
|
|
46ce236cfb | ||
|
|
86139c855d | ||
|
|
eb070b061b | ||
|
|
2b1393e7b9 | ||
|
|
85c7b07a9b | ||
|
|
0c5ed2b60f | ||
|
|
3bd307db85 | ||
|
|
35db02d35d | ||
|
|
f287546f49 | ||
|
|
1645e682f4 | ||
|
|
a57e0a1e3f | ||
|
|
b83144c552 | ||
|
|
58fb80aec4 | ||
|
|
38f277d81b | ||
|
|
fb5ae48b18 | ||
|
|
82ca4cf641 | ||
|
|
679021a1b5 | ||
|
|
f3392561ed | ||
|
|
7a9a022744 | ||
|
|
c222b3b6a4 | ||
|
|
663c79d4af | ||
|
|
bea03db25d | ||
|
|
b96f04ccce | ||
|
|
a9db765f98 | ||
|
|
c71ab5869a | ||
|
|
04bdfbccee | ||
|
|
2acc9fbdee | ||
|
|
725ed869ba | ||
|
|
301edf69d3 | ||
|
|
1612c6d638 | ||
|
|
aadd67cd3b | ||
|
|
c2ca9c3b73 | ||
|
|
0601b4e43b | ||
|
|
8aca66b109 | ||
|
|
2aeb3871ed | ||
|
|
ea21fb856e | ||
|
|
d5123011b3 | ||
|
|
8ac06fb63f | ||
|
|
4e727adc25 | ||
|
|
702a8c3a05 | ||
|
|
48d3972299 | ||
|
|
62fce50f8c | ||
|
|
e4b862f3d1 | ||
|
|
09d3a5de59 | ||
|
|
97bde47c31 | ||
|
|
1c80c6e37a | ||
|
|
4588f7c615 | ||
|
|
24b8752475 | ||
|
|
3ddcf03764 | ||
|
|
35f5d51028 | ||
|
|
87c019c65c | ||
|
|
69a1fecd2e | ||
|
|
9964d67e5e | ||
|
|
a98f21aa65 | ||
|
|
88e4938074 | ||
|
|
e932c7a637 | ||
|
|
b5e0099f28 | ||
|
|
1afe7476e3 | ||
|
|
4068570f43 | ||
|
|
7ceb18fb37 | ||
|
|
d2ff77d56c | ||
|
|
91b7c6ab55 | ||
|
|
ebed793dec | ||
|
|
be5bfeb172 | ||
|
|
801e795112 | ||
|
|
e66fc7e5cc | ||
|
|
1d63875e5d | ||
|
|
554fb7ebdd | ||
|
|
c9e8392dc7 | ||
|
|
60d37e1f53 | ||
|
|
401fccdf6e | ||
|
|
f5564a195f | ||
|
|
c7e61f3aa4 | ||
|
|
1805598eae | ||
|
|
0eca210722 | ||
|
|
fdc9e8590d | ||
|
|
e497f63e29 | ||
|
|
75233a9bca | ||
|
|
11197baf86 | ||
|
|
23ba0bc019 | ||
|
|
9cfb15a302 | ||
|
|
8bebe59e20 | ||
|
|
20d415463a | ||
|
|
9c1dcad994 | ||
|
|
0e13726e83 | ||
|
|
54346d7095 | ||
|
|
0121fbc88c | ||
|
|
f1855eed0e | ||
|
|
0f9828f179 | ||
|
|
d2c2d6d8dc | ||
|
|
f94a655121 | ||
|
|
078a3fd409 | ||
|
|
dfaed128c0 | ||
|
|
1fc4093191 | ||
|
|
ae1f8be277 | ||
|
|
d8533104b0 | ||
|
|
c6c697bdb7 | ||
|
|
660d59a7a9 | ||
|
|
92a5e6a698 | ||
|
|
aaa054a932 | ||
|
|
079065ea73 | ||
|
|
1905264061 | ||
|
|
b0a9430e98 | ||
|
|
6a93b6a7e4 | ||
|
|
ec6009dd8f | ||
|
|
4820d46353 | ||
|
|
a2845cee70 | ||
|
|
c897ca017c | ||
|
|
aee540d8bb | ||
|
|
19402aeef2 | ||
|
|
fcc0a6a203 | ||
|
|
e5eb754150 | ||
|
|
063c6d6065 | ||
|
|
2fc8ce8a16 | ||
|
|
1a3adbe9cd | ||
|
|
63fa44fa4a | ||
|
|
f89dbd48c8 | ||
|
|
9fc3e84e93 | ||
|
|
e708a5b59d | ||
|
|
d55e4c0552 | ||
|
|
54926840e6 | ||
|
|
5ef077fdf6 |
@@ -1661,6 +1661,16 @@ void NetEBinary::dump(ostream&o) const
|
||||
o << ")";
|
||||
}
|
||||
|
||||
void NetECast::dump(ostream&fd) const
|
||||
{
|
||||
if (op_=='2')
|
||||
fd << "bool<" << expr_width() << ">(" << *expr_ << ")";
|
||||
else if (op_=='4')
|
||||
fd << "logic<" << expr_width() << ">(" << *expr_ << ")";
|
||||
else
|
||||
NetEUnary::dump(fd);
|
||||
}
|
||||
|
||||
void NetEConcat::dump(ostream&o) const
|
||||
{
|
||||
if (repeat_ != 1)
|
||||
|
||||
+92
-9
@@ -267,6 +267,13 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
|
||||
unsigned l_width = left_->test_width(des, scope, mode);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEBinary::test_width: "
|
||||
<< "op_=" << op_ << ", l_width=" << l_width
|
||||
<< ", r_width=" << r_width
|
||||
<< ", saved_mode=" << saved_mode << endl;
|
||||
}
|
||||
|
||||
// If the width mode changed, retest the right operand, as it
|
||||
// may choose a different width if it is in a lossless context.
|
||||
if ((mode >= LOSSLESS) && (saved_mode < LOSSLESS))
|
||||
@@ -717,6 +724,14 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
ivl_assert(*this, left_);
|
||||
ivl_assert(*this, right_);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEBLeftWidth::test_width: "
|
||||
<< "op_=" << op_
|
||||
<< ", left_=" << *left_
|
||||
<< ", right_=" << *right_
|
||||
<< ", mode=" << width_mode_name(mode) << endl;
|
||||
}
|
||||
|
||||
// The right operand is self determined. Test its type and
|
||||
// width for use later. We only need to know its width now
|
||||
// if the left operand is unsized and we need to calculate
|
||||
@@ -724,11 +739,26 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
width_mode_t r_mode = SIZED;
|
||||
unsigned r_width = right_->test_width(des, scope, r_mode);
|
||||
|
||||
expr_width_ = left_->test_width(des, scope, mode);
|
||||
// The left operand is what will determine the size of the
|
||||
// expression. The l_mode will be converted to UNSIZED if the
|
||||
// expression does not have a well-determined size.
|
||||
width_mode_t l_mode = SIZED;
|
||||
expr_width_ = left_->test_width(des, scope, l_mode);
|
||||
expr_type_ = left_->expr_type();
|
||||
signed_flag_ = left_->has_sign();
|
||||
|
||||
if (mode==SIZED)
|
||||
mode = l_mode;
|
||||
|
||||
// The left operand width defines the size of the
|
||||
// expression. If the expression has a well-defined size, the
|
||||
// left_->test_width() above would have set mode==SIZED and we
|
||||
// can skip a lot of stuff. But if the mode is an undetermined
|
||||
// size, we need to figure out what we really want to keep a
|
||||
// lossless value. That's what the following if(...) {...} is
|
||||
// all about.
|
||||
if ((mode >= EXPAND) && type_is_vectorable(expr_type_)) {
|
||||
|
||||
// We need to make our best guess at the right operand
|
||||
// value, to minimize the calculated width. This is
|
||||
// particularly important for the power operator...
|
||||
@@ -758,6 +788,13 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
if (rc && (r_width < sizeof(long)*8))
|
||||
r_val = rc->value().as_long();
|
||||
|
||||
if (debug_elaborate && rc) {
|
||||
cerr << get_fileline() << ": PEBLeftWidth::test_width: "
|
||||
<< "Evaluated rc=" << *rc
|
||||
<< ", r_val=" << r_val
|
||||
<< ", width_cap=" << width_cap << endl;
|
||||
}
|
||||
|
||||
// Clip to a sensible range to avoid underflow/overflow
|
||||
// in the following calculations.
|
||||
if (r_val < 0)
|
||||
@@ -774,7 +811,8 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
unsigned use_width = expr_width_;
|
||||
switch (op_) {
|
||||
case 'l': // <<
|
||||
use_width += (unsigned)r_val;
|
||||
if (l_mode != SIZED)
|
||||
use_width += (unsigned)r_val;
|
||||
break;
|
||||
|
||||
case 'r': // >>
|
||||
@@ -812,6 +850,12 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
if ((rc == 0) && (use_width > expr_width_) && (use_width > integer_width))
|
||||
use_width = integer_width;
|
||||
|
||||
if (use_width >= width_cap) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "Unsized expression (" << *this << ")"
|
||||
<< " expanded beyond and was clipped to " << use_width
|
||||
<< " bits. Try using sized operands." << endl;
|
||||
}
|
||||
expr_width_ = use_width;
|
||||
}
|
||||
|
||||
@@ -820,6 +864,13 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
else
|
||||
min_width_ = UINT_MAX; // disable width pruning
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEBLeftWidth::test_width: "
|
||||
<< "Done calculating expr_width_=" << expr_width_
|
||||
<< ", min_width_=" << min_width_
|
||||
<< ", mode=" << width_mode_name(mode) << endl;
|
||||
}
|
||||
|
||||
return fix_width_(mode);
|
||||
}
|
||||
|
||||
@@ -1273,6 +1324,18 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
|
||||
if (net == 0)
|
||||
return 0;
|
||||
|
||||
// Look fonr built in string attributes.
|
||||
if (net->data_type()==IVL_VT_STRING) {
|
||||
|
||||
if (method_name == "len") {
|
||||
expr_type_ = IVL_VT_BOOL;
|
||||
expr_width_ = 32;
|
||||
min_width_ = 32;
|
||||
signed_flag_= true;
|
||||
return expr_width_;
|
||||
}
|
||||
}
|
||||
|
||||
// function int size()
|
||||
if (use_darray && method_name == "size") {
|
||||
if (debug_elaborate) {
|
||||
@@ -1333,6 +1396,13 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
|
||||
|
||||
NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, unsigned wid) const
|
||||
{
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PECallFunction::cast_to_width_: "
|
||||
<< "cast to " << wid
|
||||
<< " bits " << (signed_flag_?"signed":"unsigned")
|
||||
<< " from expr_width()=" << expr->expr_width() << endl;
|
||||
}
|
||||
|
||||
/* If the expression is a const, then replace it with a new
|
||||
const. This is a more efficient result. */
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
|
||||
@@ -1345,10 +1415,6 @@ NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, unsigned wid) const
|
||||
return tmp;
|
||||
}
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: cast to " << wid
|
||||
<< " bits " << (signed_flag_?"signed":"unsigned") << endl;
|
||||
|
||||
NetESelect*tmp = new NetESelect(expr, 0, wid);
|
||||
tmp->cast_signed(signed_flag_);
|
||||
tmp->set_line(*this);
|
||||
@@ -1392,6 +1458,10 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PECallFunction::elaborate_sfunc_: "
|
||||
<< name << " expression is the argument cast to expr_wid=" << expr_wid << endl;
|
||||
}
|
||||
PExpr*expr = parms_[0];
|
||||
NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, flags);
|
||||
|
||||
@@ -3346,7 +3416,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||
indices_flags idx_flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
use_comp.index, net->unpacked_dimensions(),
|
||||
need_const,
|
||||
need_const, net->unpacked_count(),
|
||||
idx_flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
@@ -4419,7 +4489,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
|
||||
indices_flags idx_flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
name_tail.index, net->unpacked_dimensions(),
|
||||
need_const,
|
||||
need_const, net->unpacked_count(),
|
||||
idx_flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
@@ -5395,10 +5465,23 @@ unsigned PENumber::test_width(Design*, NetScope*, width_mode_t&mode)
|
||||
expr_width_ = integer_width;
|
||||
mode = UNSIZED;
|
||||
} else if (mode < LOSSLESS) {
|
||||
mode = LOSSLESS;
|
||||
if (expr_width_ < integer_width) {
|
||||
expr_width_ = integer_width;
|
||||
if (mode < UNSIZED)
|
||||
mode = UNSIZED;
|
||||
} else {
|
||||
mode = LOSSLESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PENumber::test_width: "
|
||||
<< "Value=" << *value_
|
||||
<< ", width=" << expr_width_
|
||||
<< ", output mode=" << width_mode_name(mode) << endl;
|
||||
}
|
||||
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
|
||||
+20
-2
@@ -202,6 +202,11 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||
NetEvent* eve = 0;
|
||||
perm_string method_name;
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval: "
|
||||
<< "Elaborate l-value ident expression: " << *this << endl;
|
||||
}
|
||||
|
||||
/* Try to detect the special case that we are in a method and
|
||||
the identifier is a member of the class. */
|
||||
if (NetAssign_*tmp = elaborate_lval_method_class_member_(des, scope))
|
||||
@@ -263,7 +268,8 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval: "
|
||||
<< "Lval reg = " << reg->name() << endl;
|
||||
<< "Found l-value as reg."
|
||||
<< " unpacked_dimensions()=" << reg->unpacked_dimensions() << endl;
|
||||
}
|
||||
|
||||
// We are processing the tail of a string of names. For
|
||||
@@ -509,6 +515,11 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||
const name_component_t&name_tail = path_.back();
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_net_word_: "
|
||||
<< "Handle as n-dimensional array." << endl;
|
||||
}
|
||||
|
||||
if (name_tail.index.size() < reg->unpacked_dimensions()) {
|
||||
cerr << get_fileline() << ": error: Array " << reg->name()
|
||||
<< " needs " << reg->unpacked_dimensions() << " indices,"
|
||||
@@ -517,6 +528,8 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned array_need_words = reg->unpacked_count();
|
||||
|
||||
// Make sure there are enough indices to address an array element.
|
||||
const index_component_t&index_head = name_tail.index.front();
|
||||
if (index_head.sel == index_component_t::SEL_PART) {
|
||||
@@ -534,7 +547,7 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
name_tail.index, reg->unpacked_dimensions(),
|
||||
false,
|
||||
false, array_need_words,
|
||||
flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
@@ -576,6 +589,11 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||
canon_index = new NetEConst(verinum(verinum::Vx));
|
||||
canon_index->set_line(*this);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_net_word_: "
|
||||
<< "canon_index=" << *canon_index << endl;
|
||||
}
|
||||
|
||||
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Unable to assign words of unresolved wire array." << endl;
|
||||
|
||||
+1
-1
@@ -630,7 +630,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
path_tail.index, sig->unpacked_dimensions(),
|
||||
true,
|
||||
true, sig->unpacked_count(),
|
||||
flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
|
||||
+21
-7
@@ -201,15 +201,16 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||
verinum one_value ((uint64_t)1, enum_width);
|
||||
one_value.has_sign(enum_type->signed_flag);
|
||||
// Find the maximum allowed enumeration value.
|
||||
verinum min_value (0);
|
||||
verinum max_value (0);
|
||||
if (enum_type->signed_flag) {
|
||||
min_value = -pow(verinum(2), verinum(enum_width-1));
|
||||
max_value = pow(verinum(2), verinum(enum_width-1)) - one_value;
|
||||
} else {
|
||||
max_value = pow(verinum(2), verinum(enum_width)) - one_value;
|
||||
}
|
||||
min_value.has_sign(true);
|
||||
max_value.has_sign(enum_type->signed_flag);
|
||||
// Variable to indicate when a defined value wraps.
|
||||
bool implicit_wrapped = false;
|
||||
// Process the enumeration definition.
|
||||
for (list<named_pexpr_t>::const_iterator cur = enum_type->names->begin()
|
||||
; cur != enum_type->names->end() ; ++ cur, name_idx += 1) {
|
||||
@@ -228,8 +229,6 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||
continue;
|
||||
}
|
||||
cur_value = val_const->value();
|
||||
// Clear the implicit wrapped flag if a parameter is given.
|
||||
implicit_wrapped = false;
|
||||
|
||||
// A 2-state value can not have a constant with X/Z bits.
|
||||
if (enum_type->base_type==IVL_VT_BOOL &&
|
||||
@@ -336,8 +335,24 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check to see if an implicitly wrapped value is used.
|
||||
if (implicit_wrapped) {
|
||||
// Cast any undefined bits to zero so the comparisons below
|
||||
// return just true (1) or false (0).
|
||||
verinum two_state_value = cur_value;
|
||||
two_state_value.cast_to_int2();
|
||||
|
||||
// The enumeration value must fit into the enumeration bits.
|
||||
if (!cur_value.is_defined()) {
|
||||
if (cur_value.len() > (unsigned long)use_enum->packed_width()) {
|
||||
cerr << use_enum->get_fileline()
|
||||
<< ": error: Enumeration name " << cur->name
|
||||
<< " value=" << cur_value
|
||||
<< " is too wide for enumeration base type." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
} else if ((two_state_value > max_value) ||
|
||||
(cur_value.has_sign() && (two_state_value < min_value))) {
|
||||
|
||||
cerr << use_enum->get_fileline()
|
||||
<< ": error: Enumeration name " << cur->name
|
||||
<< " has an inferred value that overflowed." << endl;
|
||||
@@ -370,7 +385,6 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||
// In case the next name has an implicit value,
|
||||
// increment the current value by one.
|
||||
if (cur_value.is_defined()) {
|
||||
if (cur_value == max_value) implicit_wrapped = true;
|
||||
cur_value = cur_value + one_value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +135,9 @@ ivl_variable_type_t NetAssign_::expr_type() const
|
||||
return darray->element_base_type();
|
||||
}
|
||||
|
||||
if (sig_ && sig_->data_type()==IVL_VT_STRING && base_!=0)
|
||||
return IVL_VT_BOOL;
|
||||
|
||||
if (ntype) return ntype->base_type();
|
||||
|
||||
ivl_assert(*this, sig_);
|
||||
|
||||
+15
-10
@@ -527,6 +527,20 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the parameter has type or range information, then
|
||||
// make sure the type is set right. Note that if the
|
||||
// parameter doesn't have an explicit type or range,
|
||||
// then it will get the signedness from the expression itself.
|
||||
if (cur->second.type != IVL_VT_NO_TYPE) {
|
||||
expr->cast_signed(cur->second.signed_flag);
|
||||
} else if (cur->second.signed_flag) {
|
||||
expr->cast_signed(true);
|
||||
}
|
||||
|
||||
if (!range_flag && !expr->has_width()) {
|
||||
expr = pad_to_width(expr, integer_width, *expr);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -536,17 +550,8 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
(*cur).second.val = expr;
|
||||
|
||||
/* If the parameter has type or range information, then make
|
||||
sure the type is set right. Note that if the parameter
|
||||
doesn't have an explicit type or range, then it will get
|
||||
the signedness from the expression itself. */
|
||||
if ((*cur).second.type != IVL_VT_NO_TYPE) {
|
||||
(*cur).second.val->cast_signed((*cur).second.signed_flag);
|
||||
} else if ((*cur).second.signed_flag) {
|
||||
(*cur).second.val->cast_signed(true);
|
||||
}
|
||||
cur->second.val = expr;
|
||||
|
||||
// If there are no value ranges to test the value against,
|
||||
// then we are done.
|
||||
|
||||
@@ -2041,7 +2041,7 @@ class NetEConst : public NetExpr {
|
||||
/* This method allows the constant value to be converted
|
||||
to an unsized value. This is used after evaluating a
|
||||
unsized constant expression. */
|
||||
virtual void trim();
|
||||
void trim();
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
@@ -4650,6 +4650,7 @@ class NetECast : public NetEUnary {
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
virtual NetECast* dup_expr() const;
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
private:
|
||||
virtual NetExpr* eval_arguments_(const NetExpr*ex) const;
|
||||
|
||||
+63
-11
@@ -248,16 +248,26 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr)
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Multiple an existing expression by a signed positive number.
|
||||
* This does a lossless multiply, so the arguments will need to be
|
||||
* sized to match the output size.
|
||||
*/
|
||||
static NetExpr* make_mult_expr(NetExpr*expr, unsigned long val)
|
||||
{
|
||||
verinum val_v (val, expr->expr_width());
|
||||
const unsigned val_wid = ceil(log2((double)val)) ;
|
||||
unsigned use_wid = expr->expr_width() + val_wid;
|
||||
verinum val_v (val, use_wid);
|
||||
val_v.has_sign(true);
|
||||
|
||||
NetEConst*val_c = new NetEConst(val_v);
|
||||
val_c->set_line(*expr);
|
||||
|
||||
NetEBMult*res = new NetEBMult('*', expr, val_c, expr->expr_width(),
|
||||
expr->has_sign());
|
||||
// We know by definitions that the expr argument needs to be
|
||||
// padded to be the right argument width for this lossless multiply.
|
||||
expr = pad_to_width(expr, use_wid, *expr);
|
||||
|
||||
NetEBMult*res = new NetEBMult('*', expr, val_c, use_wid, expr->has_sign());
|
||||
res->set_line(*expr);
|
||||
|
||||
return res;
|
||||
@@ -470,6 +480,8 @@ void indices_to_expressions(Design*des, NetScope*scope,
|
||||
const list<index_component_t>&src, unsigned count,
|
||||
// True if the expression MUST be constant.
|
||||
bool need_const,
|
||||
// Total words in target array
|
||||
unsigned need_addr,
|
||||
// These are the outputs.
|
||||
indices_flags&flags,
|
||||
list<NetExpr*>&indices, list<long>&indices_const)
|
||||
@@ -490,7 +502,7 @@ void indices_to_expressions(Design*des, NetScope*scope,
|
||||
}
|
||||
ivl_assert(*loc, cur->msb);
|
||||
|
||||
NetExpr*word_index = elab_and_eval(des, scope, cur->msb, -1, need_const);
|
||||
NetExpr*word_index = elab_and_eval_lossless(des, scope, cur->msb, -2, need_const);
|
||||
|
||||
if (word_index == 0)
|
||||
flags.invalid = true;
|
||||
@@ -680,7 +692,8 @@ NetExpr* make_canonical_index(Design*des, NetScope*scope,
|
||||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, loc,
|
||||
src, src.size(),
|
||||
need_const, flags,
|
||||
need_const, stype->static_dimensions().size(),
|
||||
flags,
|
||||
indices_expr, indices_const);
|
||||
|
||||
if (flags.undefined) {
|
||||
@@ -790,13 +803,16 @@ NetExpr* condition_reduce(NetExpr*expr)
|
||||
return cmp;
|
||||
}
|
||||
|
||||
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
int context_width, bool need_const, bool annotatable,
|
||||
ivl_variable_type_t cast_type)
|
||||
static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
int context_width, bool need_const, bool annotatable,
|
||||
bool force_expand,
|
||||
ivl_variable_type_t cast_type)
|
||||
{
|
||||
PExpr::width_mode_t mode = PExpr::SIZED;
|
||||
if ((context_width == -2) && !gn_strict_expr_width_flag)
|
||||
mode = PExpr::EXPAND;
|
||||
if (force_expand)
|
||||
mode = PExpr::EXPAND;
|
||||
|
||||
pe->test_width(des, scope, mode);
|
||||
|
||||
@@ -815,8 +831,10 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
<< *pe << endl;
|
||||
cerr << pe->get_fileline() << ": : "
|
||||
<< "returns type=" << pe->expr_type()
|
||||
<< ", width=" << expr_width
|
||||
<< ", context_width=" << context_width
|
||||
<< ", signed=" << pe->has_sign()
|
||||
<< ", force_expand=" << force_expand
|
||||
<< ", expr_width=" << expr_width
|
||||
<< ", mode=" << PExpr::width_mode_name(mode) << endl;
|
||||
cerr << pe->get_fileline() << ": : "
|
||||
<< "cast_type=" << cast_type << endl;
|
||||
@@ -824,6 +842,7 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
|
||||
// If we can get the same result using a smaller expression
|
||||
// width, do so.
|
||||
|
||||
unsigned min_width = pe->min_width();
|
||||
if ((min_width != UINT_MAX) && (pe->expr_type() != IVL_VT_REAL)
|
||||
&& (pos_context_width > 0) && (expr_width > pos_context_width)) {
|
||||
@@ -850,6 +869,11 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
if (annotatable)
|
||||
flags |= PExpr::ANNOTATABLE;
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << pe->get_fileline() << ": elab_and_eval: "
|
||||
<< "Calculated width is " << expr_width << "." << endl;
|
||||
}
|
||||
|
||||
NetExpr*tmp = pe->elaborate_expr(des, scope, expr_width, flags);
|
||||
if (tmp == 0) return 0;
|
||||
|
||||
@@ -869,6 +893,13 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
}
|
||||
}
|
||||
|
||||
// If the context_width sent is is actually the minimim width,
|
||||
// then raise the context_width to be big enough for the
|
||||
// lossless expression.
|
||||
if (force_expand && context_width > 0) {
|
||||
context_width = max(context_width, (int)expr_width);
|
||||
}
|
||||
|
||||
eval_expr(tmp, context_width);
|
||||
|
||||
if (NetEConst*ce = dynamic_cast<NetEConst*>(tmp)) {
|
||||
@@ -879,6 +910,27 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
int context_width, bool need_const, bool annotatable,
|
||||
ivl_variable_type_t cast_type)
|
||||
{
|
||||
return do_elab_and_eval(des, scope, pe, context_width,
|
||||
need_const, annotatable, false, cast_type);
|
||||
}
|
||||
|
||||
/*
|
||||
* This variant of elab_and_eval does the expression losslessly, no
|
||||
* matter what the generation of verilog. This is in support of
|
||||
* certain special contexts, notably index expressions.
|
||||
*/
|
||||
NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope, PExpr*pe,
|
||||
int context_width, bool need_const, bool annotatable,
|
||||
ivl_variable_type_t cast_type)
|
||||
{
|
||||
return do_elab_and_eval(des, scope, pe, context_width,
|
||||
need_const, annotatable, true, cast_type);
|
||||
}
|
||||
|
||||
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
||||
ivl_type_t lv_net_type, bool need_const)
|
||||
{
|
||||
@@ -929,7 +981,7 @@ NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name,
|
||||
// determine the exact width required to hold the result.
|
||||
// But leave literal numbers exactly as the user supplied
|
||||
// them.
|
||||
if ((mode >= PExpr::LOSSLESS) && !dynamic_cast<PENumber*>(pe))
|
||||
if ((mode >= PExpr::LOSSLESS) && !dynamic_cast<PENumber*>(pe) && tmp->expr_width()>32)
|
||||
ce->trim();
|
||||
}
|
||||
|
||||
@@ -1376,7 +1428,7 @@ NetExpr*collapse_array_exprs(Design*des, NetScope*scope,
|
||||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, loc, indices,
|
||||
net->packed_dimensions(),
|
||||
false, flags, exprs, exprs_const);
|
||||
false, net->unpacked_count(), flags, exprs, exprs_const);
|
||||
ivl_assert(*loc, exprs.size() == net->packed_dimensions());
|
||||
|
||||
// Special Case: there is only 1 packed dimension, so the
|
||||
|
||||
@@ -181,6 +181,8 @@ extern void indices_to_expressions(Design*des, NetScope*scope,
|
||||
const list<index_component_t>&src, unsigned count,
|
||||
// True if the expression MUST be constant.
|
||||
bool need_const,
|
||||
// Total array size, for sizing expressions
|
||||
unsigned need_addr,
|
||||
// These are the outputs.
|
||||
indices_flags&flags,
|
||||
list<NetExpr*>&indices,list<long>&indices_const);
|
||||
@@ -260,6 +262,12 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
|
||||
bool annotatable =false,
|
||||
ivl_variable_type_t cast_type =IVL_VT_NO_TYPE);
|
||||
|
||||
extern NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope,
|
||||
PExpr*pe, int context_width,
|
||||
bool need_const =false,
|
||||
bool annotatable =false,
|
||||
ivl_variable_type_t cast_type =IVL_VT_NO_TYPE);
|
||||
|
||||
/*
|
||||
* This form of elab_and_eval uses the ivl_type_t to carry type
|
||||
* information instead of the piecemeal form. We should transition to
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
#
|
||||
# NOTE: DO NOT INSTALL THIS FILE.
|
||||
|
||||
./ivl -v -Ctgt-stub/stub.conf -C./scripts/devel-stub.conf -Pa.pf -Na.net -fDLL=tgt-stub/stub.tgt foo.vl |& tee foo.log
|
||||
./ivl -v -Ctgt-stub/stub.conf -C./scripts/devel-stub.conf -Pa.pf -Na.net -fDLL=tgt-stub/stub.tgt foo.vl | tee foo.log 2>&1
|
||||
|
||||
echo "*** ivl command completed"
|
||||
|
||||
@@ -338,6 +338,103 @@ bool NetBlock::synth_async(Design*des, NetScope*scope,
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to fix up a MUX selector to be no longer than
|
||||
* it needs to be. The general idea is that if the selector needs to
|
||||
* be only N bits, but is actually M bits, we translate it to this:
|
||||
*
|
||||
* osig = { |esig[M-1:N-1], esig[N-2:0] }
|
||||
*
|
||||
* This obviously implies that (N >= 2) and (M >= N). In the code
|
||||
* below, N is sel_need, and M is sel_got (= esig->vector_width()).
|
||||
*/
|
||||
static NetNet* mux_selector_reduce_width(Design*des, NetScope*scope,
|
||||
const LineInfo&loc,
|
||||
NetNet*esig, unsigned sel_need)
|
||||
{
|
||||
const unsigned sel_got = esig->vector_width();
|
||||
|
||||
ivl_assert(*esig, sel_got >= sel_need);
|
||||
|
||||
// If the actual width matches the desired width (M==N) then
|
||||
// osig is esig itself. We're done.
|
||||
if (sel_got == sel_need)
|
||||
return esig;
|
||||
|
||||
if (debug_synth2) {
|
||||
cerr << loc.get_fileline() << ": mux_selector_reduce_width: "
|
||||
<< "Reduce selector width=" << sel_got
|
||||
<< " to " << sel_need << " bits." << endl;
|
||||
}
|
||||
|
||||
ivl_assert(*esig, sel_need >= 2);
|
||||
|
||||
// This is the output signal, osig.
|
||||
ivl_variable_type_t osig_data_type = IVL_VT_LOGIC;
|
||||
netvector_t*osig_vec = new netvector_t(osig_data_type, sel_need-1, 0);
|
||||
NetNet*osig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::TRI, osig_vec);
|
||||
osig->local_flag(true);
|
||||
osig->set_line(loc);
|
||||
|
||||
// Create the concat: osig = {...,...}
|
||||
NetConcat*osig_cat = new NetConcat(scope, scope->local_symbol(),
|
||||
sel_need, 2, true);
|
||||
osig_cat->set_line(loc);
|
||||
des->add_node(osig_cat);
|
||||
connect(osig_cat->pin(0), osig->pin(0));
|
||||
|
||||
// Create the part select esig[N-2:0]...
|
||||
NetPartSelect*ps0 = new NetPartSelect(esig, 0, sel_need-1,
|
||||
NetPartSelect::VP);
|
||||
ps0->set_line(loc);
|
||||
des->add_node(ps0);
|
||||
connect(ps0->pin(1), esig->pin(0));
|
||||
|
||||
netvector_t*ps0_vec = new netvector_t(osig_data_type, sel_need-2, 0);
|
||||
NetNet*ps0_sig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::TRI, ps0_vec);
|
||||
ps0_sig->local_flag(true);
|
||||
ps0_sig->set_line(loc);
|
||||
connect(ps0_sig->pin(0), ps0->pin(0));
|
||||
|
||||
// osig = {..., esig[N-2:0]}
|
||||
connect(osig_cat->pin(1), ps0_sig->pin(0));
|
||||
|
||||
// Create the part select esig[M-1:N-1]
|
||||
NetPartSelect*ps1 = new NetPartSelect(esig, sel_need-1,
|
||||
sel_got-sel_need,
|
||||
NetPartSelect::VP);
|
||||
ps1->set_line(loc);
|
||||
des->add_node(ps1);
|
||||
connect(ps1->pin(1), esig->pin(0));
|
||||
|
||||
netvector_t*ps1_vec = new netvector_t(osig_data_type, sel_got-sel_need-1, 0);
|
||||
NetNet*ps1_sig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::TRI, ps1_vec);
|
||||
ps1_sig->local_flag(true);
|
||||
ps1_sig->set_line(loc);
|
||||
connect(ps1_sig->pin(0), ps1->pin(0));
|
||||
|
||||
// Create the reduction OR: | esig[M-1:N-1]
|
||||
NetUReduce*ered = new NetUReduce(scope, scope->local_symbol(),
|
||||
NetUReduce::OR, sel_got-sel_need);
|
||||
ered->set_line(loc);
|
||||
des->add_node(ered);
|
||||
connect(ered->pin(1), ps1_sig->pin(0));
|
||||
|
||||
NetNet*ered_sig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::TRI, &netvector_t::scalar_logic);
|
||||
ered_sig->local_flag(true);
|
||||
ered_sig->set_line(loc);
|
||||
connect(ered->pin(0), ered_sig->pin(0));
|
||||
|
||||
// osig = { |esig[M-1:N-1], esig[N-2:0] }
|
||||
connect(osig_cat->pin(2), ered_sig->pin(0));
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
NetBus&accumulated_nex_out)
|
||||
@@ -352,12 +449,22 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||
if (dynamic_cast<NetEConst*> (expr_))
|
||||
return synth_async_casez_(des, scope, nex_map, nex_out, accumulated_nex_out);
|
||||
|
||||
if (debug_synth2) {
|
||||
cerr << get_fileline() << ": NetCase::synth_async: "
|
||||
<< "Selector expression: " << *expr_ << endl;
|
||||
}
|
||||
|
||||
/* Synthesize the select expression. */
|
||||
NetNet*esig = expr_->synthesize(des, scope, expr_);
|
||||
|
||||
unsigned sel_width = esig->vector_width();
|
||||
ivl_assert(*this, sel_width > 0);
|
||||
|
||||
if (debug_synth2) {
|
||||
cerr << get_fileline() << ": NetCase::synth_async: "
|
||||
<< "selector width (sel_width) = " << sel_width << endl;
|
||||
}
|
||||
|
||||
ivl_assert(*this, nex_map.size() == nex_out.pin_count());
|
||||
|
||||
vector<unsigned> mux_width (nex_out.pin_count());
|
||||
@@ -384,6 +491,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||
index of the mux value, and the statement is bound to that
|
||||
index. */
|
||||
|
||||
unsigned long max_guard_value = 0;
|
||||
map<unsigned long,NetProc*>statement_map;
|
||||
NetProc*statement_default = 0;
|
||||
|
||||
@@ -416,10 +524,43 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sel_idx > max_guard_value)
|
||||
max_guard_value = sel_idx;
|
||||
|
||||
ivl_assert(*this, items_[item].statement);
|
||||
statement_map[sel_idx] = items_[item].statement;
|
||||
}
|
||||
|
||||
// The mux_size is the number of inputs that are selected.
|
||||
unsigned mux_size = max_guard_value + 1;
|
||||
unsigned sel_need = ceil(log2(mux_size));
|
||||
|
||||
// If the sel_width can select more than just the explicit
|
||||
// guard values, and there is a default statement, then adjust
|
||||
// the mux size to allow for the implicit selections.
|
||||
if (statement_default && (sel_width > sel_need)) {
|
||||
sel_need += 1;
|
||||
ivl_assert(*this, sel_need < sizeof mux_size);
|
||||
mux_size = 1<<sel_need;
|
||||
}
|
||||
|
||||
if (debug_synth2) {
|
||||
cerr << get_fileline() << ": NetCase::synth_async: "
|
||||
<< "Adjusted mux_size is " << mux_size
|
||||
<< " (max_guard_value=" << max_guard_value
|
||||
<< ", sel_need=" << sel_need
|
||||
<< ", sel_width=" << sel_width << ")." << endl;
|
||||
}
|
||||
|
||||
if (sel_width > sel_need) {
|
||||
if (debug_synth2) {
|
||||
cerr << get_fileline() << ": NetCase::synth_async: "
|
||||
<< "Selector is " << sel_width << " bits, "
|
||||
<< "need only " << sel_need << " bits." << endl;
|
||||
}
|
||||
esig = mux_selector_reduce_width(des, scope, *this, esig, sel_need);
|
||||
}
|
||||
|
||||
if (!statement_default && (statement_map.size() != ((size_t)1 << sel_width))) {
|
||||
cerr << get_fileline() << ": sorry: Latch inferred from "
|
||||
<< "incomplete case statement. This is not supported "
|
||||
@@ -428,15 +569,6 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sel_width >= 8*sizeof(unsigned)) {
|
||||
cerr << get_fileline() << ": sorry: mux select width of "
|
||||
<< sel_width << " bits is too large for synthesis." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned mux_size = 1U << sel_width;
|
||||
|
||||
/* If there is a default clause, synthesize it once and we'll
|
||||
link it in wherever it is needed. */
|
||||
NetBus default_bus (scope, nex_map.size());
|
||||
@@ -464,7 +596,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||
vector<NetMux*> mux (mux_width.size());
|
||||
for (size_t mdx = 0 ; mdx < mux_width.size() ; mdx += 1) {
|
||||
mux[mdx] = new NetMux(scope, scope->local_symbol(),
|
||||
mux_width[mdx], mux_size, sel_width);
|
||||
mux_width[mdx], mux_size, sel_need);
|
||||
des->add_node(mux[mdx]);
|
||||
|
||||
// The select signal is already synthesized, and is
|
||||
|
||||
+4
-1
@@ -49,7 +49,10 @@ LDFLAGS = @LDFLAGS@
|
||||
|
||||
O = vvp.o draw_class.o draw_enum.o draw_mux.o draw_substitute.o draw_net_input.o \
|
||||
draw_switch.o draw_ufunc.o draw_vpi.o \
|
||||
eval_bool.o eval_expr.o eval_object.o eval_real.o eval_string.o \
|
||||
eval_bool.o \
|
||||
eval_condit.o \
|
||||
eval_expr.o eval_object.o eval_real.o eval_string.o \
|
||||
eval_vec4.o \
|
||||
modpath.o stmt_assign.o vector.o \
|
||||
vvp_process.o vvp_scope.o
|
||||
|
||||
|
||||
+6
-43
@@ -24,7 +24,6 @@
|
||||
|
||||
static void function_argument_logic(ivl_signal_t port, ivl_expr_t expr)
|
||||
{
|
||||
struct vector_info res;
|
||||
unsigned ewidth, pwidth;
|
||||
|
||||
/* ports cannot be arrays. */
|
||||
@@ -32,16 +31,12 @@ static void function_argument_logic(ivl_signal_t port, ivl_expr_t expr)
|
||||
|
||||
ewidth = ivl_expr_width(expr);
|
||||
pwidth = ivl_signal_width(port);
|
||||
/* Just like a normal assignment the function arguments need to
|
||||
* be evaluated at either their width or the argument width if
|
||||
* it is larger. */
|
||||
if (ewidth < pwidth) ewidth = pwidth;
|
||||
res = draw_eval_expr_wid(expr, ewidth, 0);
|
||||
|
||||
/* We could have extra bits so only select the ones we need. */
|
||||
fprintf(vvp_out, " %%set/v v%p_0, %u, %u;\n", port, res.base, pwidth);
|
||||
draw_eval_vec4(expr);
|
||||
if (ewidth < pwidth)
|
||||
fprintf(vvp_out, " %%pad/u %u;\n", pwidth);
|
||||
|
||||
clr_vector(res);
|
||||
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, %u;\n", port, pwidth);
|
||||
}
|
||||
|
||||
static void function_argument_real(ivl_signal_t port, ivl_expr_t expr)
|
||||
@@ -153,50 +148,18 @@ static void draw_ufunc_epilogue(ivl_expr_t expr)
|
||||
* parameter 0 of the function definition.
|
||||
*/
|
||||
|
||||
struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid)
|
||||
void draw_ufunc_vec4(ivl_expr_t expr)
|
||||
{
|
||||
unsigned swid = ivl_expr_width(expr);
|
||||
ivl_scope_t def = ivl_expr_def(expr);
|
||||
ivl_signal_t retval = ivl_scope_port(def, 0);
|
||||
struct vector_info res;
|
||||
unsigned load_wid;
|
||||
|
||||
/* Take in arguments to function and call function code. */
|
||||
draw_ufunc_preamble(expr);
|
||||
|
||||
/* Fresh basic block starts after the join. */
|
||||
clear_expression_lookaside();
|
||||
|
||||
/* The return value is in a signal that has the name of the
|
||||
expression. Load that into the thread and return the
|
||||
vector result. */
|
||||
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits for function result.\n",
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr), wid);
|
||||
vvp_errors += 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
assert(res.base != 0);
|
||||
|
||||
load_wid = swid;
|
||||
if (load_wid > ivl_signal_width(retval))
|
||||
load_wid = ivl_signal_width(retval);
|
||||
|
||||
assert(ivl_signal_dimensions(retval) == 0);
|
||||
fprintf(vvp_out, " %%load/v %u, v%p_0, %u;\n",
|
||||
res.base, retval, load_wid);
|
||||
|
||||
/* Pad the signal value with zeros. */
|
||||
if (load_wid < wid)
|
||||
pad_expr_in_place(expr, res, swid);
|
||||
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", retval);
|
||||
|
||||
draw_ufunc_epilogue(expr);
|
||||
return res;
|
||||
}
|
||||
|
||||
void draw_ufunc_real(ivl_expr_t expr)
|
||||
|
||||
+44
-59
@@ -29,14 +29,16 @@
|
||||
|
||||
struct args_info {
|
||||
char*text;
|
||||
int vec_flag; /* True if the vec must be released. */
|
||||
struct vector_info vec;
|
||||
/* True ('s' or 'u' if this argument is a calculated vec4. */
|
||||
char vec_flag;
|
||||
/* True if this argument is a calculated string. */
|
||||
char str_flag;
|
||||
/* True if this argument is a calculated real. */
|
||||
char real_flag;
|
||||
/* Stack position if this argument is a calculated string. */
|
||||
/* Stack position if this argument is a calculated value. */
|
||||
unsigned stack;
|
||||
/* Expression width: Only used of vec_flag is true. */
|
||||
unsigned vec_wid;
|
||||
struct args_info *child; /* Arguments can be nested. */
|
||||
};
|
||||
|
||||
@@ -156,14 +158,9 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
|
||||
return 0;
|
||||
}
|
||||
} else if (word_ex) {
|
||||
/* Fallback case: evaluate expression. */
|
||||
struct vector_info av;
|
||||
av = draw_eval_expr(word_ex, STUFF_OK_XZ);
|
||||
snprintf(buffer, sizeof buffer, "&A<v%p, %u %u \"%s\">",
|
||||
sig, av.base, av.wid,
|
||||
(ivl_expr_signed(word_ex) ? "s" : "u"));
|
||||
result->vec = av;
|
||||
result->vec_flag = 1;
|
||||
/* Fallback case: Give up and evaluate expression. */
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
assert(use_word_defined);
|
||||
snprintf(buffer, sizeof buffer, "&A<v%p, %u>",
|
||||
@@ -247,17 +244,8 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* Fallback case: evaluate the expression. */
|
||||
struct vector_info rv;
|
||||
rv = draw_eval_expr(bexpr, STUFF_OK_XZ);
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"&PV<v%p_0, %u %u \"%s\", %u>",
|
||||
ivl_expr_signal(vexpr),
|
||||
rv.base, rv.wid,
|
||||
(ivl_expr_signed(bexpr) ? "s" : "u"),
|
||||
ivl_expr_width(expr));
|
||||
result->vec = rv;
|
||||
result->vec_flag = 1;
|
||||
/* Fallback case: Punt and let caller handle it. */
|
||||
return 0;
|
||||
}
|
||||
result->text = strdup(buffer);
|
||||
return 1;
|
||||
@@ -286,6 +274,7 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
/* Keep track of how much string stack this function call is
|
||||
going to need. We'll need this for making stack references,
|
||||
and also to clean out the stack when done. */
|
||||
unsigned vec4_stack_need = 0;
|
||||
unsigned str_stack_need = 0;
|
||||
unsigned real_stack_need = 0;
|
||||
|
||||
@@ -377,9 +366,18 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
|
||||
case IVL_EX_SIGNAL:
|
||||
case IVL_EX_SELECT:
|
||||
if (get_vpi_taskfunc_signal_arg(&args[idx], expr)) continue;
|
||||
else break;
|
||||
|
||||
args[idx].stack = vec4_stack_need;
|
||||
if (get_vpi_taskfunc_signal_arg(&args[idx], expr)) {
|
||||
if (args[idx].vec_flag) {
|
||||
vec4_stack_need += 1;
|
||||
} else {
|
||||
args[idx].stack = 0;
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
args[idx].stack = 0;
|
||||
break;
|
||||
}
|
||||
/* Everything else will need to be evaluated and
|
||||
passed as a constant to the vpi task. */
|
||||
default:
|
||||
@@ -389,17 +387,18 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
switch (ivl_expr_value(expr)) {
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
args[idx].vec_flag = 1;
|
||||
args[idx].vec = draw_eval_expr(expr, 0);
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"T<%u,%u,%s>", args[idx].vec.base, args[idx].vec.wid,
|
||||
ivl_expr_signed(expr)? "s" : "u");
|
||||
draw_eval_vec4(expr);
|
||||
args[idx].vec_flag = ivl_expr_signed(expr)? 's' : 'u';
|
||||
args[idx].str_flag = 0;
|
||||
args[idx].real_flag = 0;
|
||||
args[idx].stack = vec4_stack_need;
|
||||
args[idx].vec_wid = ivl_expr_width(expr);
|
||||
vec4_stack_need += 1;
|
||||
buffer[0] = 0;
|
||||
break;
|
||||
case IVL_VT_REAL:
|
||||
draw_eval_real(expr);
|
||||
args[idx].vec_flag = 0;
|
||||
args[idx].vec.base = 0;
|
||||
args[idx].vec.wid = 0;
|
||||
args[idx].str_flag = 0;
|
||||
args[idx].real_flag = 1;
|
||||
args[idx].stack = real_stack_need;
|
||||
@@ -411,9 +410,8 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
about the stack position. */
|
||||
draw_eval_string(expr);
|
||||
args[idx].vec_flag = 0;
|
||||
args[idx].vec.base = 0;
|
||||
args[idx].vec.wid = 0;
|
||||
args[idx].str_flag = 1;
|
||||
args[idx].real_flag = 0;
|
||||
args[idx].stack = str_stack_need;
|
||||
args[idx].real_flag = 0;
|
||||
str_stack_need += 1;
|
||||
@@ -434,7 +432,7 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
struct args_info*ptr;
|
||||
|
||||
if (args[idx].str_flag) {
|
||||
/* If this is a string stack reference, then
|
||||
/* If this is a stack reference, then
|
||||
calculate the stack depth and use that to
|
||||
generate the completed string. */
|
||||
unsigned pos = str_stack_need - args[idx].stack - 1;
|
||||
@@ -442,18 +440,16 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
} else if (args[idx].real_flag) {
|
||||
unsigned pos = real_stack_need - args[idx].stack - 1;
|
||||
fprintf(vvp_out, ", W<%u,r>",pos);
|
||||
} else if (args[idx].vec_flag) {
|
||||
unsigned pos = vec4_stack_need - args[idx].stack - 1;
|
||||
char sign_flag = args[idx].vec_flag;
|
||||
unsigned wid = args[idx].vec_wid;
|
||||
fprintf(vvp_out, ", S<%u,vec4,%c%u>",pos, sign_flag, wid);
|
||||
} else {
|
||||
fprintf(vvp_out, ", %s", args[idx].text);
|
||||
}
|
||||
|
||||
free(args[idx].text);
|
||||
/* Clear the nested children vectors. */
|
||||
for (ptr = &args[idx]; ptr != NULL; ptr = ptr->child) {
|
||||
if (ptr->vec_flag) {
|
||||
if (ptr->vec.wid > 0) clr_vector(ptr->vec);
|
||||
else clr_word(ptr->vec.base);
|
||||
}
|
||||
}
|
||||
/* Free the nested children. */
|
||||
ptr = args[idx].child;
|
||||
while (ptr != NULL) {
|
||||
@@ -465,7 +461,7 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
|
||||
free(args);
|
||||
|
||||
fprintf(vvp_out, " {%u %u}", real_stack_need, str_stack_need);
|
||||
fprintf(vvp_out, " {%u %u %u}", vec4_stack_need, real_stack_need, str_stack_need);
|
||||
fprintf(vvp_out, ";\n");
|
||||
}
|
||||
|
||||
@@ -487,7 +483,7 @@ void draw_vpi_task_call(ivl_statement_t tnet)
|
||||
}
|
||||
|
||||
if (parm_count == 0) {
|
||||
fprintf(vvp_out, " %s %u %u \"%s\" {0 0};\n", command,
|
||||
fprintf(vvp_out, " %s %u %u \"%s\" {0 0 0};\n", command,
|
||||
ivl_file_table_index(ivl_stmt_file(tnet)),
|
||||
ivl_stmt_lineno(tnet), ivl_stmt_name(tnet));
|
||||
} else {
|
||||
@@ -499,27 +495,16 @@ void draw_vpi_task_call(ivl_statement_t tnet)
|
||||
}
|
||||
}
|
||||
|
||||
struct vector_info draw_vpi_func_call(ivl_expr_t fnet, unsigned wid)
|
||||
void draw_vpi_func_call(ivl_expr_t fnet)
|
||||
{
|
||||
char call_string[1024];
|
||||
struct vector_info res;
|
||||
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits for system function result.\n",
|
||||
ivl_expr_file(fnet), ivl_expr_lineno(fnet), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
sprintf(call_string, " %%vpi_func %u %u \"%s\", %u, %u",
|
||||
sprintf(call_string, " %%vpi_func %u %u \"%s\" %u",
|
||||
ivl_file_table_index(ivl_expr_file(fnet)),
|
||||
ivl_expr_lineno(fnet), ivl_expr_name(fnet), res.base, res.wid);
|
||||
ivl_expr_lineno(fnet), ivl_expr_name(fnet),
|
||||
ivl_expr_width(fnet));
|
||||
|
||||
draw_vpi_taskfunc_args(call_string, 0, fnet);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void draw_vpi_rfunc_call(ivl_expr_t fnet)
|
||||
|
||||
+2
-5
@@ -46,17 +46,14 @@
|
||||
static int eval_bool64_logic(ivl_expr_t expr)
|
||||
{
|
||||
int res;
|
||||
struct vector_info tmp;
|
||||
const char*s_flag = "";
|
||||
|
||||
tmp = draw_eval_expr(expr, STUFF_OK_XZ);
|
||||
draw_eval_vec4(expr);
|
||||
res = allocate_word();
|
||||
if (ivl_expr_signed(expr))
|
||||
s_flag = "/s";
|
||||
|
||||
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", s_flag, res,
|
||||
tmp.base, tmp.wid);
|
||||
clr_vector(tmp);
|
||||
fprintf(vvp_out, " %%ix/vec4%s %d;\n", s_flag, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright (c) 2014 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
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
# include "vvp_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
static int draw_condition_fallback(ivl_expr_t expr)
|
||||
{
|
||||
int use_flag = allocate_flag();
|
||||
|
||||
/* Evaluate the condition expression, including optionally
|
||||
reducing it to a single bit. Put the result into a flag bit
|
||||
for use by all the tests. */
|
||||
draw_eval_vec4(expr);
|
||||
if (ivl_expr_width(expr) > 1)
|
||||
fprintf(vvp_out, " %%or/r;\n");
|
||||
|
||||
fprintf(vvp_out, " %%flag_set/vec4 %d;\n", use_flag);
|
||||
|
||||
return use_flag;
|
||||
}
|
||||
|
||||
static int draw_condition_binary_compare(ivl_expr_t expr)
|
||||
{
|
||||
ivl_expr_t le = ivl_expr_oper1(expr);
|
||||
ivl_expr_t re = ivl_expr_oper2(expr);
|
||||
|
||||
if ((ivl_expr_value(le) == IVL_VT_REAL)
|
||||
|| (ivl_expr_value(re) == IVL_VT_REAL)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_STRING)
|
||||
&& (ivl_expr_value(re)==IVL_VT_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_STRING)
|
||||
&& (ivl_expr_type(re)==IVL_EX_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_type(le)==IVL_EX_STRING)
|
||||
&& (ivl_expr_value(re)==IVL_VT_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_CLASS)
|
||||
&& (ivl_expr_value(re)==IVL_VT_CLASS)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
unsigned use_wid = ivl_expr_width(le);
|
||||
if (ivl_expr_width(re) > use_wid)
|
||||
use_wid = ivl_expr_width(re);
|
||||
|
||||
/* If the le is constant, then swap the operands so that we
|
||||
can possibly take advantage of the immediate version of the
|
||||
%cmp instruction. */
|
||||
if (ivl_expr_width(le)==use_wid && test_immediate_vec4_ok(le)) {
|
||||
ivl_expr_t tmp = le;
|
||||
re = le;
|
||||
le = tmp;
|
||||
}
|
||||
|
||||
draw_eval_vec4(le);
|
||||
resize_vec4_wid(le, use_wid);
|
||||
|
||||
char use_opcode = ivl_expr_opcode(expr);
|
||||
|
||||
|
||||
if (ivl_expr_width(re)==use_wid && test_immediate_vec4_ok(re)) {
|
||||
/* Special case: If the right operand can be handled as
|
||||
an immediate operand, then use that instead. */
|
||||
if (use_opcode=='n' || use_opcode=='N')
|
||||
draw_immediate_vec4(re, "%cmpi/ne");
|
||||
else
|
||||
draw_immediate_vec4(re, "%cmpi/e");
|
||||
} else {
|
||||
draw_eval_vec4(re);
|
||||
resize_vec4_wid(re, use_wid);
|
||||
if (use_opcode=='n' || use_opcode=='N')
|
||||
fprintf(vvp_out, " %%cmp/ne;\n");
|
||||
else
|
||||
fprintf(vvp_out, " %%cmp/e;\n");
|
||||
}
|
||||
|
||||
switch (ivl_expr_opcode(expr)) {
|
||||
case 'n': /* != */
|
||||
case 'e': /* == */
|
||||
return 4;
|
||||
break;
|
||||
case 'N': /* !== */
|
||||
case 'E': /* === */
|
||||
return 6;
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int draw_condition_binary_real_le(ivl_expr_t expr)
|
||||
{
|
||||
ivl_expr_t le = ivl_expr_oper1(expr);
|
||||
ivl_expr_t re = ivl_expr_oper2(expr);
|
||||
ivl_expr_t tmp;
|
||||
|
||||
char use_opcode = ivl_expr_opcode(expr);
|
||||
|
||||
/* If this is a > or >=, then convert it to < or <= by
|
||||
swapping the operands. Adjust the opcode to match. */
|
||||
switch (use_opcode) {
|
||||
case 'G':
|
||||
tmp = le;
|
||||
le = re;
|
||||
re = tmp;
|
||||
use_opcode = 'L';
|
||||
break;
|
||||
case '>':
|
||||
tmp = le;
|
||||
le = re;
|
||||
re = tmp;
|
||||
use_opcode = '<';
|
||||
break;
|
||||
}
|
||||
|
||||
draw_eval_real(le);
|
||||
draw_eval_real(re);
|
||||
|
||||
fprintf(vvp_out, " %%cmp/wr;\n");
|
||||
|
||||
switch (use_opcode) {
|
||||
case '<':
|
||||
return 5;
|
||||
case 'L':
|
||||
fprintf(vvp_out, " %%flag_or 5, 4;\n");
|
||||
return 5;
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int draw_condition_binary_le(ivl_expr_t expr)
|
||||
{
|
||||
ivl_expr_t le = ivl_expr_oper1(expr);
|
||||
ivl_expr_t re = ivl_expr_oper2(expr);
|
||||
ivl_expr_t tmp;
|
||||
|
||||
if ((ivl_expr_value(le) == IVL_VT_REAL)
|
||||
|| (ivl_expr_value(re) == IVL_VT_REAL)) {
|
||||
return draw_condition_binary_real_le(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_STRING)
|
||||
&& (ivl_expr_value(re)==IVL_VT_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_STRING)
|
||||
&& (ivl_expr_type(re)==IVL_EX_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_type(le)==IVL_EX_STRING)
|
||||
&& (ivl_expr_value(re)==IVL_VT_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
char use_opcode = ivl_expr_opcode(expr);
|
||||
char s_flag = (ivl_expr_signed(le) && ivl_expr_signed(re)) ? 's' : 'u';
|
||||
|
||||
/* If this is a > or >=, then convert it to < or <= by
|
||||
swapping the operands. Adjust the opcode to match. */
|
||||
switch (use_opcode) {
|
||||
case 'G':
|
||||
tmp = le;
|
||||
le = re;
|
||||
re = tmp;
|
||||
use_opcode = 'L';
|
||||
break;
|
||||
case '>':
|
||||
tmp = le;
|
||||
le = re;
|
||||
re = tmp;
|
||||
use_opcode = '<';
|
||||
break;
|
||||
}
|
||||
|
||||
/* NOTE: I think I would rather the elaborator handle the
|
||||
operand widths. When that happens, take this code out. */
|
||||
|
||||
unsigned use_wid = ivl_expr_width(le);
|
||||
if (ivl_expr_width(re) > use_wid)
|
||||
use_wid = ivl_expr_width(re);
|
||||
|
||||
draw_eval_vec4(le);
|
||||
resize_vec4_wid(le, use_wid);
|
||||
|
||||
if (ivl_expr_width(re)==use_wid && test_immediate_vec4_ok(re)) {
|
||||
/* Special case: If the right operand can be handled as
|
||||
an immediate operand, then use that instead. */
|
||||
char opcode[8];
|
||||
snprintf(opcode, sizeof opcode, "%%cmpi/%c", s_flag);
|
||||
draw_immediate_vec4(re, opcode);
|
||||
|
||||
} else {
|
||||
draw_eval_vec4(re);
|
||||
resize_vec4_wid(re, use_wid);
|
||||
|
||||
fprintf(vvp_out, " %%cmp/%c;\n", s_flag);
|
||||
}
|
||||
|
||||
switch (use_opcode) {
|
||||
case '<':
|
||||
return 5;
|
||||
case 'L':
|
||||
fprintf(vvp_out, " %%flag_or 5, 4;\n");
|
||||
return 5;
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int draw_condition_binary_lor(ivl_expr_t expr)
|
||||
{
|
||||
ivl_expr_t le = ivl_expr_oper1(expr);
|
||||
ivl_expr_t re = ivl_expr_oper2(expr);
|
||||
|
||||
int lx = draw_eval_condition(le);
|
||||
|
||||
if (lx < 8) {
|
||||
int tmp = allocate_flag();
|
||||
fprintf(vvp_out, " %%flag_mov %d, %d;\n", tmp, lx);
|
||||
lx = tmp;
|
||||
}
|
||||
|
||||
int rx = draw_eval_condition(re);
|
||||
|
||||
fprintf(vvp_out, " %%flag_or %d, %d;\n", rx, lx);
|
||||
clr_flag(lx);
|
||||
return rx;
|
||||
}
|
||||
|
||||
static int draw_condition_binary(ivl_expr_t expr)
|
||||
{
|
||||
switch (ivl_expr_opcode(expr)) {
|
||||
case 'e': /* == */
|
||||
case 'E': /* === */
|
||||
case 'n': /* != */
|
||||
case 'N': /* !== */
|
||||
return draw_condition_binary_compare(expr);
|
||||
case '<':
|
||||
case '>':
|
||||
case 'L': /* <= */
|
||||
case 'G': /* >= */
|
||||
return draw_condition_binary_le(expr);
|
||||
case 'o': /* Logical or (||) */
|
||||
return draw_condition_binary_lor(expr);
|
||||
default:
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
}
|
||||
|
||||
int draw_eval_condition(ivl_expr_t expr)
|
||||
{
|
||||
switch (ivl_expr_type(expr)) {
|
||||
case IVL_EX_BINARY:
|
||||
return draw_condition_binary(expr);
|
||||
default:
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
}
|
||||
+20
-3458
File diff suppressed because it is too large
Load Diff
+8
-14
@@ -58,7 +58,8 @@ static int eval_darray_new(ivl_expr_t ex)
|
||||
int wid = msb>=lsb? msb - lsb : lsb - msb;
|
||||
wid += 1;
|
||||
|
||||
fprintf(vvp_out, " %%new/darray %u, \"sb%d\";\n", size_reg, wid);
|
||||
fprintf(vvp_out, " %%new/darray %u, \"%sb%d\";\n", size_reg,
|
||||
ivl_type_signed(element_type) ? "s" : "", wid);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -68,18 +69,13 @@ static int eval_darray_new(ivl_expr_t ex)
|
||||
|
||||
if (init_expr && ivl_expr_type(init_expr)==IVL_EX_ARRAY_PATTERN) {
|
||||
unsigned idx;
|
||||
struct vector_info rvec;
|
||||
unsigned wid;
|
||||
switch (ivl_type_base(element_type)) {
|
||||
case IVL_VT_BOOL:
|
||||
wid = width_of_packed_type(element_type);
|
||||
for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) {
|
||||
rvec = draw_eval_expr_wid(ivl_expr_parm(init_expr,idx),
|
||||
wid, STUFF_OK_XZ);
|
||||
draw_eval_vec4(ivl_expr_parm(init_expr,idx));
|
||||
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
|
||||
fprintf(vvp_out, " %%set/dar/obj 3, %u, %u;\n",
|
||||
rvec.base, rvec.wid);
|
||||
if (rvec.base >= 4) clr_vector(rvec);
|
||||
fprintf(vvp_out, " %%set/dar/obj/vec4 3;\n");
|
||||
fprintf(vvp_out, " %%pop/vec4 1;\n");
|
||||
}
|
||||
break;
|
||||
case IVL_VT_REAL:
|
||||
@@ -110,18 +106,16 @@ static int eval_darray_new(ivl_expr_t ex)
|
||||
a constant. Generate an unrolled set of assignments. */
|
||||
long idx;
|
||||
long cnt = get_number_immediate(size_expr);
|
||||
struct vector_info rvec;
|
||||
unsigned wid;
|
||||
switch (ivl_type_base(element_type)) {
|
||||
case IVL_VT_BOOL:
|
||||
wid = width_of_packed_type(element_type);
|
||||
rvec = draw_eval_expr_wid(init_expr, wid, STUFF_OK_XZ);
|
||||
draw_eval_vec4(init_expr);
|
||||
resize_vec4_wid(init_expr, wid);
|
||||
for (idx = 0 ; idx < cnt ; idx += 1) {
|
||||
fprintf(vvp_out, " %%ix/load 3, %ld, 0;\n", idx);
|
||||
fprintf(vvp_out, " %%set/dar/obj 3, %u, %u;\n",
|
||||
rvec.base, rvec.wid);
|
||||
fprintf(vvp_out, " %%set/dar/obj/vec4 3;\n");
|
||||
}
|
||||
if (rvec.base >= 4) clr_vector(rvec);
|
||||
break;
|
||||
case IVL_VT_REAL:
|
||||
draw_eval_real(init_expr);
|
||||
|
||||
+25
-42
@@ -243,18 +243,16 @@ static void draw_realnum_real(ivl_expr_t expr)
|
||||
* The real value of a logic expression is the integer value of the
|
||||
* expression converted to real.
|
||||
*/
|
||||
static void draw_real_logic_expr(ivl_expr_t expr, int stuff_ok_flag)
|
||||
static void draw_real_logic_expr(ivl_expr_t expr)
|
||||
{
|
||||
struct vector_info sv = draw_eval_expr(expr, stuff_ok_flag);
|
||||
draw_eval_vec4(expr);
|
||||
const char*sign_flag = ivl_expr_signed(expr)? "/s" : "";
|
||||
|
||||
if (sv.wid > 64) {
|
||||
fprintf(vvp_out, " %%cvt/rv%s %u, %u;\n",
|
||||
sign_flag, sv.base, sv.wid);
|
||||
if (ivl_expr_width(expr) > 64) {
|
||||
fprintf(vvp_out, " %%cvt/rv%s;\n", sign_flag);
|
||||
} else {
|
||||
int res = allocate_word();
|
||||
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
|
||||
sign_flag, res, sv.base, sv.wid);
|
||||
fprintf(vvp_out, " %%ix/vec4%s %d;\n", sign_flag, res);
|
||||
|
||||
if (ivl_expr_signed(expr))
|
||||
fprintf(vvp_out, " %%cvt/rs %d;\n", res);
|
||||
@@ -262,8 +260,6 @@ static void draw_real_logic_expr(ivl_expr_t expr, int stuff_ok_flag)
|
||||
fprintf(vvp_out, " %%cvt/ru %d;\n", res);
|
||||
clr_word(res);
|
||||
}
|
||||
|
||||
clr_vector(sv);
|
||||
}
|
||||
|
||||
static void draw_select_real(ivl_expr_t expr)
|
||||
@@ -287,7 +283,7 @@ static void draw_sfunc_real(ivl_expr_t expr)
|
||||
|
||||
case IVL_VT_REAL:
|
||||
if (ivl_expr_parms(expr) == 0) {
|
||||
fprintf(vvp_out, " %%vpi_func/r %u %u \"%s\" {0 0};\n",
|
||||
fprintf(vvp_out, " %%vpi_func/r %u %u \"%s\" {0 0 0};\n",
|
||||
ivl_file_table_index(ivl_expr_file(expr)),
|
||||
ivl_expr_lineno(expr), ivl_expr_name(expr));
|
||||
|
||||
@@ -300,7 +296,7 @@ static void draw_sfunc_real(ivl_expr_t expr)
|
||||
/* If the value of the sfunc is a vector, then evaluate
|
||||
it as a vector, then convert the result to a real
|
||||
(via an index register) for the result. */
|
||||
draw_real_logic_expr(expr, 0);
|
||||
draw_real_logic_expr(expr);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -330,7 +326,7 @@ static void draw_signal_real(ivl_expr_t expr)
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
switch (ivl_signal_data_type(sig)) {
|
||||
case IVL_VT_LOGIC:
|
||||
draw_real_logic_expr(expr, 0);
|
||||
draw_real_logic_expr(expr);
|
||||
return;
|
||||
case IVL_VT_REAL:
|
||||
draw_signal_real_real(expr);
|
||||
@@ -352,35 +348,27 @@ static void draw_ternary_real(ivl_expr_t expr)
|
||||
ivl_expr_t true_ex = ivl_expr_oper2(expr);
|
||||
ivl_expr_t false_ex = ivl_expr_oper3(expr);
|
||||
|
||||
struct vector_info tst;
|
||||
|
||||
unsigned lab_true = local_count++;
|
||||
unsigned lab_out = local_count++;
|
||||
|
||||
int cond_flag = allocate_flag();
|
||||
|
||||
/* Evaluate the ternary condition. */
|
||||
tst = draw_eval_expr(cond, STUFF_OK_XZ|STUFF_OK_RO);
|
||||
if ((tst.base >= 4) && (tst.wid > 1)) {
|
||||
struct vector_info tmp;
|
||||
draw_eval_vec4(cond);
|
||||
if (ivl_expr_width(cond) > 1)
|
||||
fprintf(vvp_out, " %%or/r;\n");
|
||||
|
||||
fprintf(vvp_out, " %%or/r %u, %u, %u;\n",
|
||||
tst.base, tst.base, tst.wid);
|
||||
fprintf(vvp_out, " %%flag_set/vec4 %d;\n", cond_flag);
|
||||
|
||||
tmp = tst;
|
||||
tmp.base += 1;
|
||||
tmp.wid -= 1;
|
||||
clr_vector(tmp);
|
||||
|
||||
tst.wid = 1;
|
||||
}
|
||||
|
||||
/* Evaluate the true expression second. */
|
||||
fprintf(vvp_out, " %%jmp/1 T_%u.%u, %u;\n",
|
||||
thread_count, lab_true, tst.base);
|
||||
fprintf(vvp_out, " %%jmp/1 T_%u.%u, %d;\n",
|
||||
thread_count, lab_true, cond_flag);
|
||||
|
||||
/* Evaluate the false expression. */
|
||||
draw_eval_real(false_ex);
|
||||
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %u; End of false expr.\n",
|
||||
thread_count, lab_out, tst.base);
|
||||
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d; End of false expr.\n",
|
||||
thread_count, lab_out, cond_flag);
|
||||
|
||||
/* If the conditional is undefined then blend the real words. */
|
||||
draw_eval_real(true_ex);
|
||||
@@ -395,7 +383,7 @@ static void draw_ternary_real(ivl_expr_t expr)
|
||||
/* This is the out label. */
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
|
||||
|
||||
clr_vector(tst);
|
||||
clr_flag(cond_flag);
|
||||
}
|
||||
|
||||
static void increment(ivl_expr_t e, bool pre)
|
||||
@@ -428,20 +416,18 @@ static void draw_unary_real(ivl_expr_t expr)
|
||||
* a real expression, so use vector evaluation and then convert
|
||||
* that result to a real value. */
|
||||
if ((ivl_expr_opcode(expr) == '~') || (ivl_expr_opcode(expr) == '!')) {
|
||||
draw_real_logic_expr(expr, STUFF_OK_XZ);
|
||||
draw_real_logic_expr(expr);
|
||||
return;
|
||||
}
|
||||
|
||||
sube = ivl_expr_oper1(expr);
|
||||
|
||||
if (ivl_expr_opcode(expr) == 'r') { /* Cast an integer value to a real. */
|
||||
struct vector_info res;
|
||||
const char *suffix = "";
|
||||
assert(ivl_expr_value(sube) != IVL_VT_REAL);
|
||||
res = draw_eval_expr(sube, 1);
|
||||
draw_eval_vec4(sube);
|
||||
if (ivl_expr_signed(sube)) suffix = "/s";
|
||||
fprintf(vvp_out, " %%cvt/rv%s %u, %u;\n", suffix, res.base, res.wid);
|
||||
clr_vector(res);
|
||||
fprintf(vvp_out, " %%cvt/rv%s;\n", suffix);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -499,7 +485,7 @@ void draw_eval_real(ivl_expr_t expr)
|
||||
* result to a real value. This is required to get integer
|
||||
* division to work correctly. */
|
||||
if (ivl_expr_value(expr) != IVL_VT_REAL) {
|
||||
draw_real_logic_expr(expr, STUFF_OK_XZ);
|
||||
draw_real_logic_expr(expr);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -547,15 +533,12 @@ void draw_eval_real(ivl_expr_t expr)
|
||||
|
||||
default:
|
||||
if (ivl_expr_value(expr) == IVL_VT_VECTOR) {
|
||||
struct vector_info sv = draw_eval_expr(expr, 0);
|
||||
draw_eval_vec4(expr);
|
||||
const char*sign_flag = ivl_expr_signed(expr)? "/s" : "";
|
||||
|
||||
clr_vector(sv);
|
||||
int res = allocate_word();
|
||||
|
||||
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
|
||||
sign_flag, res, sv.base, sv.wid);
|
||||
|
||||
fprintf(vvp_out, " %%ix/vec4%s %d;\n", sign_flag, res);
|
||||
fprintf(vvp_out, " %%cvt/rs %d;\n", res);
|
||||
|
||||
clr_word(res);
|
||||
|
||||
@@ -23,11 +23,8 @@
|
||||
|
||||
static void fallback_eval(ivl_expr_t expr)
|
||||
{
|
||||
struct vector_info res = draw_eval_expr(expr, 0);
|
||||
fprintf(vvp_out, " %%pushv/str %u, %u; Cast BOOL/LOGIC to string\n",
|
||||
res.base, res.wid);
|
||||
if (res.base > 0)
|
||||
clr_vector(res);
|
||||
draw_eval_vec4(expr);
|
||||
fprintf(vvp_out, " %%pushv/str; Cast BOOL/LOGIC to string\n");
|
||||
}
|
||||
|
||||
static void string_ex_concat(ivl_expr_t expr)
|
||||
|
||||
+1318
File diff suppressed because it is too large
Load Diff
+217
-430
@@ -82,7 +82,7 @@ struct vec_slice_info {
|
||||
};
|
||||
|
||||
static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice,
|
||||
unsigned bit, unsigned wid)
|
||||
unsigned wid)
|
||||
{
|
||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
|
||||
@@ -116,8 +116,7 @@ static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice
|
||||
|
||||
slice->type = SLICE_SIMPLE_VECTOR;
|
||||
slice->u_.simple_vector.use_word = use_word;
|
||||
fprintf(vvp_out, " %%load/v %u, v%p_%lu, %u;\n",
|
||||
bit, sig, use_word, wid);
|
||||
fprintf(vvp_out, " %%load/vec4 v%p_%lu;\n", sig, use_word);
|
||||
|
||||
} else if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0) {
|
||||
|
||||
@@ -126,35 +125,26 @@ static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice
|
||||
slice->type = SLICE_PART_SELECT_STATIC;
|
||||
slice->u_.part_select_static.part_off = part_off;
|
||||
|
||||
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
|
||||
fprintf(vvp_out, " %%load/x1p %u, v%p_0, %u;\n", bit, sig, wid);
|
||||
fprintf(vvp_out, " %%load/vec4 v%p_%lu;\n", sig, use_word);
|
||||
fprintf(vvp_out, " %%pushi/vec4 %lu, 0, 32;\n", part_off);
|
||||
fprintf(vvp_out, " %%part/u %u;\n", wid);
|
||||
|
||||
} else if (ivl_signal_dimensions(sig)==0 && part_off_ex!=0 && word_ix==0) {
|
||||
|
||||
unsigned skip_set = transient_id++;
|
||||
unsigned out_set = transient_id++;
|
||||
|
||||
assert(use_word == 0);
|
||||
assert(part_off == 0);
|
||||
|
||||
slice->type = SLICE_PART_SELECT_DYNAMIC;
|
||||
|
||||
draw_eval_expr_into_integer(part_off_ex, 1);
|
||||
|
||||
slice->u_.part_select_dynamic.word_idx_reg = allocate_word();
|
||||
slice->u_.part_select_dynamic.x_flag = allocate_vector(1);
|
||||
slice->u_.part_select_dynamic.x_flag = allocate_flag();
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, 1;\n",
|
||||
slice->u_.part_select_dynamic.x_flag, 4);
|
||||
fprintf(vvp_out, " %%mov/wu %d, %d;\n",
|
||||
slice->u_.part_select_dynamic.word_idx_reg, 1);
|
||||
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%load/x1p %u, v%p_0, %u;\n", bit, sig, wid);
|
||||
fprintf(vvp_out, " %%jmp t_%u;\n", out_set);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
fprintf(vvp_out, " %%mov %u, 2, %u;\n", bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", out_set);
|
||||
fprintf(vvp_out, " %%load/vec4 v%p_%lu;\n", sig, use_word);
|
||||
draw_eval_vec4(part_off_ex);
|
||||
fprintf(vvp_out, " %%flag_mov %u, 4;\n", slice->u_.part_select_dynamic.x_flag);
|
||||
fprintf(vvp_out, " %%dup/vec4;\n");
|
||||
fprintf(vvp_out, " %%ix/vec4 %u;\n", slice->u_.part_select_dynamic.word_idx_reg);
|
||||
fprintf(vvp_out, " %%part/u %u;\n", wid);
|
||||
|
||||
} else if (ivl_signal_dimensions(sig) > 0 && word_ix == 0) {
|
||||
|
||||
@@ -163,156 +153,146 @@ static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice
|
||||
if (use_word < ivl_signal_array_count(sig)) {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n",
|
||||
use_word);
|
||||
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
|
||||
bit, sig, wid);
|
||||
fprintf(vvp_out, " %%load/vec4a v%p, 3;\n", sig);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%mov %u, 2, %u; OUT OF BOUNDS\n",
|
||||
bit, wid);
|
||||
assert(wid <= 32);
|
||||
fprintf(vvp_out, " %%pushi/vec4 4294967295, 4294967295, %u;\n", wid);
|
||||
}
|
||||
|
||||
} else if (ivl_signal_dimensions(sig) > 0 && word_ix != 0) {
|
||||
|
||||
unsigned skip_set = transient_id++;
|
||||
unsigned out_set = transient_id++;
|
||||
slice->type = SLICE_MEMORY_WORD_DYNAMIC;
|
||||
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
slice->u_.memory_word_dynamic.word_idx_reg = allocate_word();
|
||||
slice->u_.memory_word_dynamic.x_flag = allocate_vector(1);
|
||||
fprintf(vvp_out, " %%mov/wu %d, 3;\n",
|
||||
slice->u_.memory_word_dynamic.word_idx_reg);
|
||||
fprintf(vvp_out, " %%mov %u, 4, 1;\n",
|
||||
slice->u_.memory_word_dynamic.x_flag);
|
||||
slice->u_.memory_word_dynamic.x_flag = allocate_flag();
|
||||
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
||||
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
|
||||
bit, sig, wid);
|
||||
fprintf(vvp_out, " %%jmp t_%u;\n", out_set);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
fprintf(vvp_out, " %%mov %u, 2, %u;\n", bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", out_set);
|
||||
draw_eval_expr_into_integer(word_ix, slice->u_.memory_word_dynamic.word_idx_reg);
|
||||
fprintf(vvp_out, " %%flag_mov %d, 4;\n", slice->u_.memory_word_dynamic.x_flag);
|
||||
fprintf(vvp_out, " %%load/vec4a v%p, %d;\n", sig, slice->u_.memory_word_dynamic.word_idx_reg);
|
||||
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
static struct vector_info get_vec_from_lval(ivl_statement_t net,
|
||||
struct vec_slice_info*slices)
|
||||
/*
|
||||
* This loads the l-value values into the top of the stack, and also
|
||||
* leaves in the slices the information needed to store the slice
|
||||
* results back.
|
||||
*/
|
||||
static void get_vec_from_lval(ivl_statement_t net, struct vec_slice_info*slices)
|
||||
{
|
||||
struct vector_info res;
|
||||
unsigned lidx;
|
||||
unsigned cur_bit;
|
||||
|
||||
res.wid = ivl_stmt_lwidth(net);
|
||||
res.base = allocate_vector(res.wid);
|
||||
unsigned wid = ivl_stmt_lwidth(net);
|
||||
|
||||
cur_bit = 0;
|
||||
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
||||
unsigned bidx;
|
||||
ivl_lval_t lval;
|
||||
unsigned bit_limit = res.wid - cur_bit;
|
||||
unsigned bit_limit = wid - cur_bit;
|
||||
|
||||
lval = ivl_stmt_lval(net, lidx);
|
||||
|
||||
if (bit_limit > ivl_lval_width(lval))
|
||||
bit_limit = ivl_lval_width(lval);
|
||||
|
||||
bidx = res.base + cur_bit;
|
||||
|
||||
get_vec_from_lval_slice(lval, slices+lidx, bidx, bit_limit);
|
||||
get_vec_from_lval_slice(lval, slices+lidx, bit_limit);
|
||||
if (lidx > 0) {
|
||||
fprintf(vvp_out, " %%concat/vec4;\n");
|
||||
}
|
||||
|
||||
cur_bit += bit_limit;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void put_vec_to_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice,
|
||||
unsigned bit, unsigned wid)
|
||||
unsigned wid)
|
||||
{
|
||||
unsigned skip_set = transient_id++;
|
||||
struct vector_info tmp;
|
||||
//unsigned skip_set = transient_id++;
|
||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||
int part_off_idx;
|
||||
|
||||
/* If the slice of the l-value is a BOOL variable, then cast
|
||||
the data to a BOOL vector so that the stores can be valid. */
|
||||
if (ivl_signal_data_type(sig) == IVL_VT_BOOL) {
|
||||
fprintf(vvp_out, " %%cast2 %u, %u, %u;\n", bit, bit, wid);
|
||||
fprintf(vvp_out, " %%cast2;\n");
|
||||
}
|
||||
|
||||
switch (slice->type) {
|
||||
default:
|
||||
fprintf(vvp_out, " ; XXXX slice->type=%d\n", slice->type);
|
||||
assert(0);
|
||||
break;
|
||||
|
||||
case SLICE_SIMPLE_VECTOR:
|
||||
fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
|
||||
sig, slice->u_.simple_vector.use_word, bit, wid);
|
||||
fprintf(vvp_out, " %%store/vec4 v%p_%lu, 0, %u;\n",
|
||||
sig, slice->u_.simple_vector.use_word, wid);
|
||||
break;
|
||||
|
||||
case SLICE_PART_SELECT_STATIC:
|
||||
fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n",
|
||||
slice->u_.part_select_static.part_off);
|
||||
fprintf(vvp_out, " %%set/x0 v%p_0, %u, %u;\n", sig, bit, wid);
|
||||
part_off_idx = allocate_word();
|
||||
fprintf(vvp_out, " %%ix/load %d, %lu, 0;\n",
|
||||
part_off_idx, slice->u_.part_select_static.part_off);
|
||||
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
|
||||
fprintf(vvp_out, " %%store/vec4 v%p_0, %d, %u;\n",
|
||||
sig, part_off_idx, wid);
|
||||
clr_word(part_off_idx);
|
||||
break;
|
||||
|
||||
case SLICE_PART_SELECT_DYNAMIC:
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, %u;\n", skip_set,
|
||||
fprintf(vvp_out, " %%flag_mov 4, %u;\n",
|
||||
slice->u_.part_select_dynamic.x_flag);
|
||||
fprintf(vvp_out, " %%mov/wu 0, %d;\n",
|
||||
slice->u_.part_select_dynamic.word_idx_reg);
|
||||
fprintf(vvp_out, " %%set/x0 v%p_0, %u, %u;\n", sig, bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
fprintf(vvp_out, " %%store/vec4 v%p_0, %d, %u;\n",
|
||||
sig, slice->u_.part_select_dynamic.word_idx_reg, wid);
|
||||
clr_word(slice->u_.part_select_dynamic.word_idx_reg);
|
||||
clr_flag(slice->u_.part_select_dynamic.x_flag);
|
||||
break;
|
||||
|
||||
case SLICE_MEMORY_WORD_STATIC:
|
||||
if (slice->u_.simple_vector.use_word >= ivl_signal_array_count(sig))
|
||||
break;
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n",
|
||||
slice->u_.simple_vector.use_word);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
if (slice->u_.memory_word_static.use_word < ivl_signal_array_count(sig)) {
|
||||
int word_idx = allocate_word();
|
||||
fprintf(vvp_out," %%flag_set/imm 4, 0;\n");
|
||||
fprintf(vvp_out," %%ix/load %d, %lu, 0;\n", word_idx, slice->u_.memory_word_static.use_word);
|
||||
fprintf(vvp_out," %%store/vec4a v%p, %d, 0;\n", sig, word_idx);
|
||||
clr_word(word_idx);
|
||||
} else {
|
||||
fprintf(vvp_out," ; Skip this slice write to v%p [%lu]\n", sig, slice->u_.memory_word_static.use_word);
|
||||
}
|
||||
break;
|
||||
|
||||
case SLICE_MEMORY_WORD_DYNAMIC:
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, %u;\n", skip_set,
|
||||
slice->u_.memory_word_dynamic.x_flag);
|
||||
fprintf(vvp_out, " %%mov/wu 3, %d;\n",
|
||||
slice->u_.memory_word_dynamic.word_idx_reg);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
ivl_lval_sig(lval), bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
|
||||
tmp.base = slice->u_.memory_word_dynamic.x_flag;
|
||||
tmp.wid = 1;
|
||||
clr_vector(tmp);
|
||||
fprintf(vvp_out, " %%flag_mov 4, %d;\n", slice->u_.memory_word_dynamic.x_flag);
|
||||
fprintf(vvp_out, " %%store/vec4a v%p, %d, 0;\n", sig, slice->u_.memory_word_dynamic.word_idx_reg);
|
||||
clr_word(slice->u_.memory_word_dynamic.word_idx_reg);
|
||||
clr_flag(slice->u_.memory_word_dynamic.x_flag);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void put_vec_to_lval(ivl_statement_t net, struct vec_slice_info*slices,
|
||||
struct vector_info res)
|
||||
static void put_vec_to_lval(ivl_statement_t net, struct vec_slice_info*slices)
|
||||
{
|
||||
unsigned lidx;
|
||||
unsigned cur_bit;
|
||||
|
||||
unsigned wid = ivl_stmt_lwidth(net);
|
||||
|
||||
cur_bit = 0;
|
||||
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
||||
unsigned bidx;
|
||||
ivl_lval_t lval;
|
||||
unsigned bit_limit = res.wid - cur_bit;
|
||||
unsigned bit_limit = wid - cur_bit;
|
||||
|
||||
lval = ivl_stmt_lval(net, lidx);
|
||||
|
||||
if (bit_limit > ivl_lval_width(lval))
|
||||
bit_limit = ivl_lval_width(lval);
|
||||
|
||||
bidx = res.base + cur_bit;
|
||||
if (lidx+1 < ivl_stmt_lvals(net))
|
||||
fprintf(vvp_out, " %%split/vec4 %u;\n", bit_limit);
|
||||
|
||||
put_vec_to_lval_slice(lval, slices+lidx, bidx, bit_limit);
|
||||
put_vec_to_lval_slice(lval, slices+lidx, bit_limit);
|
||||
|
||||
cur_bit += bit_limit;
|
||||
}
|
||||
@@ -343,231 +323,107 @@ static ivl_type_t draw_lval_expr(ivl_lval_t lval)
|
||||
return ivl_type_prop_type(sub_type, ivl_lval_property_idx(lval));
|
||||
}
|
||||
|
||||
static void set_vec_to_lval_slice_nest(ivl_lval_t lval, unsigned bit, unsigned wid)
|
||||
{
|
||||
ivl_lval_t lval_nest = ivl_lval_nest(lval);
|
||||
ivl_type_t ltype = draw_lval_expr(lval_nest);
|
||||
assert(ivl_type_base(ltype) == IVL_VT_CLASS);
|
||||
|
||||
fprintf(vvp_out, " %%store/prop/v %d, %u, %u;\n",
|
||||
ivl_lval_property_idx(lval), bit, wid);
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
}
|
||||
|
||||
static void set_vec_to_lval_slice(ivl_lval_t lval, unsigned bit, unsigned wid)
|
||||
{
|
||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
|
||||
unsigned long part_off = 0;
|
||||
|
||||
/* Although Verilog doesn't support it, we'll handle
|
||||
here the case of an l-value part select of an array
|
||||
word if the address is constant. */
|
||||
ivl_expr_t word_ix = ivl_lval_idx(lval);
|
||||
unsigned long use_word = 0;
|
||||
|
||||
/* If the l-value is nested, then it is something like a class
|
||||
with a chain of member names, so handle that elsewhere. */
|
||||
if (ivl_lval_nest(lval)) {
|
||||
set_vec_to_lval_slice_nest(lval, bit, wid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (part_off_ex == 0) {
|
||||
part_off = 0;
|
||||
} else if (number_is_immediate(part_off_ex, IMM_WID, 0) &&
|
||||
!number_is_unknown(part_off_ex)) {
|
||||
part_off = get_number_immediate(part_off_ex);
|
||||
part_off_ex = 0;
|
||||
}
|
||||
|
||||
/* If the word index is a constant expression, then evaluate
|
||||
it to select the word, and pay no further heed to the
|
||||
expression itself. Out-of-bounds and undefined indices are
|
||||
converted to a canonical index of 'bx during elaboration,
|
||||
and we don't try to optimise that case. */
|
||||
if (word_ix && number_is_immediate(word_ix, IMM_WID, 0) &&
|
||||
!number_is_unknown(word_ix)) {
|
||||
use_word = get_number_immediate(word_ix);
|
||||
assert(use_word < ivl_signal_array_count(sig));
|
||||
word_ix = 0;
|
||||
}
|
||||
|
||||
if (part_off_ex && ivl_signal_dimensions(sig) == 0) {
|
||||
unsigned skip_set = transient_id++;
|
||||
|
||||
/* There is a mux expression, so this must be a write to
|
||||
a bit-select l-val. Presumably, the x0 index register
|
||||
has been loaded wit the result of the evaluated
|
||||
part select base expression. */
|
||||
assert(!word_ix);
|
||||
|
||||
draw_eval_expr_into_integer(part_off_ex, 0);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
|
||||
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
|
||||
sig, use_word, bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
/* save_signal width of 0 CLEARS the signal from the
|
||||
lookaside. */
|
||||
save_signal_lookaside(bit, sig, use_word, 0);
|
||||
|
||||
} else if (part_off_ex && ivl_signal_dimensions(sig) > 0) {
|
||||
|
||||
/* Here we have a part select write into an array word. */
|
||||
unsigned skip_set = transient_id++;
|
||||
if (word_ix) {
|
||||
int part_off_reg = allocate_word();
|
||||
draw_eval_expr_into_integer(part_off_ex, part_off_reg);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%ix/mov 1, %d;\n", part_off_reg);
|
||||
clr_word(part_off_reg);
|
||||
} else {
|
||||
draw_eval_expr_into_integer(part_off_ex, 1);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
|
||||
}
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
|
||||
} else if ((part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig))
|
||||
&& ivl_signal_dimensions(sig) > 0) {
|
||||
|
||||
/* Here we have a part select write into an array word. */
|
||||
unsigned skip_set = transient_id++;
|
||||
if (word_ix) {
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
|
||||
}
|
||||
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
if (word_ix) /* Only need this label if word_ix is set. */
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
|
||||
} else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) {
|
||||
/* There is no mux expression, but a constant part
|
||||
offset. Load that into index x0 and generate a
|
||||
vector set instruction. */
|
||||
assert(ivl_lval_width(lval) == wid);
|
||||
|
||||
/* If the word index is a constant, then we can write
|
||||
directly to the word and save the index
|
||||
calculation. Also, note the special case that we are
|
||||
writing to a UWIRE. In that case, use the %force/x0
|
||||
instruction to get the desired effect. */
|
||||
if (word_ix == 0 && ivl_signal_type(sig)==IVL_SIT_UWIRE) {
|
||||
fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", part_off);
|
||||
fprintf(vvp_out, " %%force/x0 v%p_%lu, %u, %u;\n",
|
||||
sig, use_word, bit, wid);
|
||||
|
||||
} else if (word_ix == 0) {
|
||||
fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", part_off);
|
||||
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
|
||||
sig, use_word, bit, wid);
|
||||
|
||||
} else {
|
||||
unsigned skip_set = transient_id++;
|
||||
unsigned index_reg = 3;
|
||||
draw_eval_expr_into_integer(word_ix, index_reg);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
}
|
||||
/* save_signal width of 0 CLEARS the signal from the
|
||||
lookaside. */
|
||||
save_signal_lookaside(bit, sig, use_word, 0);
|
||||
|
||||
} else if (ivl_signal_dimensions(sig) > 0) {
|
||||
|
||||
/* If the word index is a constant, then we can write
|
||||
directly to the word and save the index calculation. */
|
||||
if (word_ix == 0) {
|
||||
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
|
||||
} else {
|
||||
unsigned skip_set = transient_id++;
|
||||
unsigned index_reg = 3;
|
||||
draw_eval_expr_into_integer(word_ix, index_reg);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
}
|
||||
/* save_signal width of 0 CLEARS the signal from the
|
||||
lookaside. */
|
||||
save_signal_lookaside(bit, sig, use_word, 0);
|
||||
|
||||
|
||||
} else {
|
||||
fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
|
||||
sig, use_word, bit, wid);
|
||||
/* save_signal width of 0 CLEARS the signal from the
|
||||
lookaside. */
|
||||
save_signal_lookaside(bit, sig, use_word, 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This is a private function to generate %set code for the
|
||||
* statement. At this point, the r-value is evaluated and stored in
|
||||
* the res vector, I just need to generate the %set statements for the
|
||||
* l-values of the assignment.
|
||||
* Store a vector from the vec4 stack to the statement l-values. This
|
||||
* all assumes that the value to be assigned is already on the top of
|
||||
* the stack.
|
||||
*
|
||||
* NOTE TO SELF: The %store/vec4 takes a width, but the %assign/vec4
|
||||
* instructions do not, instead relying on the expression width. I
|
||||
* think that it the proper way to do it, so soon I should change the
|
||||
* %store/vec4 to not include the width operand.
|
||||
*/
|
||||
static void set_vec_to_lval(ivl_statement_t net, struct vector_info res)
|
||||
static void store_vec4_to_lval(ivl_statement_t net)
|
||||
{
|
||||
unsigned wid = res.wid;
|
||||
unsigned lidx;
|
||||
unsigned cur_rbit = 0;
|
||||
for (unsigned lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
||||
ivl_lval_t lval = ivl_stmt_lval(net,lidx);
|
||||
ivl_signal_t lsig = ivl_lval_sig(lval);
|
||||
ivl_lval_t nest = ivl_lval_nest(lval);
|
||||
unsigned lwid = ivl_lval_width(lval);
|
||||
|
||||
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
||||
unsigned bidx;
|
||||
unsigned bit_limit = wid - cur_rbit;
|
||||
|
||||
ivl_lval_t lval = ivl_stmt_lval(net, lidx);
|
||||
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
|
||||
/* This is non-nil if the l-val is the word of a memory,
|
||||
and nil otherwise. */
|
||||
ivl_expr_t word_ex = ivl_lval_idx(lval);
|
||||
|
||||
/* Reduce bit_limit to the width of this l-value. */
|
||||
if (bit_limit > ivl_lval_width(lval))
|
||||
bit_limit = ivl_lval_width(lval);
|
||||
if (lidx+1 < ivl_stmt_lvals(net))
|
||||
fprintf(vvp_out, " %%split/vec4 %u;\n", lwid);
|
||||
|
||||
/* This is the address within the larger r-value of the
|
||||
bit that this l-value takes. */
|
||||
bidx = res.base < 4? res.base : (res.base+cur_rbit);
|
||||
if (word_ex) {
|
||||
/* Handle index into an array */
|
||||
int word_index = allocate_word();
|
||||
int part_index = 0;
|
||||
/* Calculate the word address into word_index */
|
||||
draw_eval_expr_into_integer(word_ex, word_index);
|
||||
/* If there is a part_offset, calculate it into part_index. */
|
||||
if (part_off_ex) {
|
||||
int flag_index = allocate_flag();
|
||||
part_index = allocate_word();
|
||||
fprintf(vvp_out, " %%flag_mov %d, 4;\n", flag_index);
|
||||
draw_eval_expr_into_integer(part_off_ex, part_index);
|
||||
fprintf(vvp_out, " %%flag_or 4, %d;\n", flag_index);
|
||||
clr_flag(flag_index);
|
||||
}
|
||||
|
||||
set_vec_to_lval_slice(lval, bidx, bit_limit);
|
||||
assert(lsig);
|
||||
fprintf(vvp_out, " %%store/vec4a v%p, %d, %d;\n",
|
||||
lsig, word_index, part_index);
|
||||
|
||||
/* Now we've consumed this many r-value bits for the
|
||||
current l-value. */
|
||||
cur_rbit += bit_limit;
|
||||
clr_word(word_index);
|
||||
if (part_index)
|
||||
clr_word(part_index);
|
||||
|
||||
} else if (part_off_ex) {
|
||||
/* Dynamically calculated part offset */
|
||||
int offset_index = allocate_word();
|
||||
draw_eval_expr_into_integer(part_off_ex, offset_index);
|
||||
/* Note that flag4 is set by the eval above. */
|
||||
assert(lsig);
|
||||
if (ivl_signal_type(lsig)==IVL_SIT_UWIRE) {
|
||||
fprintf(vvp_out, " %%force/vec4/off v%p_0, %u;\n",
|
||||
lsig, offset_index);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%store/vec4 v%p_0, %d, %u;\n",
|
||||
lsig, offset_index, lwid);
|
||||
}
|
||||
clr_word(offset_index);
|
||||
|
||||
} else if (nest) {
|
||||
/* No offset expression, but the l-value is
|
||||
nested, which probably means that it is a class
|
||||
member. We will use a property assign
|
||||
function. */
|
||||
assert(!lsig);
|
||||
ivl_type_t sub_type = draw_lval_expr(nest);
|
||||
assert(ivl_type_base(sub_type) == IVL_VT_CLASS);
|
||||
fprintf(vvp_out, " %%store/prop/v %u, %u;\n",
|
||||
ivl_lval_property_idx(lval), lwid);
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
|
||||
} else {
|
||||
/* No offset expression, so use simpler store function. */
|
||||
assert(lsig);
|
||||
assert(lwid == ivl_signal_width(lsig));
|
||||
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, %u;\n", lsig, lwid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int show_stmt_assign_vector(ivl_statement_t net)
|
||||
{
|
||||
ivl_expr_t rval = ivl_stmt_rval(net);
|
||||
struct vector_info res;
|
||||
struct vector_info lres = {0, 0};
|
||||
//struct vector_info res;
|
||||
//struct vector_info lres = {0, 0};
|
||||
struct vec_slice_info*slices = 0;
|
||||
int idx_reg;
|
||||
|
||||
/* If this is a compressed assignment, then get the contents
|
||||
of the l-value. We need these values as part of the r-value
|
||||
calculation. */
|
||||
if (ivl_stmt_opcode(net) != 0) {
|
||||
slices = calloc(ivl_stmt_lvals(net), sizeof(struct vec_slice_info));
|
||||
lres = get_vec_from_lval(net, slices);
|
||||
slices = calloc(ivl_stmt_lvals(net), sizeof(struct vec_slice_info));
|
||||
get_vec_from_lval(net, slices);
|
||||
}
|
||||
|
||||
/* Handle the special case that the expression is a real
|
||||
@@ -575,154 +431,99 @@ static int show_stmt_assign_vector(ivl_statement_t net)
|
||||
result to a vector. Then store that vector into the
|
||||
l-value. */
|
||||
if (ivl_expr_value(rval) == IVL_VT_REAL) {
|
||||
draw_eval_real(rval);
|
||||
draw_eval_real(rval);
|
||||
/* This is the accumulated with of the l-value of the
|
||||
assignment. */
|
||||
unsigned wid = ivl_stmt_lwidth(net);
|
||||
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits for "
|
||||
"r-value expression.\n", ivl_expr_file(rval),
|
||||
ivl_expr_lineno(rval), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%cvt/vr %u, %u;\n", res.base, res.wid);
|
||||
/* Convert a calculated real value to a vec4 value of
|
||||
the given width. We need to include the width of the
|
||||
result because real values to not have any inherit
|
||||
width. The real value will be popped, and a vec4
|
||||
value pushed. */
|
||||
fprintf(vvp_out, " %%cvt/vr %u;\n", wid);
|
||||
|
||||
} else if (ivl_expr_value(rval) == IVL_VT_STRING) {
|
||||
/* Special case: vector to string casting */
|
||||
ivl_lval_t lval = ivl_stmt_lval(net, 0);
|
||||
fprintf(vvp_out, " %%vpi_call %u %u \"$ivl_string_method$to_vec\", v%p_0, v%p_0 {0 0};\n",
|
||||
fprintf(vvp_out, " %%vpi_call %u %u \"$ivl_string_method$to_vec\", v%p_0, v%p_0 {0 0 0};\n",
|
||||
ivl_file_table_index(ivl_stmt_file(net)), ivl_stmt_lineno(net),
|
||||
ivl_expr_signal(rval), ivl_lval_sig(lval));
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
res = draw_eval_expr(rval, 0);
|
||||
unsigned wid = ivl_stmt_lwidth(net);
|
||||
draw_eval_vec4(rval);
|
||||
resize_vec4_wid(rval, wid);
|
||||
}
|
||||
|
||||
switch (ivl_stmt_opcode(net)) {
|
||||
case 0:
|
||||
set_vec_to_lval(net, res);
|
||||
store_vec4_to_lval(net);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
if (res.base > 3) {
|
||||
fprintf(vvp_out, " %%add %u, %u, %u;\n",
|
||||
res.base, lres.base, res.wid);
|
||||
clr_vector(lres);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%add %u, %u, %u;\n",
|
||||
lres.base, res.base, res.wid);
|
||||
res.base = lres.base;
|
||||
}
|
||||
put_vec_to_lval(net, slices, res);
|
||||
fprintf(vvp_out, " %%add;\n");
|
||||
put_vec_to_lval(net, slices);
|
||||
break;
|
||||
|
||||
case '-':
|
||||
fprintf(vvp_out, " %%sub %u, %u, %u;\n",
|
||||
lres.base, res.base, res.wid);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
res.base, lres.base, res.wid);
|
||||
clr_vector(lres);
|
||||
put_vec_to_lval(net, slices, res);
|
||||
fprintf(vvp_out, " %%sub;\n");
|
||||
put_vec_to_lval(net, slices);
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if (res.base > 3) {
|
||||
fprintf(vvp_out, " %%mul %u, %u, %u;\n",
|
||||
res.base, lres.base, res.wid);
|
||||
clr_vector(lres);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%mul %u, %u, %u;\n",
|
||||
lres.base, res.base, res.wid);
|
||||
res.base = lres.base;
|
||||
}
|
||||
put_vec_to_lval(net, slices, res);
|
||||
fprintf(vvp_out, " %%mul;\n");
|
||||
put_vec_to_lval(net, slices);
|
||||
break;
|
||||
|
||||
case '/':
|
||||
fprintf(vvp_out, " %%div%s %u, %u, %u;\n",
|
||||
ivl_expr_signed(rval)? "/s" : "",
|
||||
lres.base, res.base, res.wid);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
res.base, lres.base, res.wid);
|
||||
clr_vector(lres);
|
||||
put_vec_to_lval(net, slices, res);
|
||||
fprintf(vvp_out, " %%div%s;\n", ivl_expr_signed(rval)? "/s":"");
|
||||
put_vec_to_lval(net, slices);
|
||||
break;
|
||||
|
||||
case '%':
|
||||
fprintf(vvp_out, " %%mod%s %u, %u, %u;\n",
|
||||
ivl_expr_signed(rval)? "/s" : "",
|
||||
lres.base, res.base, res.wid);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
res.base, lres.base, res.wid);
|
||||
clr_vector(lres);
|
||||
put_vec_to_lval(net, slices, res);
|
||||
fprintf(vvp_out, " %%mod%s;\n", ivl_expr_signed(rval)? "/s":"");
|
||||
put_vec_to_lval(net, slices);
|
||||
break;
|
||||
|
||||
case '&':
|
||||
if (res.base > 3) {
|
||||
fprintf(vvp_out, " %%and %u, %u, %u;\n",
|
||||
res.base, lres.base, res.wid);
|
||||
clr_vector(lres);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%and %u, %u, %u;\n",
|
||||
lres.base, res.base, res.wid);
|
||||
res.base = lres.base;
|
||||
}
|
||||
put_vec_to_lval(net, slices, res);
|
||||
fprintf(vvp_out, " %%and;\n");
|
||||
put_vec_to_lval(net, slices);
|
||||
break;
|
||||
|
||||
case '|':
|
||||
if (res.base > 3) {
|
||||
fprintf(vvp_out, " %%or %u, %u, %u;\n",
|
||||
res.base, lres.base, res.wid);
|
||||
clr_vector(lres);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%or %u, %u, %u;\n",
|
||||
lres.base, res.base, res.wid);
|
||||
res.base = lres.base;
|
||||
}
|
||||
put_vec_to_lval(net, slices, res);
|
||||
fprintf(vvp_out, " %%or;\n");
|
||||
put_vec_to_lval(net, slices);
|
||||
break;
|
||||
|
||||
case '^':
|
||||
if (res.base > 3) {
|
||||
fprintf(vvp_out, " %%xor %u, %u, %u;\n",
|
||||
res.base, lres.base, res.wid);
|
||||
clr_vector(lres);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%xor %u, %u, %u;\n",
|
||||
lres.base, res.base, res.wid);
|
||||
res.base = lres.base;
|
||||
}
|
||||
put_vec_to_lval(net, slices, res);
|
||||
fprintf(vvp_out, " %%xor;\n");
|
||||
put_vec_to_lval(net, slices);
|
||||
break;
|
||||
|
||||
case 'l': /* lres <<= res */
|
||||
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", res.base, res.wid);
|
||||
fprintf(vvp_out, " %%shiftl/i0 %u, %u;\n", lres.base, res.wid);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
res.base, lres.base, res.wid);
|
||||
case 'l': /* lval <<= expr */
|
||||
idx_reg = allocate_word();
|
||||
fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg);
|
||||
fprintf(vvp_out, " %%shiftl %d;\n", idx_reg);
|
||||
clr_word(idx_reg);
|
||||
put_vec_to_lval(net, slices);
|
||||
break;
|
||||
|
||||
case 'r': /* lres >>= res */
|
||||
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", res.base, res.wid);
|
||||
fprintf(vvp_out, " %%shiftr/i0 %u, %u;\n", lres.base, res.wid);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
res.base, lres.base, res.wid);
|
||||
case 'r': /* lval >>= expr */
|
||||
idx_reg = allocate_word();
|
||||
fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg);
|
||||
fprintf(vvp_out, " %%shiftr %d;\n", idx_reg);
|
||||
clr_word(idx_reg);
|
||||
put_vec_to_lval(net, slices);
|
||||
break;
|
||||
|
||||
case 'R': /* lres >>>= res */
|
||||
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", res.base, res.wid);
|
||||
fprintf(vvp_out, " %%shiftr/s/i0 %u, %u;\n", lres.base, res.wid);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
res.base, lres.base, res.wid);
|
||||
case 'R': /* lval >>>= expr */
|
||||
idx_reg = allocate_word();
|
||||
fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg);
|
||||
fprintf(vvp_out, " %%shiftr/s %d;\n", idx_reg);
|
||||
clr_word(idx_reg);
|
||||
put_vec_to_lval(net, slices);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -733,8 +534,6 @@ static int show_stmt_assign_vector(ivl_statement_t net)
|
||||
|
||||
if (slices)
|
||||
free(slices);
|
||||
if (res.base > 3)
|
||||
clr_vector(res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -832,17 +631,15 @@ static int show_stmt_assign_sig_string(ivl_statement_t net)
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(ivl_expr_width(rval)==8);
|
||||
draw_eval_vec4(rval);
|
||||
|
||||
/* Calculate the character select for the word. */
|
||||
int mux_word = allocate_word();
|
||||
draw_eval_expr_into_integer(part, mux_word);
|
||||
|
||||
/* Evaluate the r-value as a vector. */
|
||||
struct vector_info rvec = draw_eval_expr_wid(rval, 8, STUFF_OK_XZ);
|
||||
fprintf(vvp_out, " %%putc/str/vec4 v%p_0, %d;\n", var, mux_word);
|
||||
|
||||
assert(rvec.wid == 8);
|
||||
fprintf(vvp_out, " %%putc/str/v v%p_0, %d, %u;\n", var, mux_word, rvec.base);
|
||||
|
||||
clr_vector(rvec);
|
||||
clr_word(mux_word);
|
||||
return 0;
|
||||
}
|
||||
@@ -879,25 +676,21 @@ static int show_stmt_assign_darray_pattern(ivl_statement_t net)
|
||||
|
||||
ivl_type_t element_type = ivl_type_element(var_type);
|
||||
unsigned idx;
|
||||
struct vector_info rvec;
|
||||
#if 0
|
||||
unsigned element_width = 1;
|
||||
if (ivl_type_base(element_type) == IVL_VT_BOOL)
|
||||
element_width = width_of_packed_type(element_type);
|
||||
else if (ivl_type_base(element_type) == IVL_VT_LOGIC)
|
||||
element_width = width_of_packed_type(element_type);
|
||||
|
||||
#endif
|
||||
assert(ivl_expr_type(rval) == IVL_EX_ARRAY_PATTERN);
|
||||
for (idx = 0 ; idx < ivl_expr_parms(rval) ; idx += 1) {
|
||||
switch (ivl_type_base(element_type)) {
|
||||
case IVL_VT_BOOL:
|
||||
case IVL_VT_LOGIC:
|
||||
rvec = draw_eval_expr_wid(ivl_expr_parm(rval,idx),
|
||||
element_width, STUFF_OK_XZ);
|
||||
draw_eval_vec4(ivl_expr_parm(rval,idx));
|
||||
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
|
||||
fprintf(vvp_out, " %%set/dar v%p_0, %u, %u;\n",
|
||||
var, rvec.base, rvec.wid);
|
||||
|
||||
if (rvec.base >= 4) clr_vector(rvec);
|
||||
fprintf(vvp_out, " %%store/dar/vec4 v%p_0;\n", var);
|
||||
break;
|
||||
|
||||
case IVL_VT_REAL:
|
||||
@@ -960,16 +753,13 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net)
|
||||
fprintf(vvp_out, " %%store/dar/str v%p_0;\n", var);
|
||||
|
||||
} else if (mux) {
|
||||
struct vector_info rvec = draw_eval_expr_wid(rval, ivl_lval_width(lval),
|
||||
STUFF_OK_XZ);
|
||||
/* The %set/dar expects the array index to be in index
|
||||
draw_eval_vec4(rval);
|
||||
|
||||
/* The %store/dar/vec4 expects the array index to be in index
|
||||
register 3. Calculate the index in place. */
|
||||
draw_eval_expr_into_integer(mux, 3);
|
||||
|
||||
fprintf(vvp_out, " %%set/dar v%p_0, %u, %u;\n",
|
||||
var, rvec.base, rvec.wid);
|
||||
|
||||
if (rvec.base >= 4) clr_vector(rvec);
|
||||
fprintf(vvp_out, " %%store/dar/vec4 v%p_0;\n", var);
|
||||
|
||||
} else if (ivl_expr_type(rval) == IVL_EX_ARRAY_PATTERN) {
|
||||
/* There is no l-value mux, but the r-value is an array
|
||||
@@ -1018,6 +808,7 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net)
|
||||
ivl_lval_t lval = ivl_stmt_lval(net, 0);
|
||||
ivl_expr_t rval = ivl_stmt_rval(net);
|
||||
ivl_signal_t sig= ivl_lval_sig(lval);
|
||||
unsigned lwid = ivl_lval_width(lval);
|
||||
|
||||
int prop_idx = ivl_lval_property_idx(lval);
|
||||
|
||||
@@ -1028,30 +819,26 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net)
|
||||
if (ivl_type_base(prop_type) == IVL_VT_BOOL) {
|
||||
assert(ivl_type_packed_dimensions(prop_type) == 1);
|
||||
assert(ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0));
|
||||
int wid = ivl_type_packed_msb(prop_type,0) - ivl_type_packed_lsb(prop_type,0) + 1;
|
||||
|
||||
struct vector_info val = draw_eval_expr_wid(rval, wid, STUFF_OK_XZ);
|
||||
draw_eval_vec4(rval);
|
||||
if (ivl_expr_value(rval)!=IVL_VT_BOOL)
|
||||
fprintf(vvp_out, " %%cast2;\n");
|
||||
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
||||
fprintf(vvp_out, " %%store/prop/v %d, %u, %u; Store in bool property %s\n",
|
||||
prop_idx, val.base, val.wid,
|
||||
ivl_type_prop_name(sig_type, prop_idx));
|
||||
fprintf(vvp_out, " %%store/prop/v %d, %u; Store in bool property %s\n",
|
||||
prop_idx, lwid, ivl_type_prop_name(sig_type, prop_idx));
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
clr_vector(val);
|
||||
|
||||
} else if (ivl_type_base(prop_type) == IVL_VT_LOGIC) {
|
||||
assert(ivl_type_packed_dimensions(prop_type) == 1);
|
||||
assert(ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0));
|
||||
int wid = ivl_type_packed_msb(prop_type,0) - ivl_type_packed_lsb(prop_type,0) + 1;
|
||||
|
||||
struct vector_info val = draw_eval_expr_wid(rval, wid, STUFF_OK_XZ);
|
||||
draw_eval_vec4(rval);
|
||||
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
||||
fprintf(vvp_out, " %%store/prop/v %d, %u, %u; Store in logic property %s\n",
|
||||
prop_idx, val.base, val.wid,
|
||||
ivl_type_prop_name(sig_type, prop_idx));
|
||||
fprintf(vvp_out, " %%store/prop/v %d, %u; Store in logic property %s\n",
|
||||
prop_idx, lwid, ivl_type_prop_name(sig_type, prop_idx));
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
clr_vector(val);
|
||||
|
||||
} else if (ivl_type_base(prop_type) == IVL_VT_REAL) {
|
||||
|
||||
|
||||
@@ -18,357 +18,3 @@
|
||||
|
||||
# include "vvp_priv.h"
|
||||
# include <assert.h>
|
||||
|
||||
/* Maximum vector bits in a thread. If a thread co-processor is
|
||||
* implemented, this value may need to be reduced. At that time
|
||||
* wider operations will need to be partitioned. For example
|
||||
* shift operations on WIDE (say > 64k bit) registers.
|
||||
*/
|
||||
#define MAX_VEC (256*1024)
|
||||
|
||||
static struct allocation_score_s {
|
||||
ivl_expr_t exp;
|
||||
ivl_signal_t sig;
|
||||
unsigned sig_word;
|
||||
unsigned exp_bit : 24;
|
||||
unsigned sig_bit : 24;
|
||||
unsigned alloc : 8;
|
||||
} allocation_map[MAX_VEC] = { {0, 0, 0, 0, 0, 0} };
|
||||
|
||||
/* This is the largest bit to have lookaside values. */
|
||||
static unsigned lookaside_top = 0;
|
||||
|
||||
static __inline__ ivl_expr_t peek_exp(unsigned addr)
|
||||
{
|
||||
return allocation_map[addr].exp;
|
||||
}
|
||||
|
||||
static __inline__ unsigned peek_exp_bit(unsigned addr)
|
||||
{
|
||||
return allocation_map[addr].exp_bit;
|
||||
}
|
||||
|
||||
static __inline__ void set_exp(unsigned addr, ivl_expr_t expr, unsigned ebit)
|
||||
{
|
||||
allocation_map[addr].exp = expr;
|
||||
allocation_map[addr].exp_bit = ebit;
|
||||
}
|
||||
|
||||
static __inline__ void set_sig(unsigned addr, ivl_signal_t expr,
|
||||
unsigned sig_word, unsigned ebit)
|
||||
{
|
||||
allocation_map[addr].sig = expr;
|
||||
allocation_map[addr].sig_word = sig_word;
|
||||
allocation_map[addr].sig_bit = ebit;
|
||||
}
|
||||
|
||||
/*
|
||||
* This clears a vector that was previously allocated by
|
||||
* allocate_vector. That is, it unmarks all the bits of the map that
|
||||
* represent this vector.
|
||||
*
|
||||
* If the vector is based in one of 4 constant bit values, then there
|
||||
* are no bits to clear. If the vector is based in the 4-8 result
|
||||
* area, then someone is broken.
|
||||
*/
|
||||
void clr_vector(struct vector_info vec)
|
||||
{
|
||||
unsigned idx;
|
||||
if (vec.base < 4)
|
||||
return;
|
||||
assert(vec.base >= 8);
|
||||
for (idx = 0 ; idx < vec.wid ; idx += 1) {
|
||||
assert( allocation_map[vec.base+idx].alloc > 0);
|
||||
allocation_map[vec.base+idx].alloc -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned allocate_vector_no_lookaside(unsigned wid, int skip_lookaside)
|
||||
{
|
||||
unsigned base = 8;
|
||||
unsigned idx = 0;
|
||||
|
||||
while (idx < wid) {
|
||||
if (base+idx >= MAX_VEC)
|
||||
return 0;
|
||||
|
||||
assert((base + idx) < MAX_VEC);
|
||||
if ((allocation_map[base+idx].alloc > 0)
|
||||
|| (skip_lookaside && peek_exp(base+idx))) {
|
||||
base = base + idx + 1;
|
||||
idx = 0;
|
||||
|
||||
} else {
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (idx = 0 ; idx < wid ; idx += 1) {
|
||||
allocation_map[base+idx].alloc += 1;
|
||||
set_exp(base+idx, 0, 0);
|
||||
set_sig(base+idx, 0, 0, 0);
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
/*
|
||||
* This unconditionally allocates a stretch of bits from the register
|
||||
* set. It never returns a bit addressed <8 (0-3 are constant, 4-7 are
|
||||
* condition codes).
|
||||
*
|
||||
* First try to allocate a vector without interfering with any bits
|
||||
* cached by the lookaside buffer. If that doesn't work, then try
|
||||
* again without worrying about trashing lookaside results. This
|
||||
* should lead to preferentially allocating new bits instead of
|
||||
* constantly overwriting intermediate results.
|
||||
*
|
||||
* If there is no space for a vector of the given width, then give up
|
||||
* and return 0.
|
||||
*/
|
||||
unsigned allocate_vector(unsigned wid)
|
||||
{
|
||||
unsigned base = allocate_vector_no_lookaside(wid, 1);
|
||||
|
||||
if (base == 0)
|
||||
base = allocate_vector_no_lookaside(wid, 0);
|
||||
return base;
|
||||
}
|
||||
|
||||
/*
|
||||
* This clears the expression cache of the allocation map. It is
|
||||
* called to prevent reuse of existing expressions, normally at the
|
||||
* start of a basic block, but also at the end of thread processing.
|
||||
*/
|
||||
void clear_expression_lookaside(void)
|
||||
{
|
||||
unsigned idx;
|
||||
|
||||
for (idx = 0 ; idx < lookaside_top ; idx += 1) {
|
||||
set_exp(idx, 0, 0);
|
||||
set_sig(idx, 0, 0, 0);
|
||||
}
|
||||
|
||||
lookaside_top = 0;
|
||||
}
|
||||
|
||||
static int test_expression_savable(ivl_expr_t expr)
|
||||
{
|
||||
switch (ivl_expr_type(expr)) {
|
||||
|
||||
case IVL_EX_NUMBER:
|
||||
case IVL_EX_STRING:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void save_expression_lookaside(unsigned addr, ivl_expr_t expr, unsigned wid)
|
||||
{
|
||||
unsigned idx;
|
||||
assert(addr >= 8);
|
||||
assert((addr+wid) <= MAX_VEC);
|
||||
|
||||
/* When saving an expression to the lookaside, also clear the
|
||||
signal saved in the lookaside for these bits. The reason is
|
||||
that an expression calculation will replace any signal
|
||||
bits. */
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
set_sig(addr+idx, 0, 0, 0);
|
||||
|
||||
/* Only certain types of expressions are savable. */
|
||||
if ( ! test_expression_savable(expr))
|
||||
return;
|
||||
|
||||
for (idx = 0 ; idx < wid ; idx += 1) {
|
||||
set_exp(addr+idx, expr, idx);
|
||||
}
|
||||
|
||||
if ((addr+wid) > lookaside_top)
|
||||
lookaside_top = addr+wid;
|
||||
}
|
||||
|
||||
static void clear_signal_lookaside_bit(unsigned idx, ivl_signal_t sig, unsigned sig_word)
|
||||
{
|
||||
if (allocation_map[idx].alloc > 0)
|
||||
return;
|
||||
if (allocation_map[idx].sig != sig)
|
||||
return;
|
||||
if (allocation_map[idx].sig_word != sig_word)
|
||||
return;
|
||||
|
||||
set_sig(idx, 0, 0, 0);
|
||||
}
|
||||
|
||||
void save_signal_lookaside(unsigned addr, ivl_signal_t sig, unsigned sig_word, unsigned wid)
|
||||
{
|
||||
unsigned idx;
|
||||
/* Don't bind any of the low bits to a signal. */
|
||||
if (addr < 8 && wid > 0)
|
||||
return;
|
||||
|
||||
assert((addr+wid) <= MAX_VEC);
|
||||
|
||||
for (idx = 8 ; idx < addr ; idx += 1)
|
||||
clear_signal_lookaside_bit(idx, sig, sig_word);
|
||||
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
set_sig(addr+idx, sig, sig_word, idx);
|
||||
|
||||
if ((addr+wid) > lookaside_top)
|
||||
lookaside_top = addr+wid;
|
||||
|
||||
for (idx = addr+wid ; idx < lookaside_top ; idx += 1)
|
||||
clear_signal_lookaside_bit(idx, sig, sig_word);
|
||||
}
|
||||
|
||||
static int compare_exp(ivl_expr_t l, ivl_expr_t r)
|
||||
{
|
||||
if (! (l && r))
|
||||
return 0;
|
||||
if (l == r)
|
||||
return 1;
|
||||
|
||||
if (ivl_expr_type(l) != ivl_expr_type(r))
|
||||
return 0;
|
||||
|
||||
switch (ivl_expr_type(l)) {
|
||||
|
||||
case IVL_EX_NUMBER:
|
||||
if (ivl_expr_width(l) != ivl_expr_width(r))
|
||||
return 0;
|
||||
{ const char*bitl = ivl_expr_bits(l);
|
||||
const char*bitr = ivl_expr_bits(r);
|
||||
unsigned idx;
|
||||
for (idx = 0 ; idx < ivl_expr_width(l) ; idx += 1) {
|
||||
if (bitl[idx] != bitr[idx])
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
|
||||
case IVL_EX_SELECT:
|
||||
if (! compare_exp(ivl_expr_oper1(l), ivl_expr_oper1(r)))
|
||||
return 0;
|
||||
|
||||
if (ivl_expr_oper2(l) == 0 && ivl_expr_oper1(r) == 0)
|
||||
return 1;
|
||||
|
||||
if (! compare_exp(ivl_expr_oper2(l), ivl_expr_oper2(r)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
case IVL_EX_SIGNAL:
|
||||
if (ivl_expr_signal(l) != ivl_expr_signal(r))
|
||||
return 0;
|
||||
|
||||
if (ivl_expr_width(l) != ivl_expr_width(r))
|
||||
return 0;
|
||||
|
||||
/* Don't match array words. */
|
||||
if (ivl_expr_oper1(l) || ivl_expr_oper1(r))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned find_expression_lookaside(ivl_expr_t expr, unsigned wid)
|
||||
{
|
||||
unsigned idx, match;
|
||||
ivl_signal_t sig;
|
||||
|
||||
if (lookaside_top <= wid)
|
||||
return 0;
|
||||
|
||||
/* Look in the expression lookaside for this expression. */
|
||||
assert(expr);
|
||||
match = 0;
|
||||
for (idx = 8 ; idx < lookaside_top ; idx += 1) {
|
||||
if (! compare_exp(allocation_map[idx].exp, expr)) {
|
||||
match = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (allocation_map[idx].exp_bit != match) {
|
||||
match = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
match += 1;
|
||||
if (match == wid)
|
||||
return idx-match+1;
|
||||
}
|
||||
|
||||
/* The general expression lookup failed. If this is an
|
||||
IVL_EX_SIGNAL, then look again in the variable lookaside
|
||||
(which is saved l-values) for the expression. */
|
||||
if (ivl_expr_type(expr) != IVL_EX_SIGNAL)
|
||||
return 0;
|
||||
|
||||
sig = ivl_expr_signal(expr);
|
||||
|
||||
/* Only reg signals (variables) will be in the signal
|
||||
lookaside, because only blocking assigned values are in the
|
||||
signal lookaside. */
|
||||
if (ivl_signal_type(sig) != IVL_SIT_REG)
|
||||
return 0;
|
||||
|
||||
/* Now look for signal value matches in the signal lookaside. */
|
||||
match = 0;
|
||||
for (idx = 8 ; idx < lookaside_top ; idx += 1) {
|
||||
if (sig != allocation_map[idx].sig) {
|
||||
match = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (allocation_map[idx].sig_bit != match) {
|
||||
match = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
match += 1;
|
||||
if (match == wid)
|
||||
return idx-match+1;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for the expression in the expression lookaside table. If it is
|
||||
* there, then allocate it and return the base. In this case the
|
||||
* caller will not need to evaluate the expression. If this function
|
||||
* returns 0, then the expression is not found and nothing is allocated.
|
||||
*/
|
||||
unsigned allocate_vector_exp(ivl_expr_t expr, unsigned wid,
|
||||
int exclusive_flag)
|
||||
{
|
||||
unsigned idx;
|
||||
unsigned la = find_expression_lookaside(expr, wid);
|
||||
if (la == 0)
|
||||
return 0;
|
||||
|
||||
if (exclusive_flag) {
|
||||
/* If the caller is requesting exclusive allocation of
|
||||
the expression, then return not-found if a lookup
|
||||
already matched the expression. */
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
if (allocation_map[la+idx].alloc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
allocation_map[la+idx].alloc += 1;
|
||||
|
||||
return la;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,13 @@ FILE*vvp_out = 0;
|
||||
int vvp_errors = 0;
|
||||
unsigned show_file_line = 0;
|
||||
|
||||
int debug_draw = 0;
|
||||
|
||||
# define FLAGS_COUNT 256
|
||||
|
||||
static uint32_t allocate_flag_mask[FLAGS_COUNT / 32] = { 0x000000ff, 0 };
|
||||
|
||||
|
||||
__inline__ static void draw_execute_header(ivl_design_t des)
|
||||
{
|
||||
const char*cp = ivl_design_flag(des, "VVP_EXECUTABLE");
|
||||
@@ -85,6 +92,55 @@ __inline__ static void draw_module_declarations(ivl_design_t des)
|
||||
}
|
||||
}
|
||||
|
||||
int allocate_flag(void)
|
||||
{
|
||||
int idx;
|
||||
for (idx = 0 ; idx < FLAGS_COUNT ; idx += 1) {
|
||||
int word = idx / 32;
|
||||
uint32_t mask = 1 << (idx%32);
|
||||
if (allocate_flag_mask[word] & mask)
|
||||
continue;
|
||||
|
||||
allocate_flag_mask[word] |= mask;
|
||||
return idx;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void clr_flag(int idx)
|
||||
{
|
||||
if (idx < 8) return;
|
||||
assert(idx < FLAGS_COUNT);
|
||||
int word = idx / 32;
|
||||
uint32_t mask = 1 << (idx%32);
|
||||
|
||||
assert(allocate_flag_mask[word] & mask);
|
||||
|
||||
allocate_flag_mask[word] &= ~mask;
|
||||
}
|
||||
|
||||
static void process_debug_string(const char*debug_string)
|
||||
{
|
||||
const char*cp = debug_string;
|
||||
debug_draw = 0;
|
||||
|
||||
while (*cp) {
|
||||
const char*tail = strchr(cp, ',');
|
||||
if (tail == 0)
|
||||
tail = cp + strlen(cp);
|
||||
|
||||
size_t len = tail - cp;
|
||||
if (len == 4 && strncmp(cp,"draw", 4)==0) {
|
||||
debug_draw = 1;
|
||||
}
|
||||
|
||||
while (*tail == ',')
|
||||
tail += 1;
|
||||
|
||||
cp = tail;
|
||||
}
|
||||
}
|
||||
|
||||
int target_design(ivl_design_t des)
|
||||
|
||||
@@ -100,6 +156,9 @@ int target_design(ivl_design_t des)
|
||||
* The default is no file/line information will be included. */
|
||||
const char*fileline = ivl_design_flag(des, "fileline");
|
||||
|
||||
const char*debug_flags = ivl_design_flag(des, "debug_flags");
|
||||
process_debug_string(debug_flags);
|
||||
|
||||
assert(path);
|
||||
|
||||
/* Check to see if file/line information should be included. */
|
||||
|
||||
+27
-97
@@ -28,6 +28,8 @@
|
||||
#endif
|
||||
|
||||
|
||||
extern int debug_draw;
|
||||
|
||||
/*
|
||||
* The target_design entry opens the output file that receives the
|
||||
* compiled design, and sets the vvp_out to the descriptor.
|
||||
@@ -105,13 +107,12 @@ extern int draw_scope(ivl_scope_t scope, ivl_scope_t parent);
|
||||
extern void draw_lpm_mux(ivl_lpm_t net);
|
||||
extern void draw_lpm_substitute(ivl_lpm_t net);
|
||||
|
||||
extern struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid);
|
||||
extern void draw_ufunc_vec4(ivl_expr_t expr);
|
||||
extern void draw_ufunc_real(ivl_expr_t expr);
|
||||
extern void draw_ufunc_string(ivl_expr_t expr);
|
||||
extern void draw_ufunc_object(ivl_expr_t expr);
|
||||
|
||||
extern void pad_expr_in_place(ivl_expr_t expr, struct vector_info res,
|
||||
unsigned swid);
|
||||
extern char* process_octal_codes(const char*txt, unsigned wid);
|
||||
|
||||
/*
|
||||
* modpath.c symbols.
|
||||
@@ -135,8 +136,7 @@ extern void cleanup_modpath(void);
|
||||
*/
|
||||
extern void draw_vpi_task_call(ivl_statement_t net);
|
||||
|
||||
extern struct vector_info draw_vpi_func_call(ivl_expr_t expr,
|
||||
unsigned wid);
|
||||
extern void draw_vpi_func_call(ivl_expr_t expr);
|
||||
extern void draw_vpi_rfunc_call(ivl_expr_t expr);
|
||||
|
||||
extern void draw_class_in_scope(ivl_type_t classtype);
|
||||
@@ -199,41 +199,6 @@ extern const char* draw_island_net_input(ivl_island_t island, ivl_nexus_t nex);
|
||||
*/
|
||||
extern const char*draw_input_from_net(ivl_nexus_t nex);
|
||||
|
||||
/*
|
||||
* The draw_eval_expr function writes out the code to evaluate a
|
||||
* behavioral expression.
|
||||
*
|
||||
* Expression results are placed into a vector allocated in the bit
|
||||
* space of the thread. The vector_info structure represents that
|
||||
* allocation. When the caller is done with the bits, it must release
|
||||
* the vector with clr_vector so that the code generator can reuse
|
||||
* those bits.
|
||||
*
|
||||
* The stuff_ok_flag is normally empty. Bits in the bitmask are set
|
||||
* true in cases where certain special situations are allows. This
|
||||
* might allow deeper expressions to make assumptions about the
|
||||
* caller.
|
||||
*
|
||||
* STUFF_OK_XZ -- This bit is set if the code processing the result
|
||||
* doesn't distinguish between x and z values.
|
||||
*
|
||||
* STUFF_OK_47 -- This bit is set if the node is allowed to leave a
|
||||
* result in any of the 4-7 vthread bits.
|
||||
*
|
||||
* STUFF_OK_RO -- This bit is set if the node is allowed to nest its
|
||||
* allocation from vector. It is only true if the client is not
|
||||
* planning to use this vector as an output. This matters only
|
||||
* if the expression might be found in the lookaside table, and
|
||||
* therefore might be multiply allocated if allowed.
|
||||
*/
|
||||
|
||||
extern struct vector_info draw_eval_expr(ivl_expr_t expr, int stuff_ok_flag);
|
||||
extern struct vector_info draw_eval_expr_wid(ivl_expr_t expr, unsigned w,
|
||||
int stuff_ok_flag);
|
||||
#define STUFF_OK_XZ 0x0001
|
||||
#define STUFF_OK_47 0x0002
|
||||
#define STUFF_OK_RO 0x0004
|
||||
|
||||
/*
|
||||
* This evaluates an expression and leaves the result in the numbered
|
||||
* integer index register. It also will set bit-4 to 1 if the value is
|
||||
@@ -242,71 +207,25 @@ extern struct vector_info draw_eval_expr_wid(ivl_expr_t expr, unsigned w,
|
||||
extern void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix);
|
||||
|
||||
/*
|
||||
* These functions manage vector allocation in the thread register
|
||||
* space. They presume that we work on one thread at a time, to
|
||||
* completion.
|
||||
*
|
||||
* allocate_vector
|
||||
* Return the base of an allocated vector in the thread. The bits
|
||||
* are marked allocated in the process.
|
||||
*
|
||||
* clr_vector
|
||||
* Clear a vector previously allocated.
|
||||
*
|
||||
* The thread vector allocator also keeps a lookaside of expression
|
||||
* results that are stored in register bit. This lookaside can be used
|
||||
* by the code generator to notice that certain expression bits are
|
||||
* already calculated, and can be reused.
|
||||
*
|
||||
* clear_expression_lookaside
|
||||
* Clear the lookaside tables for the current thread. This must be
|
||||
* called before starting a new thread, and around basic blocks
|
||||
* that are entered from unknown places.
|
||||
*
|
||||
* save_expression_lookaside
|
||||
* Mark the given expression as available in the given register
|
||||
* bits. This remains until the lookaside is cleared. This does not
|
||||
* clear the allocation, it is still necessary to call clr_vector.
|
||||
*
|
||||
* save_signal_lookaside
|
||||
* Mark the given signal as available in the given register bits.
|
||||
* This is different from a given expression, in that the signal
|
||||
* lookaside is in addition to the expression lookaside. The signal
|
||||
* lookaside is specifically to save on unnecessary loads of a
|
||||
* signal recently written.
|
||||
*
|
||||
* allocate_vector_exp
|
||||
* This function attempts to locate the expression in the
|
||||
* lookaside. If it finds it, return a reallocated base for the
|
||||
* expression. Otherwise, return 0.
|
||||
*
|
||||
* The allocate_vector and allocate_vector_exp calls must have
|
||||
* matching call to clr_vector. Although the allocate_vector will
|
||||
* never reallocate a vector already allocated, the allocate_vector_exp
|
||||
* might, so it is possible for allocations to nest in that
|
||||
* manner. The exclusive_flag to allocate_vector_exp will prevent
|
||||
* nested allocations. This is needed where the expression result is
|
||||
* expected to be overwritten.
|
||||
* This evaluates an expression as a condition flag and leaves the
|
||||
* result in a flag that is returned. This result may be used as an
|
||||
* operand for conditional jump instructions.
|
||||
*/
|
||||
extern unsigned allocate_vector(unsigned wid);
|
||||
extern void clr_vector(struct vector_info vec);
|
||||
extern int draw_eval_condition(ivl_expr_t expr);
|
||||
|
||||
extern void clear_expression_lookaside(void);
|
||||
extern void save_expression_lookaside(unsigned addr,
|
||||
ivl_expr_t expr,
|
||||
unsigned wid);
|
||||
extern void save_signal_lookaside(unsigned addr,
|
||||
ivl_signal_t sig, unsigned use_word,
|
||||
unsigned wid);
|
||||
|
||||
extern unsigned allocate_vector_exp(ivl_expr_t expr, unsigned wid,
|
||||
int exclusive_flag);
|
||||
|
||||
extern int number_is_unknown(ivl_expr_t ex);
|
||||
extern int number_is_immediate(ivl_expr_t ex, unsigned lim_wid, int negative_is_ok);
|
||||
extern long get_number_immediate(ivl_expr_t ex);
|
||||
extern uint64_t get_number_immediate64(ivl_expr_t ex);
|
||||
|
||||
/*
|
||||
* draw_eval_vec4 evaluates vec4 expressions. The result of the
|
||||
* evaluation is the vec4 result in the top of the vec4 expression stack.
|
||||
*/
|
||||
extern void draw_eval_vec4(ivl_expr_t ex);
|
||||
extern void resize_vec4_wid(ivl_expr_t expr, unsigned wid);
|
||||
|
||||
/*
|
||||
* draw_eval_real evaluates real value expressions. The result of the
|
||||
* evaluation is the real result in the top of the real expression stack.
|
||||
@@ -337,12 +256,23 @@ extern int draw_eval_object(ivl_expr_t ex);
|
||||
extern int show_stmt_assign(ivl_statement_t net);
|
||||
extern void show_stmt_file_line(ivl_statement_t net, const char*desc);
|
||||
|
||||
/*
|
||||
*/
|
||||
extern int test_immediate_vec4_ok(ivl_expr_t expr);
|
||||
extern void draw_immediate_vec4(ivl_expr_t expr, const char*opcode);
|
||||
|
||||
/*
|
||||
* These functions manage word register allocation.
|
||||
*/
|
||||
extern int allocate_word(void);
|
||||
extern void clr_word(int idx);
|
||||
|
||||
/*
|
||||
* These functions manage flag bit allocation.
|
||||
*/
|
||||
extern int allocate_flag(void);
|
||||
extern void clr_flag(int idx);
|
||||
|
||||
/*
|
||||
* These are used to count labels as I generate code.
|
||||
*/
|
||||
|
||||
+227
-360
File diff suppressed because it is too large
Load Diff
@@ -874,17 +874,6 @@ or &A<>/&PV<> select. The third form retrieves the <base> from thread
|
||||
space using <twid> bits starting at <tbase>. The base value may be
|
||||
signed or unsigned.
|
||||
|
||||
* The T<> argument
|
||||
|
||||
This is the catch-all for arguments that are not otherwise
|
||||
handled. This references the bits directly in the thread. The format
|
||||
is:
|
||||
|
||||
T '<' <base>, <wid>, <su> '>'
|
||||
|
||||
The <base> and <wid> are the base of a vector value in the thread and
|
||||
the width of the vector. The <su> is 's' or 'u' for signed or unsigned.
|
||||
|
||||
TRUTH TABLES
|
||||
|
||||
The logic that a functor represents is expressed as a truth table. The
|
||||
|
||||
+4
-74
@@ -70,10 +70,6 @@ struct __vpiArrayVthrA : public __vpiHandle {
|
||||
vpiHandle address_handle;
|
||||
// If wid==0, then address is the address into the array.
|
||||
unsigned address;
|
||||
// If wid >0, then the address is the base and wid the vector
|
||||
// width of the index to pull from the thread.
|
||||
unsigned wid;
|
||||
bool is_signed;
|
||||
|
||||
unsigned get_address() const
|
||||
{
|
||||
@@ -93,39 +89,7 @@ struct __vpiArrayVthrA : public __vpiHandle {
|
||||
return vp.value.integer;
|
||||
}
|
||||
|
||||
if (wid == 0)
|
||||
return address;
|
||||
|
||||
/* Get the value from thread space. */
|
||||
int tval = 0;
|
||||
for (unsigned idx = 0 ; (idx < wid) && (idx < 8*sizeof(tval));
|
||||
idx += 1) {
|
||||
vvp_bit4_t bit = vthread_get_bit(vpip_current_vthread,
|
||||
address + idx);
|
||||
switch (bit) {
|
||||
case BIT4_X:
|
||||
case BIT4_Z:
|
||||
/* Return UINT_MAX to indicate an X base. */
|
||||
return UINT_MAX;
|
||||
|
||||
case BIT4_1:
|
||||
tval |= 1<<idx;
|
||||
break;
|
||||
|
||||
case BIT4_0:
|
||||
break; // Do nothing!
|
||||
}
|
||||
}
|
||||
|
||||
if (is_signed && (wid < 8*sizeof(tval))) {
|
||||
vvp_bit4_t msb = vthread_get_bit(vpip_current_vthread,
|
||||
address + wid - 1);
|
||||
if (msb == BIT4_1) {
|
||||
tval |= ~((1 << wid) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return tval;
|
||||
return address;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -437,12 +401,9 @@ int __vpiArrayVthrA::vpi_get(int code)
|
||||
#endif
|
||||
|
||||
// If address_handle is not zero we definitely have a
|
||||
// variable. If the wid is not zero we have a calculation
|
||||
// from thread space which probably includes a variable.
|
||||
// This assumes that the compiler is squashing all the
|
||||
// constant expressions down to a single value.
|
||||
// variable.
|
||||
case vpiConstantSelect:
|
||||
return address_handle == 0 && wid == 0;
|
||||
return address_handle == 0;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
@@ -584,7 +545,7 @@ void __vpiArrayVthrAPV::vpi_get_value(p_vpi_value vp)
|
||||
}
|
||||
}
|
||||
|
||||
void __vpiArray::set_word(unsigned address, unsigned part_off, vvp_vector4_t val)
|
||||
void __vpiArray::set_word(unsigned address, unsigned part_off, const vvp_vector4_t&val)
|
||||
{
|
||||
if (address >= get_size())
|
||||
return;
|
||||
@@ -1585,35 +1546,6 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned addr)
|
||||
|
||||
obj->address_handle = 0;
|
||||
obj->address = addr;
|
||||
obj->wid = 0;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* &A<label,tbase,twid,s>
|
||||
* This represents a VPI handle for an addressed word, where the word
|
||||
* address in thread vector space. The tbase/twod/is_signed variables
|
||||
* are the location and interpretation of the bits. This comes from
|
||||
* source expressions that look like label[<expr>].
|
||||
*/
|
||||
vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid,
|
||||
char*is_signed)
|
||||
{
|
||||
struct __vpiArrayVthrA*obj = new __vpiArrayVthrA;
|
||||
|
||||
array_resolv_list_t*resolv_mem
|
||||
= new array_resolv_list_t(label);
|
||||
|
||||
resolv_mem->array = &obj->array;
|
||||
resolv_submit(resolv_mem);
|
||||
|
||||
obj->address_handle = 0;
|
||||
obj->address = tbase;
|
||||
obj->wid = twid;
|
||||
obj->is_signed = strcmp(is_signed, "s") == 0;
|
||||
|
||||
delete [] is_signed;
|
||||
|
||||
return obj;
|
||||
}
|
||||
@@ -1637,7 +1569,6 @@ vpiHandle vpip_make_vthr_A(char*label, char*symbol)
|
||||
obj->address_handle = 0;
|
||||
compile_vpi_lookup(&obj->address_handle, symbol);
|
||||
obj->address = 0;
|
||||
obj->wid = 0;
|
||||
|
||||
return obj;
|
||||
}
|
||||
@@ -1654,7 +1585,6 @@ vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle)
|
||||
|
||||
obj->address_handle = handle;
|
||||
obj->address = 0;
|
||||
obj->wid = 0;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
+60
-47
@@ -37,39 +37,39 @@ extern bool of_ADD_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ADDI(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ALLOC(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_AND(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ANDI(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ANDR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_AR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_ARD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_ARE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_AV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_AVD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_AVE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_D(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_MV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_V0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_V0D(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_V0E(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_V0X1(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_V0X1D(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_V0X1E(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_VEC4D(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_VEC4E(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_VEC4_A_D(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_VEC4_A_E(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_VEC4_OFF_D(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_VEC4_OFF_E(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_WRE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_X0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_BLEND(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_BLEND_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_BREAKPOINT(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CASSIGN_LINK(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CASSIGN_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CASSIGN_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CASSIGN_VEC4_OFF(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CASSIGN_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CASSIGN_X0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CAST2(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPIS(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPIU(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPIE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPINE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPNE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPS(vthread_t thr, vvp_code_t code);
|
||||
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_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);
|
||||
@@ -77,6 +77,8 @@ extern bool of_CMPX(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPZ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CONCAT_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CONCATI_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CONCAT_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CONCATI_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CVT_RS(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CVT_RU(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CVT_RV(vthread_t thr, vvp_code_t code);
|
||||
@@ -86,6 +88,7 @@ extern bool of_CVT_UR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CVT_VR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DEASSIGN(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DEASSIGN_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DEBUG_THR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DELAY(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DELAYX(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DELETE_OBJ(vthread_t thr, vvp_code_t code);
|
||||
@@ -95,62 +98,63 @@ extern bool of_DIV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DIV_S(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DIV_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DUP_REAL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DUP_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_END(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_EVENT(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_EVCTL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_EVCTLC(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_EVCTLI(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_EVCTLS(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FILE_LINE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FLAG_GET_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FLAG_INV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FLAG_MOV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FLAG_OR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FLAG_SET_IMM(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FLAG_SET_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_LINK(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_VEC4_OFF(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_X0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORK(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FREE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_INV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_ADD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_GET(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_GETV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_GETV_S(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_GET_S(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_LOAD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_MOV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_MUL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_SUB(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_VEC4_S(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_JMP(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_JMP0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_JMP0XZ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_JMP1(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_JMP1XZ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_JOIN(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_JOIN_DETACH(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AVP0_S(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_DAR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_REAL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_DAR_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_DAR_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_DAR_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_OBJ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_OBJA(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_STRA(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_VP0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_VP0_S(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_X1P(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_VEC4A(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_MAX_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_MIN_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_MOD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_MOD_S(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_MOD_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_MOV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_MOV_WU(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_MOVI(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_MUL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_MUL_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_MULI(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_MUL_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_NAND(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_NANDR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_NEW_COBJ(vthread_t thr, vvp_code_t code);
|
||||
@@ -161,48 +165,54 @@ extern bool of_NORR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_NULL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_OR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ORR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PAD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PAD_S(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PAD_U(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PART_S(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PART_U(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PARTI_S(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PARTI_U(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_POP_OBJ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_POP_REAL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_POP_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_POP_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_POW(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_POW_S(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_POW_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QPOP_B(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QPOP_F(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QPOP_B_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QPOP_B_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QPOP_F_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QPOP_F_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PROP_OBJ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PROP_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PROP_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PROP_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PUSHI_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PUSHI_REAL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PUSHI_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PUSHV_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PUTC_STR_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PUTC_STR_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_REPLICATE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SCOPY(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_AV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_DAR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_QB(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_QF(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_DAR_OBJ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_DAR_OBJ_REAL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_DAR_OBJ_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_X0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_DAR_OBJ_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_X0_X(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SHIFTL_I0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SHIFTR_I0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SHIFTR_S_I0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SHIFTL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SHIFTR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SHIFTR_S(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SPLIT_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_DAR_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_DAR_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_DAR_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_QB_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_QB_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_QB_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_QF_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_QF_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_QF_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_OBJ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_OBJA(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_OBJ(vthread_t thr, vvp_code_t code);
|
||||
@@ -213,14 +223,17 @@ extern bool of_STORE_REAL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_REALA(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_STRA(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_VEC4A(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SUB(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SUB_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SUBI(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SUB_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SUBSTR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SUBSTR_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SUBSTR_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_TEST_NUL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_TEST_NUL_A(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_TEST_NUL_OBJ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_TEST_NUL_PROP(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_VPI_CALL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_WAIT(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_WAIT_FORK(vthread_t thr, vvp_code_t code);
|
||||
|
||||
+139
-131
@@ -85,195 +85,208 @@ struct opcode_table_s {
|
||||
|
||||
static const struct opcode_table_s opcode_table[] = {
|
||||
{ "%abs/wr", of_ABS_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%add", of_ADD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%add", of_ADD, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%add/wr", of_ADD_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%addi", of_ADDI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%alloc", of_ALLOC, 1, {OA_VPI_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%and", of_AND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%andi", of_ANDI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%and", of_AND, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%and/r", of_ANDR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%assign/ar",of_ASSIGN_AR,2,{OA_ARR_PTR,OA_BIT1, OA_NONE} },
|
||||
{ "%assign/ar/d",of_ASSIGN_ARD,2,{OA_ARR_PTR,OA_BIT1, OA_NONE} },
|
||||
{ "%assign/ar/e",of_ASSIGN_ARE,1,{OA_ARR_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%assign/av",of_ASSIGN_AV,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/av/d",of_ASSIGN_AVD,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/av/e",of_ASSIGN_AVE,2,{OA_ARR_PTR,OA_BIT1, OA_NONE} },
|
||||
{ "%assign/v0",of_ASSIGN_V0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/v0/d",of_ASSIGN_V0D,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/v0/e",of_ASSIGN_V0E,2,{OA_FUNC_PTR,OA_BIT1, OA_NONE} },
|
||||
{ "%assign/v0/x1",of_ASSIGN_V0X1,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
{ "%assign/v0/x1/d",of_ASSIGN_V0X1D,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
{ "%assign/v0/x1/e",of_ASSIGN_V0X1E,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%assign/vec4", of_ASSIGN_VEC4, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%assign/vec4/a/d", of_ASSIGN_VEC4_A_D, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/vec4/a/e", of_ASSIGN_VEC4_A_E, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%assign/vec4/d", of_ASSIGN_VEC4D, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%assign/vec4/e", of_ASSIGN_VEC4E, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%assign/vec4/off/d",of_ASSIGN_VEC4_OFF_D, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/vec4/off/e",of_ASSIGN_VEC4_OFF_E, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%assign/wr", of_ASSIGN_WR, 2,{OA_VPI_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%assign/wr/d",of_ASSIGN_WRD,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%assign/wr/e",of_ASSIGN_WRE,1,{OA_VPI_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%assign/x0",of_ASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%blend", of_BLEND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%blend", of_BLEND, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%blend/wr", of_BLEND_WR,0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%breakpoint", of_BREAKPOINT, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%cassign/link",of_CASSIGN_LINK,2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} },
|
||||
{ "%cassign/v",of_CASSIGN_V,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%cassign/wr",of_CASSIGN_WR,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%cassign/x0",of_CASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%cast2", of_CAST2, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%cmp/s", of_CMPS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%cassign/link", of_CASSIGN_LINK, 2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} },
|
||||
{ "%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, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%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, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%cmp/z", of_CMPZ, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%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} },
|
||||
{ "%concati/str",of_CONCATI_STR,1,{OA_STRING,OA_NONE, OA_NONE} },
|
||||
{ "%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} },
|
||||
{ "%concati/vec4",of_CONCATI_VEC4,3,{OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%cvt/rs", of_CVT_RS, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
{ "%cvt/ru", of_CVT_RU, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
{ "%cvt/rv", of_CVT_RV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%cvt/rv/s", of_CVT_RV_S,2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%cvt/rv", of_CVT_RV, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%cvt/rv/s", of_CVT_RV_S,0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%cvt/sr", of_CVT_SR, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
{ "%cvt/ur", of_CVT_UR, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
{ "%cvt/vr", of_CVT_VR, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
|
||||
{ "%cvt/vr", of_CVT_VR, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%deassign",of_DEASSIGN,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%deassign/wr",of_DEASSIGN_WR,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%debug/thr", of_DEBUG_THR, 1,{OA_STRING, OA_NONE, OA_NONE} },
|
||||
{ "%delay", of_DELAY, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%delayx", of_DELAYX, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%delete/obj",of_DELETE_OBJ,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%disable/fork",of_DISABLE_FORK,0,{OA_NONE,OA_NONE, OA_NONE} },
|
||||
{ "%div", of_DIV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%div/s", of_DIV_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%div", of_DIV, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%div/s", of_DIV_S, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%div/wr", of_DIV_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%dup/real", of_DUP_REAL,0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%dup/vec4", of_DUP_VEC4,0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%end", of_END, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%evctl", of_EVCTL, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%evctl/c",of_EVCTLC, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%evctl/i",of_EVCTLI, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%evctl/s",of_EVCTLS, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%force/link",of_FORCE_LINK,2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} },
|
||||
{ "%force/v",of_FORCE_V,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%force/wr",of_FORCE_WR,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%force/x0",of_FORCE_X0,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%event", of_EVENT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%flag_get/vec4", of_FLAG_GET_VEC4, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%flag_inv", of_FLAG_INV, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
{ "%flag_mov", of_FLAG_MOV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%flag_or", of_FLAG_OR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%flag_set/imm", of_FLAG_SET_IMM, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%flag_set/vec4", of_FLAG_SET_VEC4, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%force/link", of_FORCE_LINK,2,{OA_FUNC_PTR, OA_FUNC_PTR2, OA_NONE} },
|
||||
{ "%force/vec4", of_FORCE_VEC4, 1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%force/vec4/off",of_FORCE_VEC4_OFF,2,{OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%force/wr", of_FORCE_WR, 1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%free", of_FREE, 1, {OA_VPI_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%inv", of_INV, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%ix/add", of_IX_ADD, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
|
||||
{ "%ix/get", of_IX_GET, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%ix/get/s",of_IX_GET_S,3,{OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%ix/getv",of_IX_GETV,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} },
|
||||
{ "%ix/getv/s",of_IX_GETV_S,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} },
|
||||
{ "%ix/load",of_IX_LOAD,3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
|
||||
{ "%ix/mov", of_IX_MOV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%ix/mul", of_IX_MUL, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
|
||||
{ "%ix/sub", of_IX_SUB, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
|
||||
{ "%ix/vec4", of_IX_VEC4, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%ix/vec4/s",of_IX_VEC4_S,1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%jmp", of_JMP, 1, {OA_CODE_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%jmp/0", of_JMP0, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%jmp/0xz",of_JMP0XZ, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%jmp/1", of_JMP1, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%jmp/1xz",of_JMP1XZ, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%join", of_JOIN, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%join/detach",of_JOIN_DETACH,1,{OA_NUMBER,OA_NONE, OA_NONE} },
|
||||
{ "%load/ar",of_LOAD_AR,2, {OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avp0/s",of_LOAD_AVP0_S,3,{OA_BIT1,OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avx.p",of_LOAD_AVX_P,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/dar",of_LOAD_DAR,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
{ "%load/dar/r", of_LOAD_DAR_R, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE}},
|
||||
{ "%load/dar/str",of_LOAD_DAR_STR, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%load/obj", of_LOAD_OBJ, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%load/obja", of_LOAD_OBJA,2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%load/real", of_LOAD_REAL,1,{OA_VPI_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%load/str", of_LOAD_STR, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%load/stra", of_LOAD_STRA,2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%load/v", of_LOAD_VEC,3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
{ "%load/vp0",of_LOAD_VP0,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
{ "%load/vp0/s",of_LOAD_VP0_S,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
{ "%load/x1p",of_LOAD_X1P,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
{ "%load/dar/r", of_LOAD_DAR_R, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE}},
|
||||
{ "%load/dar/str",of_LOAD_DAR_STR, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%load/dar/vec4",of_LOAD_DAR_VEC4,1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%load/obj", of_LOAD_OBJ, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%load/obja", of_LOAD_OBJA, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%load/real", of_LOAD_REAL, 1,{OA_VPI_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%load/str", of_LOAD_STR, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%load/stra", of_LOAD_STRA, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%load/vec4", of_LOAD_VEC4, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%load/vec4a", of_LOAD_VEC4A,2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%max/wr", of_MAX_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%min/wr", of_MIN_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%mod", of_MOD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%mod/s", of_MOD_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%mod", of_MOD, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%mod/s", of_MOD_S, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%mod/wr", of_MOD_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%mov", of_MOV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%mov/wu", of_MOV_WU, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%movi", of_MOVI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%mul", of_MUL, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%mul", of_MUL, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%mul/wr", of_MUL_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%muli", of_MULI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%nand", of_NAND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%nand/r", of_NANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%nand", of_NAND, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%nand/r", of_NANDR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%new/cobj", of_NEW_COBJ, 1, {OA_VPI_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%new/darray",of_NEW_DARRAY,2, {OA_BIT1, OA_STRING,OA_NONE} },
|
||||
{ "%noop", of_NOOP, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%nor", of_NOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%nor/r", of_NORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%nor", of_NOR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%nor/r", of_NORR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%null", of_NULL, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%or", of_OR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%or/r", of_ORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%pad", of_PAD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%or", of_OR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%or/r", of_ORR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%pad/s", of_PAD_S, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%pad/u", of_PAD_U, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%part/s", of_PART_S, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%part/u", of_PART_U, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%parti/s",of_PARTI_S,3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
|
||||
{ "%parti/u",of_PARTI_U,3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
|
||||
{ "%pop/obj", of_POP_OBJ, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%pop/real",of_POP_REAL,1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%pop/str", of_POP_STR, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%pow", of_POW, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%pow/s", of_POW_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%pow/wr", of_POW_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%pop/vec4",of_POP_VEC4,1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%pow", of_POW, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%pow/s", of_POW_S, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%pow/wr", of_POW_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%prop/obj",of_PROP_OBJ,2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%prop/r", of_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%prop/str",of_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%prop/v", of_PROP_V, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%prop/v", of_PROP_V, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%pushi/real",of_PUSHI_REAL,2,{OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%pushi/str", of_PUSHI_STR, 1,{OA_STRING, OA_NONE, OA_NONE} },
|
||||
{ "%pushv/str", of_PUSHV_STR, 2, {OA_BIT1,OA_BIT2, OA_NONE} },
|
||||
{ "%putc/str/v",of_PUTC_STR_V,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%qpop/b", of_QPOP_B, 3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%pushi/vec4",of_PUSHI_VEC4,3,{OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%pushv/str", of_PUSHV_STR, 0,{OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%putc/str/vec4",of_PUTC_STR_VEC4,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%qpop/b/str",of_QPOP_B_STR,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%qpop/f", of_QPOP_F, 3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%qpop/b/v", of_QPOP_B_V, 1,{OA_FUNC_PTR,OA_NONE, OA_BIT2} },
|
||||
{ "%qpop/f/str",of_QPOP_F_STR,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%qpop/f/v", of_QPOP_F_V, 1,{OA_FUNC_PTR,OA_NONE, OA_BIT2} },
|
||||
{ "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
{ "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%release/wr", of_RELEASE_WR, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%replicate", of_REPLICATE, 1,{OA_NUMBER, OA_NONE,OA_NONE} },
|
||||
{ "%scopy", of_SCOPY, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/dar",of_SET_DAR,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/dar/obj", of_SET_DAR_OBJ, 3,{OA_NUMBER,OA_BIT1,OA_BIT2} },
|
||||
{ "%set/dar/obj/real",of_SET_DAR_OBJ_REAL,1,{OA_NUMBER,OA_NONE,OA_NONE} },
|
||||
{ "%set/dar/obj/str", of_SET_DAR_OBJ_STR, 1,{OA_NUMBER,OA_NONE,OA_NONE} },
|
||||
{ "%set/qb", of_SET_QB, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/qf", of_SET_QF, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%shiftl/i0", of_SHIFTL_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },
|
||||
{ "%shiftr/i0", of_SHIFTR_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },
|
||||
{ "%shiftr/s/i0", of_SHIFTR_S_I0,2,{OA_BIT1,OA_NUMBER, OA_NONE} },
|
||||
{ "%store/dar/r", of_STORE_DAR_R, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%store/dar/str",of_STORE_DAR_STR, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%set/dar/obj/vec4",of_SET_DAR_OBJ_VEC4,1,{OA_NUMBER,OA_NONE,OA_NONE} },
|
||||
{ "%shiftl", of_SHIFTL, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%shiftr", of_SHIFTR, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%shiftr/s", of_SHIFTR_S, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%split/vec4", of_SPLIT_VEC4, 1,{OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%store/dar/r", of_STORE_DAR_R, 1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%store/dar/str", of_STORE_DAR_STR, 1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%store/dar/vec4",of_STORE_DAR_VEC4,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%store/obj", of_STORE_OBJ, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%store/obja", of_STORE_OBJA, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%store/prop/obj",of_STORE_PROP_OBJ,2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%store/prop/r", of_STORE_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%store/prop/str",of_STORE_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%store/prop/v", of_STORE_PROP_V, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%store/prop/v", of_STORE_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%store/qb/r", of_STORE_QB_R, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%store/qb/str", of_STORE_QB_STR, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%store/qb/v", of_STORE_QB_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%store/qf/r", of_STORE_QF_R, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%store/qf/str", of_STORE_QF_STR, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%store/real", of_STORE_REAL, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%store/reala", of_STORE_REALA, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%store/str", of_STORE_STR, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%store/stra", of_STORE_STRA, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%sub", of_SUB, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%store/qf/v", of_STORE_QF_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%store/real", of_STORE_REAL, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%store/reala", of_STORE_REALA, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%store/str", of_STORE_STR, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%store/stra", of_STORE_STRA, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%store/vec4", of_STORE_VEC4, 3, {OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%store/vec4a", of_STORE_VEC4A, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%sub", of_SUB, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%sub/wr", of_SUB_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%subi", of_SUBI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%substr", of_SUBSTR, 2,{OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%substr/v",of_SUBSTR_V,3,{OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%test_nul", of_TEST_NUL, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%test_nul/a", of_TEST_NUL_A, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%test_nul/obj",of_TEST_NUL_OBJ,0,{OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%substr", of_SUBSTR, 2,{OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%substr/vec4",of_SUBSTR_VEC4,2,{OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%test_nul", of_TEST_NUL, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%test_nul/a", of_TEST_NUL_A, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%test_nul/obj", of_TEST_NUL_OBJ, 0,{OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%test_nul/prop",of_TEST_NUL_PROP,2,{OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%wait", of_WAIT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%wait/fork",of_WAIT_FORK,0,{OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%xnor", of_XNOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%xnor/r", of_XNORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%xor", of_XOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%xor/r", of_XORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%xnor", of_XNOR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%xnor/r", of_XNORR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%xor", of_XOR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%xor/r", of_XORR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ 0, of_NOOP, 0, {OA_NONE, OA_NONE, OA_NONE} }
|
||||
};
|
||||
|
||||
@@ -527,18 +540,24 @@ bool vpi_handle_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
symbol_value_t val = sym_get_value(sym_vpi, label());
|
||||
if (!val.ptr) {
|
||||
// check for thread vector T<base,wid>
|
||||
// check for thread access symbols
|
||||
unsigned base, wid;
|
||||
int n = 0;
|
||||
size_t n = 0;
|
||||
char ss[32];
|
||||
if (2 <= sscanf(label(), "T<%u,%u>%n", &base, &wid, &n)
|
||||
&& n == (int)strlen(label())) {
|
||||
val.ptr = vpip_make_vthr_vector(base, wid, false);
|
||||
if (2 == sscanf(label(), "W<%u,%[r]>%zn", &base, ss, &n)
|
||||
&& n == strlen(label())) {
|
||||
|
||||
val.ptr = vpip_make_vthr_word(base, ss);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
|
||||
} else if (3 <= sscanf(label(), "T<%u,%u,%[su]>%n", &base,
|
||||
&wid, ss, &n)
|
||||
&& n == (int)strlen(label())) {
|
||||
} else if (1 == sscanf(label(), "S<%u,str>%zn", &base, &n)
|
||||
&& n == strlen(label())) {
|
||||
|
||||
val.ptr = vpip_make_vthr_str_stack(base);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
|
||||
} else if (3 == sscanf(label(), "S<%u,vec4,%[su]%u>%zn", &base, ss, &wid, &n)
|
||||
&& n == strlen(label())) {
|
||||
|
||||
bool signed_flag = false;
|
||||
for (char*fp = ss ; *fp ; fp += 1) switch (*fp) {
|
||||
@@ -551,20 +570,7 @@ bool vpi_handle_resolv_list_s::resolve(bool mes)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
val.ptr = vpip_make_vthr_vector(base, wid, signed_flag);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
|
||||
} else if (2 == sscanf(label(), "W<%u,%[r]>%n", &base, ss, &n)
|
||||
&& n == (int)strlen(label())) {
|
||||
|
||||
val.ptr = vpip_make_vthr_word(base, ss);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
|
||||
} else if (1 == sscanf(label(), "S<%u,str>%n", &base, &n)
|
||||
&& n == (int)strlen(label())) {
|
||||
|
||||
val.ptr = vpip_make_vthr_str_stack(base);
|
||||
val.ptr = vpip_make_vthr_vec4_stack(base, signed_flag, wid);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
}
|
||||
|
||||
@@ -1858,7 +1864,7 @@ void compile_vpi_call(char*label, char*name,
|
||||
bool func_as_task_err, bool func_as_task_warn,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv,
|
||||
unsigned real_stack, unsigned string_stack)
|
||||
unsigned vec4_stack, unsigned real_stack, unsigned string_stack)
|
||||
{
|
||||
if (label)
|
||||
compile_codelabel(label);
|
||||
@@ -1869,9 +1875,9 @@ void compile_vpi_call(char*label, char*name,
|
||||
|
||||
/* Create a vpiHandle that bundles the call information, and
|
||||
store that handle in the instruction. */
|
||||
code->handle = vpip_build_vpi_call(name, 0, 0, 0,
|
||||
func_as_task_err, func_as_task_warn,
|
||||
argc, argv, real_stack, string_stack,
|
||||
code->handle = vpip_build_vpi_call(name, 0, 0,
|
||||
0, func_as_task_err, func_as_task_warn,
|
||||
argc, argv, vec4_stack, real_stack, string_stack,
|
||||
file_idx, lineno);
|
||||
if (code->handle == 0)
|
||||
compile_errors += 1;
|
||||
@@ -1881,9 +1887,10 @@ void compile_vpi_call(char*label, char*name,
|
||||
}
|
||||
|
||||
void compile_vpi_func_call(char*label, char*name,
|
||||
unsigned vbit, int vwid,
|
||||
int val_type, unsigned val_wid,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv,
|
||||
unsigned vec4_stack,
|
||||
unsigned real_stack,
|
||||
unsigned string_stack)
|
||||
{
|
||||
@@ -1896,8 +1903,9 @@ void compile_vpi_func_call(char*label, char*name,
|
||||
|
||||
/* Create a vpiHandle that bundles the call information, and
|
||||
store that handle in the instruction. */
|
||||
code->handle = vpip_build_vpi_call(name, vbit, vwid, 0, true, false,
|
||||
argc, argv, real_stack, string_stack,
|
||||
code->handle = vpip_build_vpi_call(name, val_type, val_wid,
|
||||
0, true, false,
|
||||
argc, argv, vec4_stack, real_stack, string_stack,
|
||||
file_idx, lineno);
|
||||
if (code->handle == 0)
|
||||
compile_errors += 1;
|
||||
|
||||
+3
-1
@@ -442,6 +442,7 @@ extern void compile_vpi_call(char*label, char*name,
|
||||
bool func_as_task_err, bool func_as_task_warn,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv,
|
||||
unsigned vec4_stack,
|
||||
unsigned real_stack,
|
||||
unsigned string_stack);
|
||||
|
||||
@@ -450,9 +451,10 @@ extern void compile_vpi_call(char*label, char*name,
|
||||
<0, the return type is -vpiRealConst or some other constant subtype
|
||||
code that represents the function type. */
|
||||
extern void compile_vpi_func_call(char*label, char*name,
|
||||
unsigned vbit, int vwid,
|
||||
int val_type, unsigned val_wid,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv,
|
||||
unsigned vec4_stack,
|
||||
unsigned real_stack,
|
||||
unsigned string_stack);
|
||||
extern void print_vpi_call_errors();
|
||||
|
||||
@@ -276,6 +276,11 @@ static char* strdupnew(char const *str)
|
||||
assert(yylval.text);
|
||||
return T_SYMBOL; }
|
||||
|
||||
"S<"[0-9]*",vec4,"[us][0-9]+">" {
|
||||
yylval.text = strdup(yytext);
|
||||
assert(yylval.text);
|
||||
return T_SYMBOL; }
|
||||
|
||||
"T<"[0-9]*","[0-9]*","[us]">" {
|
||||
yylval.text = strdup(yytext);
|
||||
assert(yylval.text);
|
||||
|
||||
+383
-329
File diff suppressed because it is too large
Load Diff
+13
-17
@@ -620,33 +620,33 @@ statement
|
||||
|
||||
/* This version does not allow a function to be called as a task. */
|
||||
| label_opt K_vpi_call T_NUMBER T_NUMBER T_STRING
|
||||
argument_opt '{' T_NUMBER T_NUMBER '}' ';'
|
||||
argument_opt '{' T_NUMBER T_NUMBER T_NUMBER '}' ';'
|
||||
{ compile_vpi_call($1, $5, true, false, $3, $4,
|
||||
$6.argc, $6.argv, $8, $9); }
|
||||
$6.argc, $6.argv, $8, $9, $10); }
|
||||
|
||||
/* This version allows a function to be called as a task, but prints a
|
||||
* warning message. */
|
||||
| label_opt K_vpi_call_w T_NUMBER T_NUMBER T_STRING
|
||||
argument_opt '{' T_NUMBER T_NUMBER '}' ';'
|
||||
argument_opt '{' T_NUMBER T_NUMBER T_NUMBER '}' ';'
|
||||
{ compile_vpi_call($1, $5, false, true, $3, $4,
|
||||
$6.argc, $6.argv, $8, $9); }
|
||||
$6.argc, $6.argv, $8, $9, $10); }
|
||||
|
||||
/* This version allows a function to be called as a task and does not
|
||||
* print a message. */
|
||||
| label_opt K_vpi_call_i T_NUMBER T_NUMBER T_STRING
|
||||
argument_opt '{' T_NUMBER T_NUMBER '}' ';'
|
||||
argument_opt '{' T_NUMBER T_NUMBER T_NUMBER '}' ';'
|
||||
{ compile_vpi_call($1, $5, false, false, $3, $4,
|
||||
$6.argc, $6.argv, $8, $9); }
|
||||
$6.argc, $6.argv, $8, $9, $10); }
|
||||
|
||||
| label_opt K_vpi_func T_NUMBER T_NUMBER T_STRING ','
|
||||
T_NUMBER ',' T_NUMBER argument_opt '{' T_NUMBER T_NUMBER '}' ';'
|
||||
{ compile_vpi_func_call($1, $5, $7, $9, $3, $4,
|
||||
$10.argc, $10.argv, $12, $13); }
|
||||
| label_opt K_vpi_func T_NUMBER T_NUMBER T_STRING T_NUMBER
|
||||
argument_opt '{' T_NUMBER T_NUMBER T_NUMBER '}' ';'
|
||||
{ compile_vpi_func_call($1, $5, -vpiVectorVal, $6, $3, $4,
|
||||
$7.argc, $7.argv, $9, $10, $11); }
|
||||
|
||||
| label_opt K_vpi_func_r T_NUMBER T_NUMBER T_STRING
|
||||
argument_opt '{' T_NUMBER T_NUMBER '}' ';'
|
||||
{ compile_vpi_func_call($1, $5, 0, -vpiRealConst, $3, $4,
|
||||
$6.argc, $6.argv, $8, $9); }
|
||||
argument_opt '{' T_NUMBER T_NUMBER T_NUMBER '}' ';'
|
||||
{ compile_vpi_func_call($1, $5, -vpiRealVal, 0, $3, $4,
|
||||
$6.argc, $6.argv, $8, $9, $10); }
|
||||
|
||||
/* %disable statements are instructions that takes a scope reference
|
||||
as an operand. It therefore is parsed uniquely. */
|
||||
@@ -1088,8 +1088,6 @@ argument
|
||||
symbol_access
|
||||
: K_A '<' T_SYMBOL ',' T_NUMBER '>'
|
||||
{ $$ = vpip_make_vthr_A($3, $5); }
|
||||
| K_A '<' T_SYMBOL ',' T_NUMBER T_NUMBER T_STRING '>'
|
||||
{ $$ = vpip_make_vthr_A($3, $5, $6, $7); }
|
||||
| K_A '<' T_SYMBOL ',' T_SYMBOL '>'
|
||||
{ $$ = vpip_make_vthr_A($3, $5); }
|
||||
| K_A '<' T_SYMBOL ',' symbol_access '>'
|
||||
@@ -1102,8 +1100,6 @@ symbol_access
|
||||
{ $$ = vpip_make_PV($3, $5, $7); }
|
||||
| K_PV '<' T_SYMBOL ',' symbol_access ',' T_NUMBER '>'
|
||||
{ $$ = vpip_make_PV($3, $5, $7); }
|
||||
| K_PV '<' T_SYMBOL ',' T_NUMBER T_NUMBER T_STRING ',' T_NUMBER '>'
|
||||
{ $$ = vpip_make_PV($3, $5, $6, $7, $9); }
|
||||
| K_APV '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER ',' T_NUMBER '>'
|
||||
{ $$ = vpip_make_vthr_APV($3, $5, $7, $9); }
|
||||
;
|
||||
|
||||
+1
-5
@@ -57,11 +57,7 @@ void vvp_fun_part_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
||||
{
|
||||
assert(port.port() == 0);
|
||||
|
||||
vvp_vector4_t tmp (wid_, BIT4_X);
|
||||
for (unsigned idx = 0 ; idx < wid_ ; idx += 1) {
|
||||
if (idx + base_ < bit.size())
|
||||
tmp.set_bit(idx, bit.value(base_+idx));
|
||||
}
|
||||
vvp_vector4_t tmp (bit, base_, wid_);
|
||||
if (val_ .eeq( tmp ))
|
||||
return;
|
||||
|
||||
|
||||
+4
-24
@@ -165,12 +165,6 @@ struct assign_vector4_event_s : public event_s {
|
||||
base = 0;
|
||||
vwid = 0;
|
||||
}
|
||||
/* A constructor that makes the val directly. */
|
||||
assign_vector4_event_s(const vvp_vector4_t&that, unsigned adr, unsigned wid)
|
||||
: val(that,adr,wid) {
|
||||
base = 0;
|
||||
vwid = 0;
|
||||
}
|
||||
|
||||
/* Where to do the assign. */
|
||||
vvp_net_ptr_t ptr;
|
||||
@@ -782,26 +776,12 @@ void schedule_assign_vector(vvp_net_ptr_t ptr,
|
||||
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
||||
}
|
||||
|
||||
void schedule_assign_plucked_vector(vvp_net_ptr_t ptr,
|
||||
vvp_time64_t delay,
|
||||
const vvp_vector4_t&src,
|
||||
unsigned adr, unsigned wid)
|
||||
{
|
||||
struct assign_vector4_event_s*cur
|
||||
= new struct assign_vector4_event_s(src,adr,wid);
|
||||
cur->ptr = ptr;
|
||||
cur->vwid = 0;
|
||||
cur->base = 0;
|
||||
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
||||
}
|
||||
|
||||
void schedule_propagate_plucked_vector(vvp_net_t*net,
|
||||
vvp_time64_t delay,
|
||||
const vvp_vector4_t&src,
|
||||
unsigned adr, unsigned wid)
|
||||
void schedule_propagate_vector(vvp_net_t*net,
|
||||
vvp_time64_t delay,
|
||||
const vvp_vector4_t&src)
|
||||
{
|
||||
struct propagate_vector4_event_s*cur
|
||||
= new struct propagate_vector4_event_s(src,adr,wid);
|
||||
= new struct propagate_vector4_event_s(src);
|
||||
cur->net = net;
|
||||
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
||||
}
|
||||
|
||||
+3
-9
@@ -48,11 +48,6 @@ extern void schedule_assign_vector(vvp_net_ptr_t ptr,
|
||||
const vvp_vector4_t&val,
|
||||
vvp_time64_t delay);
|
||||
|
||||
extern void schedule_assign_plucked_vector(vvp_net_ptr_t ptr,
|
||||
vvp_time64_t delay,
|
||||
const vvp_vector4_t&val,
|
||||
unsigned adr, unsigned wid);
|
||||
|
||||
extern void schedule_assign_array_word(vvp_array_t mem,
|
||||
unsigned word_address,
|
||||
unsigned off,
|
||||
@@ -66,10 +61,9 @@ extern void schedule_assign_array_word(vvp_array_t mem,
|
||||
/*
|
||||
* Create an event to propagate the output of a net.
|
||||
*/
|
||||
extern void schedule_propagate_plucked_vector(vvp_net_t*ptr,
|
||||
vvp_time64_t delay,
|
||||
const vvp_vector4_t&val,
|
||||
unsigned adr, unsigned wid);
|
||||
extern void schedule_propagate_vector(vvp_net_t*ptr,
|
||||
vvp_time64_t delay,
|
||||
const vvp_vector4_t&val);
|
||||
|
||||
/*
|
||||
* This is very similar to schedule_assign_vector, but generates an
|
||||
|
||||
+14
-4
@@ -98,7 +98,7 @@ static int make_vpi_argv(unsigned argc, vpiHandle*vpi_argv,
|
||||
switch (*cp) {
|
||||
case 'r': // real result
|
||||
cp += 1;
|
||||
return_type = -vpiRealConst;
|
||||
return_type = -vpiRealVal;
|
||||
break;
|
||||
|
||||
case 'v': // vector4_t
|
||||
@@ -147,17 +147,27 @@ void compile_sfunc(char*label, char*name, char*format_string,
|
||||
unsigned argc, struct symb_s*argv,
|
||||
char*trigger_label)
|
||||
{
|
||||
unsigned vec4_stack = 0;
|
||||
unsigned real_stack = 0;
|
||||
unsigned string_stack = 0;
|
||||
vpiHandle*vpi_argv = new vpiHandle[argc];
|
||||
int width_code = make_vpi_argv(argc, vpi_argv, format_string);
|
||||
int val_code = make_vpi_argv(argc, vpi_argv, format_string);
|
||||
unsigned val_width = 0;
|
||||
delete[] format_string;
|
||||
|
||||
// The make_vpi_argv returns for the function return value a
|
||||
// >0 value for the vector width if this is a vector. Convert
|
||||
// it to the form that the vpip_build_vpi_call uses.
|
||||
if (val_code > 0) {
|
||||
val_width = val_code;
|
||||
val_code = -vpiVectorVal;
|
||||
}
|
||||
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
|
||||
vpiHandle sys = vpip_build_vpi_call(name, 0, width_code, ptr,
|
||||
vpiHandle sys = vpip_build_vpi_call(name, val_code, val_width, ptr,
|
||||
true, false, argc, vpi_argv,
|
||||
real_stack, string_stack,
|
||||
vec4_stack, real_stack, string_stack,
|
||||
file_idx, lineno);
|
||||
assert(sys);
|
||||
|
||||
|
||||
+1
-1
@@ -174,7 +174,7 @@ static void cmd_call(unsigned argc, char*argv[])
|
||||
vpiHandle call_handle = vpip_build_vpi_call(argv[0], 0, 0, 0,
|
||||
true, false,
|
||||
vpi_argc, vpi_argv,
|
||||
0, 0,
|
||||
0, 0, 0,
|
||||
1, 0);
|
||||
if (call_handle == 0)
|
||||
goto out;
|
||||
|
||||
+1
-1
@@ -538,7 +538,7 @@ __vpiDecConst::__vpiDecConst(int val)
|
||||
}
|
||||
|
||||
__vpiDecConst::__vpiDecConst(const __vpiDecConst&that)
|
||||
: value(that.value)
|
||||
: __vpiHandle(), value(that.value)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -162,7 +162,8 @@ void __vpiDarrayVar::put_word_value(struct __vpiArrayWord*word, p_vpi_value vp,
|
||||
case vpiIntVal:
|
||||
{
|
||||
vvp_vector4_t vec;
|
||||
vec.setarray(0, 8 * sizeof(vp->value.integer), (unsigned long*)(&vp->value.integer));
|
||||
unsigned long val = vp->value.integer;
|
||||
vec.setarray(0, 8 * sizeof(vp->value.integer), &val);
|
||||
aobj->set_word(index, vec);
|
||||
}
|
||||
break;
|
||||
|
||||
+13
-16
@@ -359,14 +359,11 @@ struct __vpiPV : public __vpiHandle {
|
||||
vvp_net_t*net;
|
||||
vpiHandle sbase;
|
||||
int tbase;
|
||||
unsigned twid, width;
|
||||
bool is_signed;
|
||||
unsigned width;
|
||||
};
|
||||
extern vpiHandle vpip_make_PV(char*name, int base, int width);
|
||||
extern vpiHandle vpip_make_PV(char*name, char*symbol, int width);
|
||||
extern vpiHandle vpip_make_PV(char*name, vpiHandle handle, int width);
|
||||
extern vpiHandle vpip_make_PV(char*name, int tbase, int twid, char*is_signed,
|
||||
int width);
|
||||
|
||||
struct __vpiModPathTerm : public __vpiHandle {
|
||||
__vpiModPathTerm();
|
||||
@@ -540,6 +537,7 @@ extern vpiHandle vpip_make_string_var(const char*name, vvp_net_t*net);
|
||||
|
||||
struct __vpiArrayBase {
|
||||
__vpiArrayBase() : vals_words(NULL) {}
|
||||
virtual ~__vpiArrayBase() {}
|
||||
|
||||
virtual unsigned get_size(void) const = 0;
|
||||
virtual vpiHandle get_left_range() = 0;
|
||||
@@ -608,7 +606,7 @@ struct __vpiArray : public __vpiArrayBase, public __vpiHandle {
|
||||
inline vpiHandle vpi_iterate(int code) { return vpi_array_base_iterate(code); }
|
||||
vpiHandle vpi_index(int idx);
|
||||
|
||||
void set_word(unsigned idx, unsigned off, vvp_vector4_t val);
|
||||
void set_word(unsigned idx, unsigned off, const vvp_vector4_t&val);
|
||||
void set_word(unsigned idx, double val);
|
||||
void set_word(unsigned idx, const std::string&val);
|
||||
void set_word(unsigned idx, const vvp_object_t&val);
|
||||
@@ -743,13 +741,12 @@ struct __vpiSysTaskCall : public __vpiHandle {
|
||||
unsigned nargs;
|
||||
vpiHandle*args;
|
||||
/* Stack consumed by this call */
|
||||
unsigned vec4_stack;
|
||||
unsigned real_stack;
|
||||
unsigned string_stack;
|
||||
/* Support for vpi_get_userdata. */
|
||||
void*userdata;
|
||||
/* These represent where in the vthread to put the return value. */
|
||||
unsigned vbit;
|
||||
signed vwid;
|
||||
// This is set if this is a structural call to a function
|
||||
class vvp_net_t*fnet;
|
||||
unsigned file_idx;
|
||||
unsigned lineno;
|
||||
@@ -757,6 +754,7 @@ struct __vpiSysTaskCall : public __vpiHandle {
|
||||
protected:
|
||||
inline __vpiSysTaskCall()
|
||||
{
|
||||
vec4_stack = 0;
|
||||
real_stack = 0;
|
||||
string_stack = 0;
|
||||
}
|
||||
@@ -814,15 +812,12 @@ vpiHandle vpip_make_real_param(char*name, double value, bool local_flag,
|
||||
* thread.
|
||||
*/
|
||||
|
||||
vpiHandle vpip_make_vthr_vector(unsigned base, unsigned wid, bool signed_flag);
|
||||
|
||||
vpiHandle vpip_make_vthr_word(unsigned base, const char*type);
|
||||
vpiHandle vpip_make_vthr_str_stack(unsigned depth);
|
||||
vpiHandle vpip_make_vthr_vec4_stack(unsigned depth, bool signed_flag, unsigned wid);
|
||||
|
||||
vpiHandle vpip_make_vthr_A(char*label, unsigned index);
|
||||
vpiHandle vpip_make_vthr_A(char*label, char*symbol);
|
||||
vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid,
|
||||
char*is_signed);
|
||||
vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle);
|
||||
vpiHandle vpip_make_vthr_APV(char*label, unsigned index, unsigned bit, unsigned wid);
|
||||
|
||||
@@ -849,20 +844,22 @@ extern unsigned vpip_module_path_cnt;
|
||||
* call. However, the vpiSysTaskCall that is the returned handle,
|
||||
* holds a parameter argument list that is passed in here.
|
||||
*
|
||||
* The vbit and vwid fields are used if this turns out to be a system
|
||||
* function. In that case, the vbit and vwid are used to address the
|
||||
* vector in thread bit space where the result is supposed to go.
|
||||
* The val_type and return_width fields are used if this turns out to
|
||||
* be a system function. In that case, the val_type encodes the return
|
||||
* type (-vpiRealVal, -vpiVectorVal) and if a vector the return_width
|
||||
* has the vector width.
|
||||
*
|
||||
* Note that the argv array is saved in the handle, and should should
|
||||
* not be released by the caller.
|
||||
*/
|
||||
extern vpiHandle vpip_build_vpi_call(const char*name,
|
||||
unsigned vbit, int vwid,
|
||||
int val_type, unsigned return_width,
|
||||
class vvp_net_t*fnet,
|
||||
bool func_as_task_err,
|
||||
bool func_as_task_warn,
|
||||
unsigned argc,
|
||||
vpiHandle*argv,
|
||||
unsigned vec4_stack,
|
||||
unsigned real_stack,
|
||||
unsigned string_stack,
|
||||
long file_idx,
|
||||
|
||||
+2
-54
@@ -1164,39 +1164,7 @@ static int PV_get_base(struct __vpiPV*rfp)
|
||||
}
|
||||
|
||||
/* If the width is zero then tbase is the constant. */
|
||||
if (rfp->twid == 0) return rfp->tbase;
|
||||
|
||||
/* Get the value from thread space. */
|
||||
int tval = 0;
|
||||
for (unsigned idx = 0 ; (idx < rfp->twid) && (idx < 8*sizeof(tval));
|
||||
idx += 1) {
|
||||
vvp_bit4_t bit = vthread_get_bit(vpip_current_vthread,
|
||||
rfp->tbase + idx);
|
||||
switch (bit) {
|
||||
case BIT4_X:
|
||||
case BIT4_Z:
|
||||
/* We use INT_MIN to indicate an X base. */
|
||||
return INT_MIN;
|
||||
|
||||
case BIT4_1:
|
||||
tval |= 1<<idx;
|
||||
break;
|
||||
|
||||
case BIT4_0:
|
||||
break; // Do nothing!
|
||||
}
|
||||
}
|
||||
|
||||
/* Check to see if we need to sign extend the result. */
|
||||
if (rfp->is_signed && (rfp->twid < 8*sizeof(tval))) {
|
||||
vvp_bit4_t msb = vthread_get_bit(vpip_current_vthread,
|
||||
rfp->tbase + rfp->twid - 1);
|
||||
if (msb == BIT4_1) {
|
||||
tval |= ~((1 << rfp->twid) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return tval;
|
||||
return rfp->tbase;
|
||||
}
|
||||
|
||||
static int PV_get(int code, vpiHandle ref)
|
||||
@@ -1217,7 +1185,7 @@ static int PV_get(int code, vpiHandle ref)
|
||||
|
||||
/* This is like the &A<> in array.cc. */
|
||||
case vpiConstantSelect:
|
||||
return rfp->sbase == 0 && rfp->twid == 0;
|
||||
return rfp->sbase == 0;
|
||||
|
||||
case vpiLeftRange:
|
||||
rval += rfp->width - 1;
|
||||
@@ -1419,7 +1387,6 @@ vpiHandle vpip_make_PV(char*var, int base, int width)
|
||||
obj->parent = vvp_lookup_handle(var);
|
||||
obj->sbase = 0;
|
||||
obj->tbase = base;
|
||||
obj->twid = 0;
|
||||
obj->width = (unsigned) width;
|
||||
obj->net = 0;
|
||||
functor_ref_lookup(&obj->net, var);
|
||||
@@ -1433,7 +1400,6 @@ vpiHandle vpip_make_PV(char*var, char*symbol, int width)
|
||||
obj->parent = vvp_lookup_handle(var);
|
||||
compile_vpi_lookup(&obj->sbase, symbol);
|
||||
obj->tbase = 0;
|
||||
obj->twid = 0;
|
||||
obj->width = (unsigned) width;
|
||||
obj->net = 0;
|
||||
functor_ref_lookup(&obj->net, var);
|
||||
@@ -1447,7 +1413,6 @@ vpiHandle vpip_make_PV(char*var, vpiHandle handle, int width)
|
||||
obj->parent = vvp_lookup_handle(var);
|
||||
obj->sbase = handle;
|
||||
obj->tbase = 0;
|
||||
obj->twid = 0;
|
||||
obj->width = (unsigned) width;
|
||||
obj->net = 0;
|
||||
functor_ref_lookup(&obj->net, var);
|
||||
@@ -1455,23 +1420,6 @@ vpiHandle vpip_make_PV(char*var, vpiHandle handle, int width)
|
||||
return obj;
|
||||
}
|
||||
|
||||
vpiHandle vpip_make_PV(char*var, int tbase, int twid, char*is_signed, int width)
|
||||
{
|
||||
struct __vpiPV*obj = new __vpiPV;
|
||||
obj->parent = vvp_lookup_handle(var);
|
||||
obj->sbase = 0;
|
||||
obj->tbase = tbase;
|
||||
obj->twid = (unsigned) twid;
|
||||
obj->is_signed = strcmp(is_signed, "s") == 0;
|
||||
obj->width = (unsigned) width;
|
||||
obj->net = 0;
|
||||
functor_ref_lookup(&obj->net, var);
|
||||
|
||||
delete [] is_signed;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
void PV_delete(vpiHandle item)
|
||||
{
|
||||
|
||||
+325
-282
@@ -94,7 +94,8 @@ static int sysfunc_get(int type, vpiHandle ref)
|
||||
|
||||
switch (type) {
|
||||
case vpiSize:
|
||||
return rfp->vwid;
|
||||
assert(0); // This should be handled by derived classes
|
||||
return 0;
|
||||
|
||||
case vpiLineNo:
|
||||
return rfp->lineno;
|
||||
@@ -150,244 +151,6 @@ struct systask_def : public __vpiSysTaskCall {
|
||||
vpiHandle vpi_iterate(int code){ return systask_iter(code, this); }
|
||||
};
|
||||
|
||||
/*
|
||||
* A value *can* be put to a vpiSysFuncCall object. This is how the
|
||||
* return value is set. The value that is given should be converted to
|
||||
* bits and set into the thread space bits that were selected at
|
||||
* compile time.
|
||||
*/
|
||||
static vpiHandle sysfunc_put_value(vpiHandle ref, p_vpi_value vp, int)
|
||||
{
|
||||
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
|
||||
assert(rfp);
|
||||
|
||||
rfp->put_value = true;
|
||||
|
||||
assert(rfp->vbit >= 4);
|
||||
|
||||
switch (vp->format) {
|
||||
|
||||
case vpiIntVal: {
|
||||
long val = vp->value.integer;
|
||||
for (int idx = 0 ; idx < rfp->vwid ; idx += 1) {
|
||||
vthread_put_bit(vpip_current_vthread,
|
||||
rfp->vbit+idx, (val&1)? BIT4_1 :BIT4_0);
|
||||
val >>= 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiTimeVal:
|
||||
for (int idx = 0 ; idx < rfp->vwid ; idx += 1) {
|
||||
PLI_INT32 word;
|
||||
if (idx >= 32)
|
||||
word = vp->value.time->high;
|
||||
else
|
||||
word = vp->value.time->low;
|
||||
|
||||
word >>= idx % 32;
|
||||
|
||||
vthread_put_bit(vpip_current_vthread,
|
||||
rfp->vbit+idx, (word&1)? BIT4_1 :BIT4_0);
|
||||
}
|
||||
break;
|
||||
|
||||
case vpiScalarVal:
|
||||
switch (vp->value.scalar) {
|
||||
case vpi0:
|
||||
vthread_put_bit(vpip_current_vthread, rfp->vbit, BIT4_0);
|
||||
break;
|
||||
case vpi1:
|
||||
vthread_put_bit(vpip_current_vthread, rfp->vbit, BIT4_1);
|
||||
break;
|
||||
case vpiX:
|
||||
vthread_put_bit(vpip_current_vthread, rfp->vbit, BIT4_X);
|
||||
break;
|
||||
case vpiZ:
|
||||
vthread_put_bit(vpip_current_vthread, rfp->vbit, BIT4_Z);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported value %d.\n",
|
||||
(int)vp->value.scalar);
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case vpiStringVal: {
|
||||
unsigned len = strlen(vp->value.str) - 1;
|
||||
assert(len*8 <= (unsigned)rfp->vwid);
|
||||
for (unsigned wdx = 0 ; wdx < (unsigned)rfp->vwid ; wdx += 8) {
|
||||
unsigned word = wdx / 8;
|
||||
char bits;
|
||||
if (word <= len) {
|
||||
bits = vp->value.str[len-word];
|
||||
} else {
|
||||
bits = 0;
|
||||
}
|
||||
for (unsigned idx = 0 ; (wdx+idx) < (unsigned)rfp->vwid &&
|
||||
idx < 8; idx += 1) {
|
||||
vvp_bit4_t bit4 = BIT4_0;
|
||||
if (bits & 1) bit4 = BIT4_1;
|
||||
vthread_put_bit(vpip_current_vthread,
|
||||
rfp->vbit+wdx+idx, bit4);
|
||||
bits >>= 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiVectorVal:
|
||||
|
||||
for (unsigned wdx = 0 ; wdx < (unsigned)rfp->vwid ; wdx += 32) {
|
||||
unsigned word = wdx / 32;
|
||||
unsigned long aval = vp->value.vector[word].aval;
|
||||
unsigned long bval = vp->value.vector[word].bval;
|
||||
|
||||
for (unsigned idx = 0 ; (wdx+idx) < (unsigned)rfp->vwid &&
|
||||
idx < 32; idx += 1)
|
||||
{
|
||||
int bit = (aval&1) | ((bval<<1)&2);
|
||||
vvp_bit4_t bit4;
|
||||
|
||||
switch (bit) {
|
||||
case 0:
|
||||
bit4 = BIT4_0;
|
||||
break;
|
||||
case 1:
|
||||
bit4 = BIT4_1;
|
||||
break;
|
||||
case 2:
|
||||
bit4 = BIT4_Z;
|
||||
break;
|
||||
case 3:
|
||||
bit4 = BIT4_X;
|
||||
break;
|
||||
default:
|
||||
bit4 = BIT4_X;
|
||||
fprintf(stderr, "Unsupported bit value %d.\n",
|
||||
bit);
|
||||
assert(0);
|
||||
}
|
||||
vthread_put_bit(vpip_current_vthread,
|
||||
rfp->vbit+wdx+idx, bit4);
|
||||
|
||||
aval >>= 1;
|
||||
bval >>= 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unsupported format %d.\n", (int)vp->format);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static vpiHandle sysfunc_put_4net_value(vpiHandle ref, p_vpi_value vp, int)
|
||||
{
|
||||
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
|
||||
|
||||
rfp->put_value = true;
|
||||
|
||||
unsigned vwid = (unsigned) rfp->vwid;
|
||||
vvp_vector4_t val (vwid);
|
||||
|
||||
switch (vp->format) {
|
||||
|
||||
case vpiScalarVal: {
|
||||
switch(vp->value.scalar) {
|
||||
case vpi0:
|
||||
val.set_bit(0, BIT4_0);
|
||||
break;
|
||||
case vpi1:
|
||||
val.set_bit(0, BIT4_1);
|
||||
break;
|
||||
case vpiX:
|
||||
val.set_bit(0, BIT4_X);
|
||||
break;
|
||||
case vpiZ:
|
||||
val.set_bit(0, BIT4_Z);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported bit value %d.\n",
|
||||
(int)vp->value.scalar);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
case vpiIntVal: {
|
||||
long tmp = vp->value.integer;
|
||||
for (unsigned idx = 0 ; idx < vwid ; idx += 1) {
|
||||
val.set_bit(idx, (tmp&1)? BIT4_1 : BIT4_0);
|
||||
tmp >>= 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiTimeVal: {
|
||||
unsigned long tmp = vp->value.time->low;
|
||||
for (unsigned idx = 0 ; idx < vwid ; idx += 1) {
|
||||
val.set_bit(idx, (tmp&1)? BIT4_1 : BIT4_0);
|
||||
|
||||
if (idx == 31)
|
||||
tmp = vp->value.time->high;
|
||||
else
|
||||
tmp >>= 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiVectorVal:
|
||||
|
||||
for (unsigned wdx = 0 ; wdx < vwid ; wdx += 32) {
|
||||
unsigned word = wdx / 32;
|
||||
unsigned long aval = vp->value.vector[word].aval;
|
||||
unsigned long bval = vp->value.vector[word].bval;
|
||||
|
||||
for (unsigned idx = 0 ; (wdx+idx) < vwid && idx < 32;
|
||||
idx += 1) {
|
||||
int bit = (aval&1) | ((bval<<1)&2);
|
||||
vvp_bit4_t bit4;
|
||||
|
||||
switch (bit) {
|
||||
case 0:
|
||||
bit4 = BIT4_0;
|
||||
break;
|
||||
case 1:
|
||||
bit4 = BIT4_1;
|
||||
break;
|
||||
case 2:
|
||||
bit4 = BIT4_Z;
|
||||
break;
|
||||
case 3:
|
||||
bit4 = BIT4_X;
|
||||
break;
|
||||
default:
|
||||
bit4 = BIT4_X;
|
||||
fprintf(stderr, "Unsupported bit value %d.\n",
|
||||
bit);
|
||||
assert(0);
|
||||
}
|
||||
val.set_bit(wdx+idx, bit4);
|
||||
|
||||
aval >>= 1;
|
||||
bval >>= 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "XXXX format=%d, vwid=%d\n", (int)vp->format,
|
||||
rfp->vwid);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
rfp->fnet->send_vec4(val, vthread_get_wt_context());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static vpiHandle sysfunc_put_rnet_value(vpiHandle ref, p_vpi_value vp, int)
|
||||
{
|
||||
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
|
||||
@@ -417,19 +180,6 @@ static vpiHandle sysfunc_put_no_value(vpiHandle, p_vpi_value, int)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sysfunc_def : public __vpiSysTaskCall {
|
||||
inline sysfunc_def() { }
|
||||
int get_type_code(void) const { return vpiSysFuncCall; }
|
||||
int vpi_get(int code) { return sysfunc_get(code, this); }
|
||||
char* vpi_get_str(int code) { return systask_get_str(code, this); }
|
||||
vpiHandle vpi_put_value(p_vpi_value val, int flags)
|
||||
{ return sysfunc_put_value(this, val, flags); }
|
||||
vpiHandle vpi_handle(int code)
|
||||
{ return systask_handle(code, this); }
|
||||
vpiHandle vpi_iterate(int code)
|
||||
{ return systask_iter(code, this); }
|
||||
};
|
||||
|
||||
struct sysfunc_real : public __vpiSysTaskCall {
|
||||
inline sysfunc_real() { }
|
||||
int get_type_code(void) const { return vpiSysFuncCall; }
|
||||
@@ -461,17 +211,196 @@ vpiHandle sysfunc_real::vpi_put_value(p_vpi_value vp, int)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sysfunc_4net : public __vpiSysTaskCall {
|
||||
inline sysfunc_4net() { }
|
||||
class sysfunc_vec4 : public __vpiSysTaskCall {
|
||||
public:
|
||||
inline sysfunc_vec4(unsigned wid): return_value_(wid, BIT4_X) { }
|
||||
int get_type_code(void) const { return vpiSysFuncCall; }
|
||||
int vpi_get(int code) { return sysfunc_get(code, this); }
|
||||
int vpi_get(int code);
|
||||
char* vpi_get_str(int code) { return systask_get_str(code, this); }
|
||||
vpiHandle vpi_put_value(p_vpi_value val, int flags)
|
||||
{ return sysfunc_put_4net_value(this, val, flags); }
|
||||
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
||||
vpiHandle vpi_handle(int code)
|
||||
{ return systask_handle(code, this); }
|
||||
vpiHandle vpi_iterate(int code)
|
||||
{ return systask_iter(code, this); }
|
||||
|
||||
inline const vvp_vector4_t& return_value() const { return return_value_; }
|
||||
|
||||
private:
|
||||
vpiHandle put_value_scalar_(p_vpi_value vp);
|
||||
vpiHandle put_value_int_(p_vpi_value vp);
|
||||
vpiHandle put_value_string_(p_vpi_value vp);
|
||||
vpiHandle put_value_vector_(p_vpi_value vp);
|
||||
vpiHandle put_value_time_(p_vpi_value vp);
|
||||
|
||||
private:
|
||||
vvp_vector4_t return_value_;
|
||||
};
|
||||
|
||||
int sysfunc_vec4::vpi_get(int code)
|
||||
{
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return return_value_.size();
|
||||
|
||||
case vpiLineNo:
|
||||
return lineno;
|
||||
|
||||
case vpiUserDefn:
|
||||
return defn->is_user_defn;
|
||||
|
||||
default:
|
||||
return vpiUndefined;
|
||||
}
|
||||
}
|
||||
|
||||
vpiHandle sysfunc_vec4::put_value_scalar_(p_vpi_value vp)
|
||||
{
|
||||
switch (vp->value.scalar) {
|
||||
case vpi0:
|
||||
return_value_.set_bit(0, BIT4_0);
|
||||
break;
|
||||
case vpi1:
|
||||
return_value_.set_bit(0, BIT4_1);
|
||||
break;
|
||||
case vpiX:
|
||||
return_value_.set_bit(0, BIT4_X);
|
||||
break;
|
||||
case vpiZ:
|
||||
return_value_.set_bit(0, BIT4_Z);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported value %d.\n", (int)vp->value.scalar);
|
||||
assert(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
vpiHandle sysfunc_vec4::put_value_int_(p_vpi_value vp)
|
||||
{
|
||||
long tmp = vp->value.integer;
|
||||
unsigned width = return_value_.size();
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
return_value_.set_bit(idx, (tmp&1)? BIT4_1 : BIT4_0);
|
||||
tmp >>= 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
vpiHandle sysfunc_vec4::put_value_string_(p_vpi_value vp)
|
||||
{
|
||||
size_t slen = strlen(vp->value.str);
|
||||
unsigned wid = return_value_.size();
|
||||
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
unsigned cidx = idx / 8;
|
||||
// If wider then the string, then pad with zero.
|
||||
if (cidx >= slen) {
|
||||
return_value_.set_bit(idx, BIT4_0);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Put the end of the string in the LSB of the vector
|
||||
char use_char = vp->value.str[slen - 1 - cidx];
|
||||
|
||||
if ((use_char >> (idx % 8)) & 1)
|
||||
return_value_.set_bit(idx, BIT4_1);
|
||||
else
|
||||
return_value_.set_bit(idx, BIT4_0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
vpiHandle sysfunc_vec4::put_value_vector_(p_vpi_value vp)
|
||||
{
|
||||
unsigned width = return_value_.size();
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
unsigned word = idx / 32;
|
||||
unsigned bidx = idx % 32;
|
||||
|
||||
unsigned long aval = vp->value.vector[word].aval >> bidx;
|
||||
unsigned long bval = vp->value.vector[word].bval >> bidx;
|
||||
|
||||
int bit = (aval&1) | ((bval<<1)&2);
|
||||
vvp_bit4_t bit4;
|
||||
|
||||
switch (bit) {
|
||||
case 0:
|
||||
bit4 = BIT4_0;
|
||||
break;
|
||||
case 1:
|
||||
bit4 = BIT4_1;
|
||||
break;
|
||||
case 2:
|
||||
bit4 = BIT4_Z;
|
||||
break;
|
||||
case 3:
|
||||
bit4 = BIT4_X;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
bit4 = BIT4_X;
|
||||
break;
|
||||
}
|
||||
return_value_.set_bit(idx, bit4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
vpiHandle sysfunc_vec4::put_value_time_(p_vpi_value vp)
|
||||
{
|
||||
unsigned width = return_value_.size();
|
||||
long tmp = 0;
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
if (idx == 0)
|
||||
tmp = vp->value.time->low;
|
||||
else if (idx == 32)
|
||||
tmp = vp->value.time->high;
|
||||
else if (idx == 64)
|
||||
tmp = 0;
|
||||
|
||||
return_value_.set_bit(idx, (tmp&1)? BIT4_1 : BIT4_0);
|
||||
tmp >>= 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
vpiHandle sysfunc_vec4::vpi_put_value(p_vpi_value vp, int)
|
||||
{
|
||||
put_value = true;
|
||||
|
||||
switch (vp->format) {
|
||||
case vpiScalarVal:
|
||||
return put_value_scalar_(vp);
|
||||
case vpiIntVal:
|
||||
return put_value_int_(vp);
|
||||
case vpiStringVal:
|
||||
return put_value_string_(vp);
|
||||
case vpiVectorVal:
|
||||
return put_value_vector_(vp);
|
||||
case vpiTimeVal:
|
||||
return put_value_time_(vp);
|
||||
default:
|
||||
fprintf(stderr, "Unsupported format %d setting sysfunc vec4 value.\n", (int)vp->format);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sysfunc_4net : public __vpiSysTaskCall {
|
||||
inline sysfunc_4net(unsigned wid) : vwid_(wid) { }
|
||||
int get_type_code(void) const { return vpiSysFuncCall; }
|
||||
int vpi_get(int code);
|
||||
char* vpi_get_str(int code) { return systask_get_str(code, this); }
|
||||
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
||||
vpiHandle vpi_handle(int code)
|
||||
{ return systask_handle(code, this); }
|
||||
vpiHandle vpi_iterate(int code)
|
||||
{ return systask_iter(code, this); }
|
||||
|
||||
private:
|
||||
unsigned vwid_;
|
||||
};
|
||||
|
||||
struct sysfunc_rnet : public __vpiSysTaskCall {
|
||||
@@ -500,6 +429,125 @@ struct sysfunc_no : public __vpiSysTaskCall {
|
||||
{ return systask_iter(code, this); }
|
||||
};
|
||||
|
||||
|
||||
// support getting vpiSize for a system function call
|
||||
int sysfunc_4net::vpi_get(int code)
|
||||
{
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return vwid_;
|
||||
|
||||
case vpiLineNo:
|
||||
return lineno;
|
||||
|
||||
case vpiUserDefn:
|
||||
return defn->is_user_defn;
|
||||
|
||||
default:
|
||||
return vpiUndefined;
|
||||
}
|
||||
}
|
||||
|
||||
vpiHandle sysfunc_4net::vpi_put_value(p_vpi_value vp, int)
|
||||
{
|
||||
put_value = true;
|
||||
|
||||
vvp_vector4_t val (vwid_);
|
||||
|
||||
switch (vp->format) {
|
||||
|
||||
case vpiScalarVal: {
|
||||
switch(vp->value.scalar) {
|
||||
case vpi0:
|
||||
val.set_bit(0, BIT4_0);
|
||||
break;
|
||||
case vpi1:
|
||||
val.set_bit(0, BIT4_1);
|
||||
break;
|
||||
case vpiX:
|
||||
val.set_bit(0, BIT4_X);
|
||||
break;
|
||||
case vpiZ:
|
||||
val.set_bit(0, BIT4_Z);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported bit value %d.\n",
|
||||
(int)vp->value.scalar);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
case vpiIntVal: {
|
||||
long tmp = vp->value.integer;
|
||||
for (unsigned idx = 0 ; idx < vwid_ ; idx += 1) {
|
||||
val.set_bit(idx, (tmp&1)? BIT4_1 : BIT4_0);
|
||||
tmp >>= 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiTimeVal: {
|
||||
unsigned long tmp = vp->value.time->low;
|
||||
for (unsigned idx = 0 ; idx < vwid_ ; idx += 1) {
|
||||
val.set_bit(idx, (tmp&1)? BIT4_1 : BIT4_0);
|
||||
|
||||
if (idx == 31)
|
||||
tmp = vp->value.time->high;
|
||||
else
|
||||
tmp >>= 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiVectorVal:
|
||||
|
||||
for (unsigned wdx = 0 ; wdx < vwid_ ; wdx += 32) {
|
||||
unsigned word = wdx / 32;
|
||||
unsigned long aval = vp->value.vector[word].aval;
|
||||
unsigned long bval = vp->value.vector[word].bval;
|
||||
|
||||
for (unsigned idx = 0 ; (wdx+idx) < vwid_ && idx < 32;
|
||||
idx += 1) {
|
||||
int bit = (aval&1) | ((bval<<1)&2);
|
||||
vvp_bit4_t bit4;
|
||||
|
||||
switch (bit) {
|
||||
case 0:
|
||||
bit4 = BIT4_0;
|
||||
break;
|
||||
case 1:
|
||||
bit4 = BIT4_1;
|
||||
break;
|
||||
case 2:
|
||||
bit4 = BIT4_Z;
|
||||
break;
|
||||
case 3:
|
||||
bit4 = BIT4_X;
|
||||
break;
|
||||
default:
|
||||
bit4 = BIT4_X;
|
||||
fprintf(stderr, "Unsupported bit value %d.\n",
|
||||
bit);
|
||||
assert(0);
|
||||
}
|
||||
val.set_bit(wdx+idx, bit4);
|
||||
|
||||
aval >>= 1;
|
||||
bval >>= 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "XXXX format=%d, vwid_=%u\n", (int)vp->format, vwid_);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
fnet->send_vec4(val, vthread_get_wt_context());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* **** Manipulate the internal data structures. **** */
|
||||
|
||||
/*
|
||||
@@ -724,16 +772,12 @@ static void cleanup_vpi_call_args(unsigned argc, vpiHandle*argv)
|
||||
* %vpi_call statement is encountered. Create here a vpiHandle that
|
||||
* describes the call, and return it. The %vpi_call instruction will
|
||||
* store this handle for when it is executed.
|
||||
*
|
||||
* If this is called to make a function, then the vwid will be a
|
||||
* non-zero value that represents the width or type of the result. The
|
||||
* vbit is also a non-zero value, the address in thread space of the result.
|
||||
*/
|
||||
vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
|
||||
vpiHandle vpip_build_vpi_call(const char*name, int val_code, unsigned return_width,
|
||||
vvp_net_t*fnet,
|
||||
bool func_as_task_err, bool func_as_task_warn,
|
||||
unsigned argc, vpiHandle*argv,
|
||||
unsigned real_stack, unsigned string_stack,
|
||||
unsigned vec4_stack, unsigned real_stack, unsigned string_stack,
|
||||
long file_idx, long lineno)
|
||||
{
|
||||
assert(!(func_as_task_err && func_as_task_warn));
|
||||
@@ -749,7 +793,7 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
|
||||
|
||||
switch (defn->info.type) {
|
||||
case vpiSysTask:
|
||||
if (vwid != 0 || fnet != 0) {
|
||||
if (val_code != 0 || fnet != 0) {
|
||||
add_vpi_call_error(VPI_CALL_TASK_AS_FUNC, name, file_idx,
|
||||
lineno);
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
@@ -757,11 +801,10 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
assert(vbit == 0);
|
||||
break;
|
||||
|
||||
case vpiSysFunc:
|
||||
if (vwid == 0 && fnet == 0) {
|
||||
if (val_code == 0 && fnet == 0) {
|
||||
if (func_as_task_err) {
|
||||
add_vpi_call_error(VPI_CALL_FUNC_AS_TASK,
|
||||
name, file_idx, lineno);
|
||||
@@ -790,22 +833,23 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
|
||||
break;
|
||||
|
||||
case vpiSysFunc:
|
||||
if (fnet && vwid == -vpiRealConst) {
|
||||
if (fnet && val_code == -vpiRealVal) {
|
||||
obj = new sysfunc_rnet;
|
||||
|
||||
} else if (fnet && vwid > 0) {
|
||||
obj = new sysfunc_4net;
|
||||
} else if (fnet && val_code == -vpiVectorVal) {
|
||||
obj = new sysfunc_4net(return_width);
|
||||
|
||||
} else if (vwid == -vpiRealConst) {
|
||||
} else if (val_code == -vpiRealVal) {
|
||||
obj = new sysfunc_real;
|
||||
|
||||
} else if (vwid > 0) {
|
||||
obj = new sysfunc_def;
|
||||
} else if (val_code == -vpiVectorVal) {
|
||||
obj = new sysfunc_vec4(return_width);
|
||||
|
||||
} else if (vwid == 0 && fnet == 0) {
|
||||
} else if (val_code == 0 && fnet == 0) {
|
||||
obj = new sysfunc_no;
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "XXXX fnet=%p, val_code=%d\n", fnet, val_code);
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
@@ -815,10 +859,9 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
|
||||
obj->defn = defn;
|
||||
obj->nargs = argc;
|
||||
obj->args = argv;
|
||||
obj->vec4_stack = vec4_stack;
|
||||
obj->real_stack = real_stack;
|
||||
obj->string_stack = string_stack;
|
||||
obj->vbit = vbit;
|
||||
obj->vwid = vwid;
|
||||
obj->fnet = fnet;
|
||||
obj->file_idx = (unsigned) file_idx;
|
||||
obj->lineno = (unsigned) lineno;
|
||||
@@ -902,16 +945,13 @@ void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref)
|
||||
if (ref->get_type_code() == vpiSysFuncCall &&
|
||||
!vpip_cur_task->put_value) {
|
||||
s_vpi_value val;
|
||||
if (vpip_cur_task->vwid == -vpiRealConst) {
|
||||
val.format = vpiRealVal;
|
||||
val.value.real = 0.0;
|
||||
} else {
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = 0;
|
||||
}
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = 0;
|
||||
vpi_put_value(ref, &val, 0, vpiNoDelay);
|
||||
}
|
||||
}
|
||||
if (vpip_cur_task->vec4_stack > 0)
|
||||
vthread_pop_vec4(thr, vpip_cur_task->vec4_stack);
|
||||
if (vpip_cur_task->real_stack > 0)
|
||||
vthread_pop_real(thr, vpip_cur_task->real_stack);
|
||||
if (vpip_cur_task->string_stack > 0)
|
||||
@@ -922,6 +962,9 @@ void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref)
|
||||
if (sysfunc_real*func_real = dynamic_cast<sysfunc_real*>(ref)) {
|
||||
vthread_push_real(thr, func_real->return_value_);
|
||||
}
|
||||
if (sysfunc_vec4*func_vec4 = dynamic_cast<sysfunc_vec4*>(ref)) {
|
||||
vthread_push_vec4(thr, func_vec4->return_value());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+272
-423
@@ -35,33 +35,6 @@
|
||||
# include <cassert>
|
||||
# include "ivl_alloc.h"
|
||||
|
||||
struct __vpiVThrVec : public __vpiHandle {
|
||||
__vpiVThrVec();
|
||||
int get_type_code(void) const;
|
||||
int vpi_get(int code);
|
||||
char* vpi_get_str(int code);
|
||||
void vpi_get_value(p_vpi_value val);
|
||||
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
||||
|
||||
unsigned bas;
|
||||
unsigned wid;
|
||||
unsigned signed_flag : 1;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
inline static
|
||||
vvp_bit4_t get_bit(struct __vpiVThrVec *rfp, unsigned idx)
|
||||
{
|
||||
return vthread_get_bit(vpip_current_vthread, rfp->bas+idx);
|
||||
}
|
||||
|
||||
inline static
|
||||
void set_bit(struct __vpiVThrVec *rfp, unsigned idx, vvp_bit4_t bit)
|
||||
{
|
||||
return vthread_put_bit(vpip_current_vthread, rfp->bas+idx, bit);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Hex digits that represent 4-value bits of Verilog are not as
|
||||
* trivially obvious to display as if the bits were the usual 2-value
|
||||
@@ -73,405 +46,10 @@ void set_bit(struct __vpiVThrVec *rfp, unsigned idx, vvp_bit4_t bit)
|
||||
* The table is calculated as compile time, therefore, by the
|
||||
* draw_tt.c program.
|
||||
*/
|
||||
|
||||
extern const char hex_digits[256];
|
||||
|
||||
extern const char oct_digits[64];
|
||||
|
||||
/*
|
||||
* vpi_get
|
||||
*/
|
||||
static int vthr_vec_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiVThrVec*rfp = dynamic_cast<__vpiVThrVec*>(ref);
|
||||
assert(rfp);
|
||||
|
||||
switch (code) {
|
||||
|
||||
case vpiSigned:
|
||||
return rfp->signed_flag;
|
||||
|
||||
case vpiConstType:
|
||||
return vpiBinaryConst; // If this is a constant it is Binary.
|
||||
|
||||
case vpiSize:
|
||||
return rfp->wid;
|
||||
|
||||
#if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX)
|
||||
case _vpiFromThr:
|
||||
return _vpiVThr;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char* vthr_vec_get_str(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiVThrVec*rfp = dynamic_cast<__vpiVThrVec*>(ref);
|
||||
assert(rfp);
|
||||
|
||||
switch (code) {
|
||||
|
||||
case vpiFullName: /* should this be vpiName? */
|
||||
return simple_set_rbuf_str(rfp->name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vthr_vec_DecStrVal(struct __vpiVThrVec*rfp, s_vpi_value*vp)
|
||||
{
|
||||
int nbuf = (rfp->wid+2)/3 + 1;
|
||||
char *rbuf = (char *) need_result_buf(nbuf, RBUF_VAL);
|
||||
|
||||
vvp_vector4_t tmp (rfp->wid);
|
||||
for (unsigned idx = 0 ; idx < rfp->wid ; idx += 1)
|
||||
tmp.set_bit(idx, get_bit(rfp, idx));
|
||||
|
||||
vpip_vec4_to_dec_str(tmp, rbuf, nbuf, rfp->signed_flag);
|
||||
vp->value.str = rbuf;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void vthr_vec_StringVal(struct __vpiVThrVec*rfp, s_vpi_value*vp)
|
||||
{
|
||||
char tmp = 0;
|
||||
char *rbuf = (char *) need_result_buf((rfp->wid / 8) + 1, RBUF_VAL);
|
||||
char *cp = rbuf;
|
||||
|
||||
for(int bitnr=rfp->wid-1; bitnr>=0; bitnr--){
|
||||
tmp <<= 1;
|
||||
|
||||
switch(get_bit(rfp, bitnr)){
|
||||
case BIT4_0:
|
||||
break;
|
||||
case BIT4_1:
|
||||
tmp |= 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((bitnr&7)==0){
|
||||
// Don't including leading nulls
|
||||
if (tmp == 0 && cp == rbuf)
|
||||
continue;
|
||||
|
||||
// Translated embedded nulls to space.
|
||||
*cp++ = tmp? tmp : ' ';
|
||||
tmp = 0;
|
||||
}
|
||||
}
|
||||
*cp++ = 0;
|
||||
vp->value.str = rbuf;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The get_value method reads the values of the functors and returns
|
||||
* the vector to the caller. This causes no side-effect, and reads the
|
||||
* variables like a %load would.
|
||||
*/
|
||||
static void vthr_vec_get_value(vpiHandle ref, s_vpi_value*vp)
|
||||
{
|
||||
struct __vpiVThrVec*rfp = dynamic_cast<__vpiVThrVec*>(ref);
|
||||
assert(rfp);
|
||||
char *rbuf;
|
||||
|
||||
unsigned wid = rfp->wid;
|
||||
|
||||
switch (vp->format) {
|
||||
|
||||
case vpiBinStrVal:
|
||||
rbuf = (char *) need_result_buf(wid+1, RBUF_VAL);
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
rbuf[wid-idx-1] = vvp_bit4_to_ascii(get_bit(rfp, idx));
|
||||
}
|
||||
rbuf[wid] = 0;
|
||||
vp->value.str = rbuf;
|
||||
break;
|
||||
|
||||
case vpiHexStrVal: {
|
||||
unsigned hval, hwid;
|
||||
hwid = (wid + 3) / 4;
|
||||
rbuf = (char *) need_result_buf(hwid+1, RBUF_VAL);
|
||||
rbuf[hwid] = 0;
|
||||
hval = 0;
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
unsigned tmp = 0;
|
||||
switch (get_bit(rfp, idx)) {
|
||||
case BIT4_0:
|
||||
tmp = 0;
|
||||
break;
|
||||
case BIT4_1:
|
||||
tmp = 1;
|
||||
break;
|
||||
case BIT4_X:
|
||||
tmp = 2;
|
||||
break;
|
||||
case BIT4_Z:
|
||||
tmp = 3;
|
||||
break;
|
||||
}
|
||||
hval = hval | (tmp << 2*(idx % 4));
|
||||
|
||||
if (idx%4 == 3) {
|
||||
hwid -= 1;
|
||||
rbuf[hwid] = hex_digits[hval];
|
||||
hval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (hwid > 0) {
|
||||
hwid -= 1;
|
||||
rbuf[hwid] = hex_digits[hval];
|
||||
hval = 0;
|
||||
}
|
||||
vp->value.str = rbuf;
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiOctStrVal: {
|
||||
unsigned hval, hwid;
|
||||
hwid = (wid + 2) / 3;
|
||||
rbuf = (char *) need_result_buf(hwid+1, RBUF_VAL);
|
||||
rbuf[hwid] = 0;
|
||||
hval = 0;
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
unsigned tmp = 0;
|
||||
switch (get_bit(rfp, idx)) {
|
||||
case BIT4_0:
|
||||
tmp = 0;
|
||||
break;
|
||||
case BIT4_1:
|
||||
tmp = 1;
|
||||
break;
|
||||
case BIT4_X:
|
||||
tmp = 2;
|
||||
break;
|
||||
case BIT4_Z:
|
||||
tmp = 3;
|
||||
break;
|
||||
}
|
||||
hval = hval | (tmp << 2*(idx % 3));
|
||||
|
||||
if (idx%3 == 2) {
|
||||
hwid -= 1;
|
||||
rbuf[hwid] = oct_digits[hval];
|
||||
hval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (hwid > 0) {
|
||||
hwid -= 1;
|
||||
rbuf[hwid] = oct_digits[hval];
|
||||
hval = 0;
|
||||
}
|
||||
vp->value.str = rbuf;
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiDecStrVal:
|
||||
vthr_vec_DecStrVal(rfp, vp);
|
||||
break;
|
||||
|
||||
case vpiStringVal:
|
||||
vthr_vec_StringVal(rfp, vp);
|
||||
break;
|
||||
|
||||
case vpiIntVal: {
|
||||
long ival = 0;
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
switch (get_bit(rfp, idx)) {
|
||||
case BIT4_0:
|
||||
break;
|
||||
case BIT4_1:
|
||||
ival |= 1 << idx;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
vp->value.integer = ival;
|
||||
}
|
||||
break;
|
||||
|
||||
case vpiRealVal:
|
||||
vp->value.real = 0;
|
||||
for (unsigned idx = wid ; idx > 0 ; idx -= 1) {
|
||||
vp->value.real *= 2.0;
|
||||
switch (get_bit(rfp, idx-1)) {
|
||||
case BIT4_0:
|
||||
break;
|
||||
case BIT4_1:
|
||||
vp->value.real += 1.0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case vpiObjTypeVal:
|
||||
vp->format = vpiVectorVal;
|
||||
case vpiVectorVal:
|
||||
vp->value.vector = (s_vpi_vecval*)
|
||||
need_result_buf((wid+31)/32*sizeof(s_vpi_vecval), RBUF_VAL);
|
||||
assert(vp->value.vector);
|
||||
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
int word = idx/32;
|
||||
PLI_INT32 mask = 1 << (idx%32);
|
||||
|
||||
switch (get_bit(rfp,idx)) {
|
||||
case BIT4_0:
|
||||
vp->value.vector[word].aval &= ~mask;
|
||||
vp->value.vector[word].bval &= ~mask;
|
||||
break;
|
||||
case BIT4_1:
|
||||
vp->value.vector[word].aval |= mask;
|
||||
vp->value.vector[word].bval &= ~mask;
|
||||
break;
|
||||
case BIT4_X:
|
||||
vp->value.vector[word].aval |= mask;
|
||||
vp->value.vector[word].bval |= mask;
|
||||
break;
|
||||
case BIT4_Z:
|
||||
vp->value.vector[word].aval &= ~mask;
|
||||
vp->value.vector[word].bval |= mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "internal error: vpi_get_value(<format=%d>)"
|
||||
" not implemented for vthr_vectors.\n", (int)vp->format);
|
||||
/* XXXX Not implemented yet. */
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The put_value method writes the value into the vector.
|
||||
*/
|
||||
static vpiHandle vthr_vec_put_value(vpiHandle ref, s_vpi_value*vp, int)
|
||||
{
|
||||
struct __vpiVThrVec*rfp = dynamic_cast<__vpiVThrVec*>(ref);
|
||||
assert(rfp);
|
||||
|
||||
unsigned wid = rfp->wid;
|
||||
|
||||
switch (vp->format) {
|
||||
|
||||
case vpiIntVal: {
|
||||
assert(wid <= sizeof(long));
|
||||
|
||||
long val = vp->value.integer;
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
set_bit(rfp, idx, (val&1)? BIT4_1 : BIT4_0);
|
||||
val >>= 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiScalarVal:
|
||||
switch (vp->value.scalar) {
|
||||
case vpi0:
|
||||
set_bit(rfp, 0, BIT4_0);
|
||||
break;
|
||||
case vpi1:
|
||||
set_bit(rfp, 0, BIT4_1);
|
||||
break;
|
||||
case vpiX:
|
||||
set_bit(rfp, 0, BIT4_X);
|
||||
break;
|
||||
case vpiZ:
|
||||
set_bit(rfp, 0, BIT4_Z);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported scalar value %d.\n",
|
||||
(int)vp->value.scalar);
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case vpiVectorVal: {
|
||||
assert(wid <= sizeof (unsigned long));
|
||||
|
||||
unsigned long aval = vp->value.vector->aval;
|
||||
unsigned long bval = vp->value.vector->bval;
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
int bit = (aval&1) | (((bval^aval)<<1)&2);
|
||||
switch (bit) {
|
||||
case 0:
|
||||
set_bit(rfp, idx, BIT4_0);
|
||||
break;
|
||||
case 1:
|
||||
set_bit(rfp, idx, BIT4_1);
|
||||
break;
|
||||
case 2:
|
||||
set_bit(rfp, idx, BIT4_X);
|
||||
break;
|
||||
case 3:
|
||||
set_bit(rfp, idx, BIT4_Z);
|
||||
break;
|
||||
}
|
||||
aval >>= 1;
|
||||
bval >>= 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unsupported format %d.\n", (int)vp->format);
|
||||
assert(0);
|
||||
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
// The code fully supports vpiReg, vpi_Net, but we do not
|
||||
// create such things, yet. Lacking a name, for example.
|
||||
|
||||
inline __vpiVThrVec::__vpiVThrVec()
|
||||
{ }
|
||||
|
||||
int __vpiVThrVec::get_type_code(void) const
|
||||
{ return vpiConstant; }
|
||||
|
||||
int __vpiVThrVec::vpi_get(int code)
|
||||
{ return vthr_vec_get(code, this); }
|
||||
|
||||
char* __vpiVThrVec::vpi_get_str(int code)
|
||||
{ return vthr_vec_get_str(code, this); }
|
||||
|
||||
void __vpiVThrVec::vpi_get_value(p_vpi_value val)
|
||||
{ vthr_vec_get_value(this, val); }
|
||||
|
||||
vpiHandle __vpiVThrVec::vpi_put_value(p_vpi_value val, int flags)
|
||||
{ return vthr_vec_put_value(this, val, flags); }
|
||||
|
||||
/*
|
||||
* Construct a vpiReg object. Give the object specified dimensions,
|
||||
* and point to the specified functor for the lsb.
|
||||
*/
|
||||
vpiHandle vpip_make_vthr_vector(unsigned base, unsigned wid, bool signed_flag)
|
||||
{
|
||||
struct __vpiVThrVec*obj = new __vpiVThrVec;
|
||||
assert(base < 65536);
|
||||
obj->bas = base;
|
||||
assert(wid < 65536);
|
||||
obj->wid = wid;
|
||||
obj->signed_flag = signed_flag? 1 : 0;
|
||||
obj->name = vpip_name_string("T<>");
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
static map<vpiHandle, bool> handle_map;
|
||||
@@ -650,7 +228,6 @@ class __vpiVThrStrStack : public __vpiHandle {
|
||||
int vpi_get(int code);
|
||||
void vpi_get_value(p_vpi_value val);
|
||||
private:
|
||||
const char* name;
|
||||
unsigned depth_;
|
||||
};
|
||||
|
||||
@@ -703,6 +280,272 @@ void __vpiVThrStrStack::vpi_get_value(p_vpi_value vp)
|
||||
}
|
||||
}
|
||||
|
||||
class __vpiVThrVec4Stack : public __vpiHandle {
|
||||
public:
|
||||
__vpiVThrVec4Stack(unsigned depth, bool signed_flag, unsigned wid);
|
||||
int get_type_code(void) const;
|
||||
int vpi_get(int code);
|
||||
char*vpi_get_str(int code);
|
||||
void vpi_get_value(p_vpi_value val);
|
||||
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
||||
private:
|
||||
void vpi_get_value_string_(p_vpi_value vp, const vvp_vector4_t&val);
|
||||
void vpi_get_value_binstr_(p_vpi_value vp, const vvp_vector4_t&val);
|
||||
void vpi_get_value_decstr_(p_vpi_value vp, const vvp_vector4_t&val);
|
||||
void vpi_get_value_int_ (p_vpi_value vp, const vvp_vector4_t&val);
|
||||
void vpi_get_value_real_ (p_vpi_value vp, const vvp_vector4_t&val);
|
||||
void vpi_get_value_hexstr_(p_vpi_value vp, const vvp_vector4_t&val);
|
||||
void vpi_get_value_vector_(p_vpi_value vp, const vvp_vector4_t&val);
|
||||
private:
|
||||
unsigned depth_;
|
||||
bool signed_flag_;
|
||||
unsigned expect_width_;
|
||||
const char*name;
|
||||
};
|
||||
|
||||
__vpiVThrVec4Stack::__vpiVThrVec4Stack(unsigned d, bool sf, unsigned wid)
|
||||
: depth_(d), signed_flag_(sf), expect_width_(wid)
|
||||
{
|
||||
name = vpip_name_string("S<,vec4,>");
|
||||
}
|
||||
|
||||
int __vpiVThrVec4Stack::get_type_code(void) const
|
||||
{ return vpiConstant; }
|
||||
|
||||
|
||||
int __vpiVThrVec4Stack::vpi_get(int code)
|
||||
{
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return expect_width_;
|
||||
|
||||
case vpiSigned:
|
||||
return signed_flag_? 1 : 0;
|
||||
|
||||
case vpiConstType:
|
||||
return vpiBinaryConst;
|
||||
|
||||
#if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX)
|
||||
case _vpiFromThr:
|
||||
return _vpiVThr;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
char*__vpiVThrVec4Stack::vpi_get_str(int code)
|
||||
{
|
||||
switch (code) {
|
||||
case vpiFullName:
|
||||
return simple_set_rbuf_str(name);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void __vpiVThrVec4Stack::vpi_get_value(p_vpi_value vp)
|
||||
{
|
||||
vvp_vector4_t val;
|
||||
|
||||
if (vpip_current_vthread)
|
||||
val = vthread_get_vec4_stack(vpip_current_vthread, depth_);
|
||||
|
||||
switch (vp->format) {
|
||||
|
||||
case vpiBinStrVal:
|
||||
vpi_get_value_binstr_(vp, val);
|
||||
break;
|
||||
case vpiDecStrVal:
|
||||
vpi_get_value_decstr_(vp, val);
|
||||
break;
|
||||
case vpiHexStrVal:
|
||||
vpi_get_value_hexstr_(vp, val);
|
||||
break;
|
||||
case vpiIntVal:
|
||||
vpi_get_value_int_(vp, val);
|
||||
break;
|
||||
case vpiRealVal:
|
||||
vpi_get_value_real_(vp, val);
|
||||
break;
|
||||
case vpiStringVal:
|
||||
vpi_get_value_string_(vp, val);
|
||||
break;
|
||||
case vpiObjTypeVal:
|
||||
vp->format = vpiVectorVal;
|
||||
case vpiVectorVal:
|
||||
vpi_get_value_vector_(vp, val);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "internal error: vpi_get_value(<format=%d>)"
|
||||
" not implemented for __vpiVThrVec4Stack.\n", vp->format);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void __vpiVThrVec4Stack::vpi_get_value_binstr_(p_vpi_value vp, const vvp_vector4_t&val)
|
||||
{
|
||||
unsigned wid = val.size();
|
||||
char*rbuf = (char*) need_result_buf(wid+1, RBUF_VAL);
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
rbuf[wid-idx-1] = vvp_bit4_to_ascii(val.value(idx));
|
||||
}
|
||||
rbuf[wid] = 0;
|
||||
vp->value.str = rbuf;
|
||||
}
|
||||
|
||||
void __vpiVThrVec4Stack::vpi_get_value_decstr_(p_vpi_value vp, const vvp_vector4_t&val)
|
||||
{
|
||||
unsigned wid = val.size();
|
||||
int nbuf = (wid+2)/3 + 1;
|
||||
char *rbuf = (char*) need_result_buf(nbuf, RBUF_VAL);
|
||||
|
||||
vpip_vec4_to_dec_str(val, rbuf, nbuf, signed_flag_);
|
||||
vp->value.str = rbuf;
|
||||
}
|
||||
|
||||
void __vpiVThrVec4Stack::vpi_get_value_hexstr_(p_vpi_value vp, const vvp_vector4_t&val)
|
||||
{
|
||||
unsigned wid = val.size();
|
||||
unsigned hwid = (wid + 3) /4;
|
||||
char*rbuf = (char*) need_result_buf(hwid+1, RBUF_VAL);
|
||||
rbuf[hwid] = 0;
|
||||
|
||||
unsigned hval = 0;
|
||||
for (unsigned idx = 0; idx < wid ; idx += 1) {
|
||||
unsigned tmp = 0;
|
||||
switch (val.value(idx)) {
|
||||
case BIT4_0:
|
||||
tmp = 0;
|
||||
break;
|
||||
case BIT4_1:
|
||||
tmp = 1;
|
||||
break;
|
||||
case BIT4_X:
|
||||
tmp = 2;
|
||||
break;
|
||||
case BIT4_Z:
|
||||
tmp = 3;
|
||||
break;
|
||||
}
|
||||
hval = hval | (tmp << 2*(idx%4));
|
||||
|
||||
if (idx%4 == 3) {
|
||||
hwid -= 1;
|
||||
rbuf[hwid] = hex_digits[hval];
|
||||
hval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (hwid > 0) {
|
||||
hwid -= 1;
|
||||
rbuf[hwid] = hex_digits[hval];
|
||||
hval = 0;
|
||||
}
|
||||
vp->value.str = rbuf;
|
||||
}
|
||||
|
||||
void __vpiVThrVec4Stack::vpi_get_value_int_(p_vpi_value vp, const vvp_vector4_t&val)
|
||||
{
|
||||
int32_t vali = 0;
|
||||
int signed_flag = 0;
|
||||
vector4_to_value(val, vali, signed_flag, false);
|
||||
vp->value.integer = vali;
|
||||
}
|
||||
|
||||
void __vpiVThrVec4Stack::vpi_get_value_real_(p_vpi_value vp, const vvp_vector4_t&val)
|
||||
{
|
||||
unsigned wid = val.size();
|
||||
vp->value.real = 0.0;
|
||||
|
||||
for (unsigned idx = wid ; idx > 0 ; idx -= 1) {
|
||||
vp->value.real *= 2.0;
|
||||
if (val.value(idx-1) == BIT4_1)
|
||||
vp->value.real += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
void __vpiVThrVec4Stack::vpi_get_value_string_(p_vpi_value vp, const vvp_vector4_t&val)
|
||||
{
|
||||
char*rbuf = (char*) need_result_buf((val.size() / 8) + 1, RBUF_VAL);
|
||||
char*cp = rbuf;
|
||||
|
||||
char tmp = 0;
|
||||
for (int bitnr = val.size()-1 ; bitnr >= 0 ; bitnr -= 1) {
|
||||
tmp <<= 1;
|
||||
switch (val.value(bitnr)) {
|
||||
case BIT4_1:
|
||||
tmp |= 1;
|
||||
break;
|
||||
case BIT4_0:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((bitnr&7)==0) {
|
||||
// Don't include leading nuls
|
||||
if (tmp == 0 && cp == rbuf)
|
||||
continue;
|
||||
|
||||
*cp++ = tmp? tmp : ' ';
|
||||
tmp = 0;
|
||||
}
|
||||
}
|
||||
*cp++ = 0;
|
||||
vp->format = vpiStringVal;
|
||||
vp->value.str = rbuf;
|
||||
}
|
||||
|
||||
void __vpiVThrVec4Stack::vpi_get_value_vector_(p_vpi_value vp, const vvp_vector4_t&val)
|
||||
{
|
||||
unsigned wid = val.size();
|
||||
|
||||
vp->value.vector = (s_vpi_vecval*)
|
||||
need_result_buf((wid+31)/32*sizeof(s_vpi_vecval), RBUF_VAL);
|
||||
assert(vp->value.vector);
|
||||
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
int word = idx/32;
|
||||
PLI_INT32 mask = 1 << (idx%32);
|
||||
|
||||
switch (val.value(idx)) {
|
||||
case BIT4_0:
|
||||
vp->value.vector[word].aval &= ~mask;
|
||||
vp->value.vector[word].bval &= ~mask;
|
||||
break;
|
||||
case BIT4_1:
|
||||
vp->value.vector[word].aval |= mask;
|
||||
vp->value.vector[word].bval &= ~mask;
|
||||
break;
|
||||
case BIT4_X:
|
||||
vp->value.vector[word].aval |= mask;
|
||||
vp->value.vector[word].bval |= mask;
|
||||
break;
|
||||
case BIT4_Z:
|
||||
vp->value.vector[word].aval &= ~mask;
|
||||
vp->value.vector[word].bval |= mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vpiHandle __vpiVThrVec4Stack::vpi_put_value(p_vpi_value vp, int /*flags*/)
|
||||
{
|
||||
assert(vpip_current_vthread);
|
||||
|
||||
switch (vp->format) {
|
||||
|
||||
default:
|
||||
fprintf(stderr, "internal error: vpi_put_value(<format=%d>)"
|
||||
" not implemented for __vpiVThrVec4Stack.\n", vp->format);
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
vpiHandle vpip_make_vthr_str_stack(unsigned depth)
|
||||
{
|
||||
@@ -710,6 +553,12 @@ vpiHandle vpip_make_vthr_str_stack(unsigned depth)
|
||||
return obj;
|
||||
}
|
||||
|
||||
vpiHandle vpip_make_vthr_vec4_stack(unsigned depth, bool signed_flag, unsigned wid)
|
||||
{
|
||||
class __vpiVThrVec4Stack*obj = new __vpiVThrVec4Stack(depth, signed_flag, wid);
|
||||
return obj;
|
||||
}
|
||||
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
static map<vpiHandle, bool> stack_map;
|
||||
|
||||
|
||||
+2095
-2355
File diff suppressed because it is too large
Load Diff
+4
-6
@@ -109,15 +109,12 @@ extern vvp_context_item_t vthread_get_wt_context_item(unsigned context_idx);
|
||||
extern vvp_context_item_t vthread_get_rd_context_item(unsigned context_idx);
|
||||
|
||||
/*
|
||||
* Return a bit from the thread's bit space. These are used, for
|
||||
* example, when a VPI implementation function needs to access the bit
|
||||
* space of the thread.
|
||||
* Access value stacks from thread space.
|
||||
*/
|
||||
extern vvp_bit4_t vthread_get_bit(struct vthread_s*thr, unsigned addr);
|
||||
extern void vthread_put_bit(struct vthread_s*thr, unsigned addr, vvp_bit4_t bit);
|
||||
|
||||
extern void vthread_push_vec4(struct vthread_s*thr, const vvp_vector4_t&val);
|
||||
extern void vthread_push_real(struct vthread_s*thr, double val);
|
||||
|
||||
extern void vthread_pop_vec4(struct vthread_s*thr, unsigned count);
|
||||
extern void vthread_pop_str(struct vthread_s*thr, unsigned count);
|
||||
extern void vthread_pop_real(struct vthread_s*thr, unsigned count);
|
||||
|
||||
@@ -127,6 +124,7 @@ extern void vthread_pop_real(struct vthread_s*thr, unsigned count);
|
||||
depth==1, etc. */
|
||||
extern const std::string&vthread_get_str_stack(struct vthread_s*thr, unsigned depth);
|
||||
extern double vthread_get_real_stack(struct vthread_s*thr, unsigned depth);
|
||||
extern const vvp_vector4_t& vthread_get_vec4_stack(struct vthread_s*thr, unsigned depth);
|
||||
|
||||
/* This is used to actually delete a thread once we are done with it. */
|
||||
extern void vthread_delete(vthread_t thr);
|
||||
|
||||
+374
-48
@@ -41,6 +41,11 @@
|
||||
# include "ivl_alloc.h"
|
||||
#endif
|
||||
|
||||
/* This is the size of an unsigned long in bits. This is just a
|
||||
convenience macro. */
|
||||
# define CPU_WORD_BITS (8*sizeof(unsigned long))
|
||||
# define TOP_BIT (1UL << (CPU_WORD_BITS-1))
|
||||
|
||||
permaheap vvp_net_fun_t::heap_;
|
||||
permaheap vvp_net_fil_t::heap_;
|
||||
|
||||
@@ -510,6 +515,49 @@ int edge(vvp_bit4_t from, vvp_bit4_t to)
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long multiply_with_carry(unsigned long a, unsigned long b,
|
||||
unsigned long&carry)
|
||||
{
|
||||
const unsigned long mask = (1UL << (CPU_WORD_BITS/2)) - 1;
|
||||
unsigned long a0 = a & mask;
|
||||
unsigned long a1 = (a >> (CPU_WORD_BITS/2)) & mask;
|
||||
unsigned long b0 = b & mask;
|
||||
unsigned long b1 = (b >> (CPU_WORD_BITS/2)) & mask;
|
||||
|
||||
unsigned long tmp = a0 * b0;
|
||||
|
||||
unsigned long r00 = tmp & mask;
|
||||
unsigned long c00 = (tmp >> (CPU_WORD_BITS/2)) & mask;
|
||||
|
||||
tmp = a0 * b1;
|
||||
|
||||
unsigned long r01 = tmp & mask;
|
||||
unsigned long c01 = (tmp >> (CPU_WORD_BITS/2)) & mask;
|
||||
|
||||
tmp = a1 * b0;
|
||||
|
||||
unsigned long r10 = tmp & mask;
|
||||
unsigned long c10 = (tmp >> (CPU_WORD_BITS/2)) & mask;
|
||||
|
||||
tmp = a1 * b1;
|
||||
|
||||
unsigned long r11 = tmp & mask;
|
||||
unsigned long c11 = (tmp >> (CPU_WORD_BITS/2)) & mask;
|
||||
|
||||
unsigned long r1 = c00 + r01 + r10;
|
||||
unsigned long r2 = (r1 >> (CPU_WORD_BITS/2)) & mask;
|
||||
r1 &= mask;
|
||||
r2 += c01 + c10 + r11;
|
||||
unsigned long r3 = (r2 >> (CPU_WORD_BITS/2)) & mask;
|
||||
r2 &= mask;
|
||||
r3 += c11;
|
||||
r3 &= mask;
|
||||
|
||||
carry = (r3 << (CPU_WORD_BITS/2)) + r2;
|
||||
return (r1 << (CPU_WORD_BITS/2)) + r00;
|
||||
}
|
||||
|
||||
|
||||
void vvp_send_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&val)
|
||||
{
|
||||
while (vvp_net_t*cur = ptr.ptr()) {
|
||||
@@ -643,23 +691,20 @@ void vvp_vector4_t::copy_bits(const vvp_vector4_t&that)
|
||||
}
|
||||
}
|
||||
|
||||
void vvp_vector4_t::copy_from_(const vvp_vector4_t&that)
|
||||
/*
|
||||
* This function should ONLY BE CALLED FROM vvp_vector4_t::copy_from_,
|
||||
* as it performs part of that functions tasks.
|
||||
*/
|
||||
void vvp_vector4_t::copy_from_big_(const vvp_vector4_t&that)
|
||||
{
|
||||
size_ = that.size_;
|
||||
if (size_ > BITS_PER_WORD) {
|
||||
unsigned words = (size_+BITS_PER_WORD-1) / BITS_PER_WORD;
|
||||
abits_ptr_ = new unsigned long[2*words];
|
||||
bbits_ptr_ = abits_ptr_ + words;
|
||||
unsigned words = (size_+BITS_PER_WORD-1) / BITS_PER_WORD;
|
||||
abits_ptr_ = new unsigned long[2*words];
|
||||
bbits_ptr_ = abits_ptr_ + words;
|
||||
|
||||
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
||||
abits_ptr_[idx] = that.abits_ptr_[idx];
|
||||
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
||||
bbits_ptr_[idx] = that.bbits_ptr_[idx];
|
||||
|
||||
} else {
|
||||
abits_val_ = that.abits_val_;
|
||||
bbits_val_ = that.bbits_val_;
|
||||
}
|
||||
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
||||
abits_ptr_[idx] = that.abits_ptr_[idx];
|
||||
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
||||
bbits_ptr_[idx] = that.bbits_ptr_[idx];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -793,11 +838,30 @@ vvp_vector4_t::vvp_vector4_t(unsigned size__, double val)
|
||||
vvp_vector4_t::vvp_vector4_t(const vvp_vector4_t&that,
|
||||
unsigned adr, unsigned wid)
|
||||
{
|
||||
// Set up and initialize the destination.
|
||||
size_ = wid;
|
||||
assert((adr + wid) <= that.size_);
|
||||
|
||||
allocate_words_(WORD_X_ABITS, WORD_X_BBITS);
|
||||
|
||||
// Special case: selecting from far beyond the source vector,
|
||||
// to the result is all X bits. We're done.
|
||||
if (adr >= that.size_)
|
||||
return;
|
||||
|
||||
// Special case: The source is not quite big enough to supply
|
||||
// all bits, so get the bits that we can. The remainder will
|
||||
// be left at BIT4_X.
|
||||
if ((adr + wid) > that.size_) {
|
||||
unsigned use_wid = that.size_ - adr;
|
||||
for (unsigned idx = 0 ; idx < use_wid ; idx += 1)
|
||||
set_bit(idx, that.value(adr+idx));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// At the point, we know that the source part is entirely
|
||||
// contained in the source vector.
|
||||
// assert((adr + wid) <= that.size_);
|
||||
|
||||
if (wid > BITS_PER_WORD) {
|
||||
/* In this case, the subvector and the source vector are
|
||||
long. Do the transfer reasonably efficiently. */
|
||||
@@ -889,18 +953,46 @@ vvp_vector4_t::vvp_vector4_t(const vvp_vector4_t&that,
|
||||
* Change the size of the vvp_vector4_t vector to the new size. Copy
|
||||
* the old values, as many as well fit, into the new vector.
|
||||
*/
|
||||
void vvp_vector4_t::resize(unsigned newsize)
|
||||
void vvp_vector4_t::resize(unsigned newsize, vvp_bit4_t pad_bit)
|
||||
{
|
||||
if (size_ == newsize)
|
||||
return;
|
||||
|
||||
unsigned cnt = (size_ + BITS_PER_WORD - 1) / BITS_PER_WORD;
|
||||
unsigned long word_pad_abits = 0;
|
||||
unsigned long word_pad_bbits = 0;
|
||||
switch (pad_bit) {
|
||||
case BIT4_0:
|
||||
word_pad_abits = WORD_0_ABITS;
|
||||
word_pad_bbits = WORD_0_BBITS;
|
||||
break;
|
||||
case BIT4_1:
|
||||
word_pad_abits = WORD_1_ABITS;
|
||||
word_pad_bbits = WORD_1_BBITS;
|
||||
break;
|
||||
case BIT4_X:
|
||||
word_pad_abits = WORD_X_ABITS;
|
||||
word_pad_bbits = WORD_X_BBITS;
|
||||
break;
|
||||
case BIT4_Z:
|
||||
word_pad_abits = WORD_Z_ABITS;
|
||||
word_pad_bbits = WORD_Z_BBITS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (newsize > BITS_PER_WORD) {
|
||||
unsigned newcnt = (newsize + BITS_PER_WORD - 1) / BITS_PER_WORD;
|
||||
if (newcnt == cnt) {
|
||||
// If the word count doesn't change, then there is
|
||||
// no need for re-allocation so we are done now.
|
||||
if (newsize > size_) {
|
||||
if (unsigned fill = size_ % BITS_PER_WORD) {
|
||||
abits_ptr_[cnt-1] &= ~((-1L) << fill);
|
||||
bbits_ptr_[cnt-1] &= ~((-1L) << fill);
|
||||
abits_ptr_[cnt-1] |= word_pad_abits << fill;
|
||||
bbits_ptr_[cnt-1] |= word_pad_bbits << fill;
|
||||
}
|
||||
}
|
||||
size_ = newsize;
|
||||
return;
|
||||
}
|
||||
@@ -924,10 +1016,18 @@ void vvp_vector4_t::resize(unsigned newsize)
|
||||
newbits[newcnt] = bbits_val_;
|
||||
}
|
||||
|
||||
for (unsigned idx = cnt ; idx < newcnt ; idx += 1)
|
||||
newbits[idx] = WORD_X_ABITS;
|
||||
for (unsigned idx = cnt ; idx < newcnt ; idx += 1)
|
||||
newbits[newcnt+idx] = WORD_X_BBITS;
|
||||
if (newsize > size_) {
|
||||
if (unsigned fill = size_ % BITS_PER_WORD) {
|
||||
newbits[cnt-1] &= ~((-1L) << fill);
|
||||
newbits[cnt-1] |= word_pad_abits << fill;
|
||||
newbits[newcnt+cnt-1] &= ~((-1L) << fill);
|
||||
newbits[newcnt+cnt-1] |= word_pad_bbits << fill;
|
||||
}
|
||||
for (unsigned idx = cnt ; idx < newcnt ; idx += 1)
|
||||
newbits[idx] = word_pad_abits;
|
||||
for (unsigned idx = cnt ; idx < newcnt ; idx += 1)
|
||||
newbits[newcnt+idx] = word_pad_bbits;
|
||||
}
|
||||
|
||||
size_ = newsize;
|
||||
abits_ptr_ = newbits;
|
||||
@@ -942,12 +1042,19 @@ void vvp_vector4_t::resize(unsigned newsize)
|
||||
bbits_val_ = newvalb;
|
||||
}
|
||||
|
||||
if (newsize > size_) {
|
||||
abits_val_ &= ~((-1L) << size_);
|
||||
bbits_val_ &= ~((-1L) << size_);
|
||||
abits_val_ |= word_pad_abits << size_;
|
||||
bbits_val_ |= word_pad_bbits << size_;
|
||||
}
|
||||
|
||||
size_ = newsize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned long* vvp_vector4_t::subarray(unsigned adr, unsigned wid) const
|
||||
unsigned long* vvp_vector4_t::subarray(unsigned adr, unsigned wid, bool xz_to_0) const
|
||||
{
|
||||
const unsigned BIT2_PER_WORD = 8*sizeof(unsigned long);
|
||||
unsigned awid = (wid + BIT2_PER_WORD - 1) / (BIT2_PER_WORD);
|
||||
@@ -968,7 +1075,12 @@ unsigned long* vvp_vector4_t::subarray(unsigned adr, unsigned wid) const
|
||||
atmp &= (1UL << wid) - 1;
|
||||
btmp &= (1UL << wid) - 1;
|
||||
}
|
||||
if (btmp) goto x_out;
|
||||
if (btmp) {
|
||||
if (xz_to_0)
|
||||
atmp &= ~btmp;
|
||||
else
|
||||
goto x_out;
|
||||
}
|
||||
|
||||
val[0] = atmp;
|
||||
|
||||
@@ -995,7 +1107,12 @@ unsigned long* vvp_vector4_t::subarray(unsigned adr, unsigned wid) const
|
||||
atmp &= (1UL << trans) - 1;
|
||||
btmp &= (1UL << trans) - 1;
|
||||
}
|
||||
if (btmp) goto x_out;
|
||||
if (btmp) {
|
||||
if (xz_to_0)
|
||||
atmp &= ~btmp;
|
||||
else
|
||||
goto x_out;
|
||||
}
|
||||
|
||||
val[val_ptr] |= atmp << val_off;
|
||||
adr += trans;
|
||||
@@ -1297,6 +1414,132 @@ bool vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that)
|
||||
return diff_flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add that vector to this vector. Do it in the Verilog way, which
|
||||
* means if we detect any X or Z bits, change the entire results to
|
||||
* all X.
|
||||
*
|
||||
* Assume both vectors are the same size.
|
||||
*/
|
||||
void vvp_vector4_t::add(const vvp_vector4_t&that)
|
||||
{
|
||||
assert(size_ == that.size_);
|
||||
|
||||
if (size_ < BITS_PER_WORD) {
|
||||
unsigned long mask = ~(-1UL << size_);
|
||||
if ((bbits_val_|that.bbits_val_) & mask) {
|
||||
abits_val_ |= mask;
|
||||
bbits_val_ |= mask;
|
||||
return;
|
||||
}
|
||||
|
||||
abits_val_ += that.abits_val_;
|
||||
abits_val_ &= mask;
|
||||
return;
|
||||
}
|
||||
|
||||
if (size_ == BITS_PER_WORD) {
|
||||
if (bbits_val_ | that.bbits_val_) {
|
||||
abits_val_ = WORD_X_ABITS;
|
||||
bbits_val_ = WORD_X_BBITS;
|
||||
} else {
|
||||
abits_val_ += that.abits_val_;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int cnt = size_ / BITS_PER_WORD;
|
||||
unsigned long carry = 0;
|
||||
for (int idx = 0 ; idx < cnt ; idx += 1) {
|
||||
if (bbits_ptr_[idx] | that.bbits_ptr_[idx])
|
||||
goto x_out;
|
||||
|
||||
abits_ptr_[idx] = add_with_carry(abits_ptr_[idx], that.abits_ptr_[idx], carry);
|
||||
}
|
||||
|
||||
if (unsigned tail = size_ % BITS_PER_WORD) {
|
||||
unsigned long mask = ~( -1UL << tail );
|
||||
if ((bbits_ptr_[cnt] | that.bbits_ptr_[cnt])&mask)
|
||||
goto x_out;
|
||||
|
||||
abits_ptr_[cnt] = add_with_carry(abits_ptr_[cnt], that.abits_ptr_[cnt], carry);
|
||||
abits_ptr_[cnt] &= mask;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
x_out:
|
||||
for (int idx = 0 ; idx < cnt ; idx += 1) {
|
||||
abits_ptr_[idx] = WORD_X_ABITS;
|
||||
bbits_ptr_[idx] = WORD_X_BBITS;
|
||||
}
|
||||
if (unsigned tail = size_%BITS_PER_WORD) {
|
||||
unsigned long mask = ~( -1UL << tail );
|
||||
abits_ptr_[cnt] = WORD_X_ABITS&mask;
|
||||
bbits_ptr_[cnt] = WORD_X_BBITS&mask;
|
||||
}
|
||||
}
|
||||
|
||||
void vvp_vector4_t::sub(const vvp_vector4_t&that)
|
||||
{
|
||||
assert(size_ == that.size_);
|
||||
|
||||
if (size_ < BITS_PER_WORD) {
|
||||
unsigned long mask = ~(-1UL << size_);
|
||||
if ((bbits_val_|that.bbits_val_) & mask) {
|
||||
abits_val_ |= mask;
|
||||
bbits_val_ |= mask;
|
||||
return;
|
||||
}
|
||||
|
||||
abits_val_ -= that.abits_val_;
|
||||
abits_val_ &= mask;
|
||||
return;
|
||||
}
|
||||
|
||||
if (size_ == BITS_PER_WORD) {
|
||||
if (bbits_val_ | that.bbits_val_) {
|
||||
abits_val_ = WORD_X_ABITS;
|
||||
bbits_val_ = WORD_X_BBITS;
|
||||
} else {
|
||||
abits_val_ -= that.abits_val_;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int cnt = size_ / BITS_PER_WORD;
|
||||
unsigned long carry = 1;
|
||||
for (int idx = 0 ; idx < cnt ; idx += 1) {
|
||||
if (bbits_ptr_[idx] | that.bbits_ptr_[idx])
|
||||
goto x_out;
|
||||
|
||||
abits_ptr_[idx] = add_with_carry(abits_ptr_[idx], ~that.abits_ptr_[idx], carry);
|
||||
}
|
||||
|
||||
if (unsigned tail = size_ % BITS_PER_WORD) {
|
||||
unsigned long mask = ~( -1UL << tail );
|
||||
if ((bbits_ptr_[cnt] | that.bbits_ptr_[cnt])&mask)
|
||||
goto x_out;
|
||||
|
||||
abits_ptr_[cnt] = add_with_carry(abits_ptr_[cnt], ~that.abits_ptr_[cnt], carry);
|
||||
abits_ptr_[cnt] &= mask;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
x_out:
|
||||
for (int idx = 0 ; idx < cnt ; idx += 1) {
|
||||
abits_ptr_[idx] = WORD_X_ABITS;
|
||||
bbits_ptr_[idx] = WORD_X_BBITS;
|
||||
}
|
||||
if (unsigned tail = size_%BITS_PER_WORD) {
|
||||
unsigned long mask = ~( -1UL << tail );
|
||||
abits_ptr_[cnt] = WORD_X_ABITS&mask;
|
||||
bbits_ptr_[cnt] = WORD_X_BBITS&mask;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void vvp_vector4_t::mov(unsigned dst, unsigned src, unsigned cnt)
|
||||
{
|
||||
assert(dst+cnt <= size_);
|
||||
@@ -1370,6 +1613,104 @@ void vvp_vector4_t::mov(unsigned dst, unsigned src, unsigned cnt)
|
||||
}
|
||||
}
|
||||
|
||||
void vvp_vector4_t::mul(const vvp_vector4_t&that)
|
||||
{
|
||||
assert(size_ == that.size_);
|
||||
|
||||
if (size_ < BITS_PER_WORD) {
|
||||
unsigned long mask = ~(-1UL << size_);
|
||||
if ((bbits_val_|that.bbits_val_) & mask) {
|
||||
abits_val_ |= mask;
|
||||
bbits_val_ |= mask;
|
||||
return;
|
||||
}
|
||||
|
||||
abits_val_ *= that.abits_val_;
|
||||
abits_val_ &= mask;
|
||||
return;
|
||||
}
|
||||
|
||||
if (size_ == BITS_PER_WORD) {
|
||||
if (bbits_val_ || that.bbits_val_) {
|
||||
abits_val_ = WORD_X_ABITS;
|
||||
bbits_val_ = WORD_X_BBITS;
|
||||
} else {
|
||||
abits_val_ *= that.abits_val_;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const int cnt = (size_+BITS_PER_WORD-1) / BITS_PER_WORD;
|
||||
|
||||
unsigned long mask;
|
||||
if (unsigned tail = size_%BITS_PER_WORD) {
|
||||
mask = ~( -1UL << tail );
|
||||
} else {
|
||||
mask = ~0UL;
|
||||
}
|
||||
|
||||
// Check for any XZ values ahead of time in a first pass. If
|
||||
// we find any, then force the entire result to be X and be
|
||||
// done.
|
||||
for (int idx = 0 ; idx < cnt ; idx += 1) {
|
||||
unsigned long lval = bbits_ptr_[idx];
|
||||
unsigned long rval = that.bbits_ptr_[idx];
|
||||
if (idx == (cnt-1)) {
|
||||
lval &= mask;
|
||||
rval &= mask;
|
||||
}
|
||||
if (lval || rval) {
|
||||
for (int xdx = 0 ; xdx < cnt-1 ; xdx += 1) {
|
||||
abits_ptr_[xdx] = WORD_X_ABITS;
|
||||
bbits_ptr_[xdx] = WORD_X_BBITS;
|
||||
}
|
||||
abits_ptr_[cnt-1] = WORD_X_ABITS & mask;
|
||||
bbits_ptr_[cnt-1] = WORD_X_BBITS & mask;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the result into a res array. We need to keep is
|
||||
// separate from the "this" array because we are making
|
||||
// multiple passes.
|
||||
unsigned long*res = new unsigned long[cnt];
|
||||
for (int idx = 0 ; idx < cnt ; idx += 1)
|
||||
res[idx] = 0;
|
||||
|
||||
for (int mul_a = 0 ; mul_a < cnt ; mul_a += 1) {
|
||||
unsigned long lval = abits_ptr_[mul_a];
|
||||
if (mul_a == (cnt-1))
|
||||
lval &= mask;
|
||||
|
||||
for (int mul_b = 0 ; mul_b < (cnt-mul_a) ; mul_b += 1) {
|
||||
unsigned long rval = that.abits_ptr_[mul_b];
|
||||
if (mul_b == (cnt-1))
|
||||
rval &= mask;
|
||||
|
||||
unsigned long sum;
|
||||
unsigned long tmp = multiply_with_carry(lval, rval, sum);
|
||||
int base = mul_a + mul_b;
|
||||
unsigned long carry = 0;
|
||||
res[base] = add_with_carry(res[base], tmp, carry);
|
||||
for (int add_idx = base+1 ; add_idx < cnt ; add_idx += 1) {
|
||||
res[add_idx] = add_with_carry(res[add_idx], sum, carry);
|
||||
sum = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the "this" value with the calculated result. We
|
||||
// know a-priori that the bbits are zero and unchanged.
|
||||
res[cnt-1] &= mask;
|
||||
for (int idx = 0 ; idx < cnt ; idx += 1)
|
||||
abits_ptr_[idx] = res[idx];
|
||||
|
||||
delete[]res;
|
||||
return;
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool vvp_vector4_t::eeq(const vvp_vector4_t&that) const
|
||||
{
|
||||
if (size_ != that.size_)
|
||||
@@ -1652,8 +1993,8 @@ ostream& operator<< (ostream&out, const vvp_vector4_t&that)
|
||||
template <class INT>bool vector4_to_value(const vvp_vector4_t&vec, INT&val,
|
||||
bool is_signed, bool is_arithmetic)
|
||||
{
|
||||
long res = 0;
|
||||
INT msk = 1;
|
||||
INT res = 0;
|
||||
INT msk = 1;
|
||||
bool rc_flag = true;
|
||||
|
||||
unsigned size = vec.size();
|
||||
@@ -1672,12 +2013,12 @@ template <class INT>bool vector4_to_value(const vvp_vector4_t&vec, INT&val,
|
||||
rc_flag = false;
|
||||
}
|
||||
|
||||
msk <<= 1L;
|
||||
msk <<= 1;
|
||||
}
|
||||
|
||||
if (is_signed && vec.value(vec.size()-1) == BIT4_1) {
|
||||
if (vec.size() < 8*sizeof(val))
|
||||
res |= (INT)(-1L) << vec.size();
|
||||
res |= (~static_cast<INT>(0)) << vec.size();
|
||||
}
|
||||
|
||||
val = res;
|
||||
@@ -2050,24 +2391,9 @@ void vvp_vector2_t::copy_from_that_(const vvp_vector4_t&that)
|
||||
return;
|
||||
}
|
||||
|
||||
vec_ = new unsigned long[words];
|
||||
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
||||
vec_[idx] = 0;
|
||||
|
||||
for (unsigned idx = 0 ; idx < that.size() ; idx += 1) {
|
||||
unsigned addr = idx / BITS_PER_WORD;
|
||||
unsigned shift = idx % BITS_PER_WORD;
|
||||
|
||||
switch (that.value(idx)) {
|
||||
case BIT4_0:
|
||||
case BIT4_X:
|
||||
case BIT4_Z:
|
||||
break;
|
||||
case BIT4_1:
|
||||
vec_[addr] |= 1UL << shift;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Use the subarray method with the xz_to_0 flag set so that
|
||||
// we get values even when there are xz bits.
|
||||
vec_ = that.subarray(0, wid_, true);
|
||||
}
|
||||
|
||||
void vvp_vector2_t::copy_from_that_(const vvp_vector2_t&that)
|
||||
@@ -3026,7 +3352,7 @@ void vvp_wide_fun_core::propagate_vec4(const vvp_vector4_t&bit,
|
||||
vvp_time64_t delay)
|
||||
{
|
||||
if (delay)
|
||||
schedule_propagate_plucked_vector(ptr_, delay, bit, 0, bit.size());
|
||||
schedule_propagate_vector(ptr_, delay, bit);
|
||||
else
|
||||
ptr_->send_vec4(bit, 0);
|
||||
}
|
||||
|
||||
+59
-16
@@ -130,6 +130,9 @@ struct automatic_hooks_s {
|
||||
* values. The enumeration has fixed numeric values that can be
|
||||
* expressed in 2 real bits, so that some of the internal classes can
|
||||
* pack them tightly.
|
||||
*
|
||||
* WARNING: Many things rely on this encoding for the BIT4_* enumeration
|
||||
* values, so accept that these values are cast in stone.
|
||||
*/
|
||||
enum vvp_bit4_t {
|
||||
BIT4_0 = 0,
|
||||
@@ -206,6 +209,28 @@ inline void update_driver_counts(vvp_bit4_t bit, unsigned counts[3])
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Some of the instructions do wide addition to arrays of long. They
|
||||
* use this add_with_carry function to help.
|
||||
*/
|
||||
static inline unsigned long add_with_carry(unsigned long a, unsigned long b,
|
||||
unsigned long&carry)
|
||||
{
|
||||
unsigned long tmp = b + carry;
|
||||
unsigned long sum = a + tmp;
|
||||
carry = 0;
|
||||
if (tmp < b)
|
||||
carry = 1;
|
||||
if (sum < tmp)
|
||||
carry = 1;
|
||||
if (sum < a)
|
||||
carry = 1;
|
||||
return sum;
|
||||
}
|
||||
|
||||
extern unsigned long multiply_with_carry(unsigned long a, unsigned long b,
|
||||
unsigned long&carry);
|
||||
|
||||
/*
|
||||
* This class represents scalar values collected into vectors. The
|
||||
* vector values can be accessed individually, or treated as a
|
||||
@@ -230,7 +255,11 @@ class vvp_vector4_t {
|
||||
|
||||
explicit vvp_vector4_t(unsigned size, double val);
|
||||
|
||||
// Construct a vector4 from the subvalue of another vector4.
|
||||
// Construct a vector4 from the subvalue of another
|
||||
// vector4. The width of the result is 'wid', and the bits are
|
||||
// pulled from 'that' to implement the Verilog part select
|
||||
// semantics. This means that part select beyond 'that'
|
||||
// returns X bits.
|
||||
explicit vvp_vector4_t(const vvp_vector4_t&that,
|
||||
unsigned adr, unsigned wid);
|
||||
|
||||
@@ -240,8 +269,8 @@ class vvp_vector4_t {
|
||||
|
||||
~vvp_vector4_t();
|
||||
|
||||
unsigned size() const { return size_; }
|
||||
void resize(unsigned new_size);
|
||||
inline unsigned size() const { return size_; }
|
||||
void resize(unsigned new_size, vvp_bit4_t pad_bit = BIT4_X);
|
||||
|
||||
// Get the bit at the specified address
|
||||
vvp_bit4_t value(unsigned idx) const;
|
||||
@@ -250,7 +279,7 @@ class vvp_vector4_t {
|
||||
// Get the 2-value bits for the subvector. This returns a new
|
||||
// array of longs, or a nil pointer if an XZ bit was detected
|
||||
// in the array.
|
||||
unsigned long*subarray(unsigned idx, unsigned size) const;
|
||||
unsigned long*subarray(unsigned idx, unsigned size, bool xz_to_0 =false) const;
|
||||
void setarray(unsigned idx, unsigned size, const unsigned long*val);
|
||||
|
||||
// Set a 4-value bit or subvector into the vector. Return true
|
||||
@@ -264,6 +293,15 @@ class vvp_vector4_t {
|
||||
// Move bits within this vector.
|
||||
void mov(unsigned dst, unsigned src, unsigned cnt);
|
||||
|
||||
// Add that to this in the Verilog way.
|
||||
void add(const vvp_vector4_t&that);
|
||||
|
||||
// Subtract that from this in the Verilog way.
|
||||
void sub(const vvp_vector4_t&that);
|
||||
|
||||
// Multiply this by that in the Verilog way.
|
||||
void mul(const vvp_vector4_t&that);
|
||||
|
||||
// Test that the vectors are exactly equal
|
||||
bool eeq(const vvp_vector4_t&that) const;
|
||||
|
||||
@@ -313,6 +351,7 @@ class vvp_vector4_t {
|
||||
// Initialize and operator= use this private method to copy
|
||||
// the data from that object into this object.
|
||||
void copy_from_(const vvp_vector4_t&that);
|
||||
void copy_from_big_(const vvp_vector4_t&that);
|
||||
void copy_inverted_from_(const vvp_vector4_t&that);
|
||||
|
||||
void allocate_words_(unsigned long inita, unsigned long initb);
|
||||
@@ -392,20 +431,32 @@ inline vvp_vector4_t& vvp_vector4_t::operator= (const vvp_vector4_t&that)
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void vvp_vector4_t::copy_from_(const vvp_vector4_t&that)
|
||||
{
|
||||
size_ = that.size_;
|
||||
if (size_ <= BITS_PER_WORD) {
|
||||
abits_val_ = that.abits_val_;
|
||||
bbits_val_ = that.bbits_val_;
|
||||
} else {
|
||||
copy_from_big_(that);
|
||||
}
|
||||
}
|
||||
|
||||
inline vvp_bit4_t vvp_vector4_t::value(unsigned idx) const
|
||||
{
|
||||
if (idx >= size_)
|
||||
return BIT4_X;
|
||||
|
||||
unsigned wdx = idx / BITS_PER_WORD;
|
||||
unsigned long off = idx % BITS_PER_WORD;
|
||||
unsigned off;
|
||||
|
||||
unsigned long abits, bbits;
|
||||
if (size_ > BITS_PER_WORD) {
|
||||
unsigned wdx = idx / BITS_PER_WORD;
|
||||
off = idx % BITS_PER_WORD;
|
||||
abits = abits_ptr_[wdx];
|
||||
bbits = bbits_ptr_[wdx];
|
||||
} else {
|
||||
off = idx;
|
||||
abits = abits_val_;
|
||||
bbits = bbits_val_;
|
||||
}
|
||||
@@ -413,16 +464,8 @@ inline vvp_bit4_t vvp_vector4_t::value(unsigned idx) const
|
||||
abits >>= off;
|
||||
bbits >>= off;
|
||||
int tmp = ((bbits&1) << 1) + (abits&1);
|
||||
static const vvp_bit4_t bits_bit4_map[4] = {
|
||||
BIT4_0, // bbit==0, abit==0
|
||||
BIT4_1, // bbit==0, abit==1
|
||||
BIT4_Z, // bbit==1, abit==0
|
||||
BIT4_X // bbit==1, abit==1
|
||||
};
|
||||
|
||||
/* Casting is evil, but this cast matches the un-cast done
|
||||
when the vvp_bit4_t value is put into the vector. */
|
||||
return bits_bit4_map[tmp];
|
||||
// This cast works since b==1,a==1 is X and b==1,a==0 is Z.
|
||||
return (vvp_bit4_t)tmp;
|
||||
}
|
||||
|
||||
inline vvp_vector4_t vvp_vector4_t::subvalue(unsigned adr, unsigned wid) const
|
||||
|
||||
Reference in New Issue
Block a user