Compare commits

...
132 Commits
Author SHA1 Message Date
Stephen Williams 105521b547 Merge branch 'master' into vec4-stack 2014-12-06 08:24:46 -08:00
Cary R fd3086f0a9 Fix compile warnings on RHEL5 2014-12-05 19:03:07 -08:00
Cary R 77ebfcacb9 Correctly pass if a darray element is signed or unsigned. 2014-12-05 18:23:02 -08:00
Cary R d62a307c34 Fix 32-bit issue in vector4_to_value() 2014-12-05 18:00:08 -08:00
Stephen Williams 011519cb5b Merge branch 'master' into vec4-stack 2014-12-05 13:55:51 -08:00
Stephen Williams 77d1671d8f Merge branch 'master' into vec4-stack 2014-12-05 10:44:49 -08:00
Stephen Williams 409f8c5823 Add the vec4 %subi instruction 2014-12-05 09:45:29 -08:00
Stephen Williams 03198356a5 vec4-stack stack manipulation improvements. 2014-12-04 17:15:27 -08:00
Stephen Williams b1d2393789 Optimize the %sub instruction by integrating it with vvp_vector4_t class 2014-12-04 17:01:16 -08:00
Stephen Williams 0f740289e9 Optimize %mul instructions by integrating with vvp_vector4_t class. 2014-12-04 16:00:57 -08:00
Stephen Williams 46ce236cfb Optimize the %add and %addi instructions
Tightly integrate with the vvp_vector4_t class to get much
better add performance.
2014-12-04 12:38:08 -08:00
Stephen Williams 86139c855d Optimize the vec4-stack %cmp/s and %cmpi/s instructions.
Magnitude compare is called a LOT, so it is worth putting some
special effort into it.
2014-12-04 10:42:48 -08:00
Stephen Williams eb070b061b Optimize the vec4_to_index, which implements %ix/vec4 instructions. 2014-12-03 17:53:45 -08:00
Stephen Williams 2b1393e7b9 Reduce some vector copies in %load/vec4 and %concat/vec4 instructions.
By clever stack manipulations, we can eliminate some vector copies,
which can improve performance.
2014-12-03 13:12:06 -08:00
Stephen Williams 85c7b07a9b Implement %cmp/ne and %cmpi/ne
These pull in the inversion of the output flags so that they more
efficiently implement != and !==, without %flag_inv instructions.
2014-12-03 11:06:11 -08:00
Stephen Williams 0c5ed2b60f Merge branch 'master' into vec4-stack 2014-12-03 08:36:38 -08:00
Stephen Williams 3bd307db85 Expression cast handles size if need be. 2014-12-02 16:54:32 -08:00
Stephen Williams 35db02d35d elaborate dump cast operators. 2014-12-02 16:50:42 -08:00
Stephen Williams f287546f49 Fix a %vpi_call call syntax. 2014-12-02 15:28:22 -08:00
Stephen Williams 1645e682f4 Generate more efficient vec4-stack code for real le compare. 2014-12-02 14:53:01 -08:00
Stephen Williams a57e0a1e3f vvp implementation of copy from vec4 to vec2 can use subarray method. 2014-12-02 14:52:37 -08:00
Stephen Williams b83144c552 The __vpiArray::set_word method should take a reference.
Seem to have missed a case where a vvp_vector4_t can be passed by
const reference instead of by value.
2014-12-02 13:02:46 -08:00
Stephen Williams 58fb80aec4 Implement and put to use the %muli instruction. 2014-12-02 12:46:17 -08:00
Stephen Williams 38f277d81b Merge branch 'master' into vec4-stack
Conflicts:
	vvp/array.cc
	vvp/vthread.cc
2014-12-02 11:21:58 -08:00
Stephen Williams fb5ae48b18 Merge branch 'master' into vec4-stack 2014-12-01 17:00:35 -08:00
Stephen Williams 82ca4cf641 Add a warning if an expression pads itself to a crazy width. 2014-11-25 14:49:04 -08:00
Stephen Williams 679021a1b5 Optimize special cases of immediate value extraction. 2014-11-22 10:38:16 -08:00
Stephen Williams f3392561ed Optimize the vvp pad implementation. 2014-11-22 09:59:02 -08:00
Stephen Williams 7a9a022744 Remove some dead code. 2014-11-21 17:36:22 -08:00
Stephen Williams c222b3b6a4 Minor improvements to the %split/vec4 instruction. 2014-11-21 16:51:59 -08:00
Stephen Williams 663c79d4af Add the %cmp/e instructions, and put them to use.
When testing for == and ===, there is no need to also calculate <,
so it makes sense to have a special instruction for these cases.
2014-11-21 16:45:27 -08:00
Stephen Williams bea03db25d Minor vec4 stack manipulation optimizations. 2014-11-21 14:41:31 -08:00
Stephen Williams b96f04ccce Implement the %parti/X instructions
This allows part select with constant base to be handled optimally.
Also update some more instructions to more optimally work with
the vec4 stack.
2014-11-20 18:43:24 -08:00
Stephen Williams a9db765f98 Generate better code for condition expressions. 2014-11-20 14:47:44 -08:00
Stephen Williams c71ab5869a vvp code generator try to generate condition flags directly.
When generating code for a condition expression, i.e. directly
before a %jmp/X statement, try to generate the result into the
flag bit without passing through the vec4 stack. For example, the
%cmpX/X instructions generate results into the flag bits, so it
makes no sense to push these bits into the vec4 stack then pop
them back into the flag bit. So try to handle this case.
2014-11-19 18:32:19 -08:00
Stephen Williams 04bdfbccee Add %cmpi/s and %cmpi/u instructions for performance
These bypass the vec4 stack in some common cases, saving instructions
and vec4 manipulations.

Also, minor improvement to the %flag/set/vec4 statement.

Kill a few warnings.
2014-11-19 16:38:43 -08:00
Stephen Williams 2acc9fbdee Remove dead instructsion %set/qb and %set/qf / Kill some warnings. 2014-11-19 09:15:01 -08:00
Stephen Williams 725ed869ba Remove dead %load/vp0 instructions and related infrastructure
Also remove some &A<> and &PV<> symbols that use this now dead
infrastructure.
2014-11-19 09:02:21 -08:00
Stephen Williams 301edf69d3 Add and use %concati/vec4 and %addi instructions.
Also, clean up some warnings, and optimize some existing opcodes.
2014-11-18 12:27:55 -08:00
Stephen Williams 1612c6d638 Instruction %concat/vec4, %pad/u and %shiftl manipulate stack in place 2014-11-17 16:32:18 -08:00
Stephen Williams aadd67cd3b Some instructions can do stack manipultations in place.
By doing some stack manipulations in place, certain instructions
can eliminate, or optimize, vector copies.
2014-11-14 18:38:15 -08:00
Stephen Williams c2ca9c3b73 Optimize draw_number_vec4 to use %pushi/vec4 zero-padding. 2014-11-14 18:37:10 -08:00
Stephen Williams 0601b4e43b Optimizations for %pushi/vec4 and %load/vec4
- Have %pushi/vec4 handle some special cases optimally.
- Eliminate some duplicated method calls in %load/vec4.
- Optimize the vvp_vector4_t::copy_from_ method by inlining
some parts.
2014-11-14 14:41:04 -08:00
Stephen Williams 8aca66b109 Performance tweaks
Better performance for %cmp/s and the vvp_fun_part_sa node.
2014-11-14 11:48:36 -08:00
Stephen Williams 2aeb3871ed Merge branch 'master' into vec4-stack
This was a challenging merge...
Conflicts:
	elab_scope.cc
	synth2.cc
	tgt-vvp/eval_expr.c
	vvp/vthread.cc
2014-11-13 16:26:15 -08:00
Stephen Williams ea21fb856e Mux with default, handle possible large selector. 2014-11-09 16:49:21 -08:00
Stephen Williams d5123011b3 Merge branch 'master' into vec4-stack
Conflicts:
	elab_scope.cc
2014-11-01 14:57:05 -07:00
Stephen Williams 8ac06fb63f Support vpiObjTypeVal for vec4Stack values.
Also allow vpi_get_value outside of scope. (Return 'x)
2014-10-25 20:38:39 -07:00
Stephen Williams 4e727adc25 Merge branch 'master' into vec4-stack 2014-10-25 09:49:39 -07:00
Stephen Williams 702a8c3a05 Merge branch 'master' into vec4-stack 2014-10-24 15:17:31 -07:00
Stephen Williams 48d3972299 Remove a bunch of dead vvp opcodes. 2014-10-24 15:13:28 -07:00
Stephen Williams 62fce50f8c Remove dead code for allocate_vec handling. 2014-10-24 13:07:53 -07:00
Stephen Williams e4b862f3d1 Clean up vector handling dead code. 2014-10-24 11:17:36 -07:00
Stephen Williams 09d3a5de59 Port %pushv/str to vec4-stack style. 2014-10-24 10:16:35 -07:00
Stephen Williams 97bde47c31 Remove dead %set/dar and %set/dar/obj instructions. 2014-10-24 10:03:22 -07:00
Stephen Williams 1c80c6e37a Remove dead stuff_ok_flags from draw_eval_vec4 functions. 2014-10-24 09:32:32 -07:00
Stephen Williams 4588f7c615 vec4 stack versions of queue pop methods. 2014-10-24 09:03:20 -07:00
Stephen Williams 24b8752475 More cases where %store/prop/v takes a width. 2014-10-22 16:15:10 -07:00
Stephen Williams 3ddcf03764 Kill some eval_vec4.c warnings. 2014-10-22 13:01:25 -07:00
Stephen Williams 35f5d51028 Support testing nul for property that is an object. 2014-10-22 12:58:50 -07:00
Stephen Williams 87c019c65c Merge branch 'master' into vec4-stack 2014-10-21 12:19:40 -07:00
Stephen Williams 69a1fecd2e Handle arrays of object is comparison with null. 2014-10-21 11:47:22 -07:00
Stephen Williams 9964d67e5e Implicit crop of vectors assigned to vector properties.
The %store/prop/v takes a width so that it is guaranteed that
all assignments to a vector property will get the size right.
2014-10-21 11:46:59 -07:00
Stephen Williams a98f21aa65 Merge branch 'master' into vec4-stack
Conflicts:
	elab_lval.cc
	netmisc.cc
	tgt-vvp/eval_object.c
	tgt-vvp/vvp_process.c
	vvp/codes.h
	vvp/compile.cc
	vvp/opcodes.txt
	vvp/vpi_tasks.cc
	vvp/vpi_vthr_vector.cc
	vvp/vthread.cc
2014-10-21 09:12:02 -07:00
Stephen Williams 88e4938074 Merge branch 'master' into vec4-stack 2014-03-04 19:08:56 -08:00
Stephen Williams e932c7a637 Support get of vpiIntVal from vec4 stack. 2014-03-04 19:02:21 -08:00
Stephen Williams b5e0099f28 Fix support for enum literals with undefined values. 2014-03-01 17:45:13 -08:00
Stephen Williams 1afe7476e3 Handle nested l-values in vec4-stack code generator. 2014-03-01 16:49:15 -08:00
Stephen Williams 4068570f43 Fix %pow and %pow/s to properly account for 'x operands. 2014-03-01 16:11:47 -08:00
Stephen Williams 7ceb18fb37 Merge branch 'master' into vec4-stack
Conflicts:
	netmisc.cc
	tgt-vvp/eval_expr.c
	vvp/vthread.cc
2014-03-01 09:02:14 -08:00
Stephen Williams d2ff77d56c More standard handling of unsized numbers as system task arguments. 2014-03-01 08:38:23 -08:00
Stephen Williams 91b7c6ab55 Merge branch 'master' into vec4-stack
Conflicts:
	vvp/vthread.cc
2014-02-21 18:04:16 -08:00
Stephen Williams ebed793dec Merge branch 'master' into vec4-stack
Conflicts:
	vvp/vthread.cc

Signed-off-by: Stephen Williams <[email protected]>
2014-02-21 17:34:59 -08:00
Stephen Williams be5bfeb172 Elaborate widths of parameters correctly for unsigned values
If there is no size in the parameter type declaration or on the
value itself, then give the parameter value a minimum width of
integer bits.
2014-02-11 18:24:12 -08:00
Stephen Williams 801e795112 Better job of matching adder operand sizes for vec4 code generator. 2014-02-10 18:06:56 -08:00
Stephen Williams e66fc7e5cc Port UWIRE assignments to vec4 branch. 2014-02-10 17:19:52 -08:00
Stephen Williams 1d63875e5d Merge branch 'master' into vec4-stack
Conflicts:
	elab_lval.cc
2014-02-10 16:26:22 -08:00
Stephen Williams 554fb7ebdd Various internal vec4 size mismatches fixed. 2014-02-07 17:50:13 -08:00
Stephen Williams c9e8392dc7 Fix dangling vec4 stack when force assignment is suppressed.
Also improve the %debug/thr instruction.
2014-02-07 16:10:28 -08:00
Stephen Williams 60d37e1f53 More vec4 support for various things. 2014-02-07 11:24:41 -08:00
Stephen Williams 401fccdf6e vec4 handling of DARRAY of vec4 vectors. 2014-02-06 15:05:26 -08:00
Stephen Williams f5564a195f vec4 versions of compressed assignment statements. 2014-02-06 09:55:25 -08:00
Stephen Williams c7e61f3aa4 Merge branch 'master' into vec4-stack 2014-02-05 15:18:25 -08:00
Stephen Williams 1805598eae Fix some vec4 handling of putc, len, and other string methods. 2014-01-31 19:01:28 -08:00
Stephen Williams 0eca210722 Merge branch 'master' into vec4-stack 2014-01-30 17:07:54 -08:00
Stephen Williams fdc9e8590d Merge branch 'master' into vec4-stack 2014-01-30 15:59:51 -08:00
Stephen Williams e497f63e29 Implement string compares for vec4 support. 2014-01-28 17:11:21 -08:00
Stephen Williams 75233a9bca vec4 implementation of auto-increment/decrement. 2014-01-28 16:24:26 -08:00
Stephen Williams 11197baf86 The vec4 %cvt/vr requires a <wid> 2014-01-28 15:51:29 -08:00
Stephen Williams 23ba0bc019 various vec4 fixes. 2014-01-25 19:25:21 -08:00
Stephen Williams 9cfb15a302 Implement assign/vec4/off/e 2014-01-23 18:39:29 -08:00
Stephen Williams 8bebe59e20 Fix vec4 abs() generating duplicat labels. 2014-01-22 17:15:26 -08:00
Stephen Williams 20d415463a vec4 non-blocking assign to array swapped delay and part offset! 2014-01-21 20:58:48 -08:00
Stephen Williams 9c1dcad994 vec4 vvp support for non-blocking assign with delay and part offset. 2014-01-21 19:37:05 -08:00
Stephen Williams 0e13726e83 fix broken call-out of real-valued system functions. 2014-01-21 13:31:49 -08:00
Stephen Williams 54346d7095 vec4 implementations of real ternary and vec4 to real casts. 2014-01-21 12:02:59 -08:00
Stephen Williams 0121fbc88c Remove useless assert. 2014-01-21 11:05:32 -08:00
Stephen Williams f1855eed0e Fix system function call in net types to get proper vector width.
This means using some of the new vec4 infrastructure to get at the
data, instead of using the old thread bit pointers. In the process,
remove the vbit and vwid members that pointed to thread bits. Those
bits no longer exist.
2014-01-20 19:07:11 -08:00
Stephen Williams 0f9828f179 Fix vec4 overflow of times when they are >32bits. 2014-01-19 14:28:39 -08:00
Stephen Williams d2c2d6d8dc vec4 versions of %cassign/vec4/off and %force/vec4/off send flags[4]. 2014-01-18 17:08:36 -08:00
Stephen Williams f94a655121 Yet again, try to fix vec4 calculation of n-dimensional array index. 2014-01-18 16:04:25 -08:00
Stephen Williams 078a3fd409 Was a little too aggressive with the lossless elab_and_eval
The index expressions ARE self-sized context, we just need to
force the EXPAND flag to make this work.
2014-01-17 18:22:11 -08:00
Stephen Williams dfaed128c0 Fix %store/vec4 overlap of vectors written with extreme indices. 2014-01-15 16:30:34 -08:00
Stephen Williams 1fc4093191 Fix possible overflow in calculation of canonical indices. 2014-01-15 14:26:53 -08:00
Stephen Williams ae1f8be277 Wrap up vpi access to vec4 stack items. 2014-01-14 17:10:03 -08:00
Stephen Williams d8533104b0 Cleanup vec4 handling of suppressed store/assign due to bad offset/index math. 2014-01-14 12:00:39 -08:00
Stephen Williams c6c697bdb7 WRap up vec4 support for system function calls. 2014-01-14 09:22:23 -08:00
Stephen Williams 660d59a7a9 vec4 versions of the %force instructions. 2014-01-13 18:57:03 -08:00
Stephen Williams 92a5e6a698 vec4 based calls to simple real system functions. 2014-01-13 17:46:39 -08:00
Stephen Williams aaa054a932 Fix botched implementations of vec4 based shift. 2014-01-13 17:46:14 -08:00
Stephen Williams 079065ea73 Remove some dead code in tgt-vvp. 2014-01-13 17:45:44 -08:00
Stephen Williams 1905264061 vec4 support for part select of memory word to VPI function. 2014-01-13 16:12:56 -08:00
Stephen Williams b0a9430e98 Wrap up vecc4 support for left/right shift expressions. 2014-01-13 16:11:47 -08:00
Stephen Williams 6a93b6a7e4 Fix some subtle code generator bugs with wide literals and large r-values. 2014-01-07 18:46:35 -08:00
Stephen Williams ec6009dd8f Compile out the T<...> format in vvp.
This ifdef's the code out. Leave it in place for a little longer
for reference.
2014-01-06 20:36:26 -08:00
Stephen Williams 4820d46353 Implement some vpi_get_value formats for vec4 stack values. 2014-01-06 20:27:14 -08:00
Stephen Williams a2845cee70 Update %pow instructions to use vec4 stack. 2014-01-06 10:34:07 -08:00
Stephen Williams c897ca017c Update %div instruction to vec4 version. 2014-01-06 10:14:49 -08:00
Stephen Williams aee540d8bb Fix sort of %event command in vvp compile list.
The sort is important, the names must be sorted because the table is
searched using binary search.
2014-01-06 09:12:42 -08:00
Stephen Williams 19402aeef2 get vpiStringVal from vec4 stack positions. 2014-01-06 08:35:49 -08:00
Stephen Williams fcc0a6a203 vec4 string literal expressions 2014-01-06 08:35:23 -08:00
Stephen Williams e5eb754150 vec4 versions of a bunch of unary operators. 2014-01-05 14:12:27 -08:00
Stephen Williams 063c6d6065 Add the %event instruction, remove %ix/get and %ix/get/s. 2014-01-05 12:39:52 -08:00
Stephen Williams 2fc8ce8a16 Implement vec4 basec %assign delay and event / vpiTimeVal for functions. 2014-01-05 12:04:16 -08:00
Stephen Williams 1a3adbe9cd Vec4 store to memories.
This also reworks the working of the %store/vec4 instruction to
take a part offset, and eliminate the %store/vec4/off instruction.
2014-01-05 10:30:59 -08:00
Stephen Williams 63fa44fa4a vec4 support for ufuncs and ligical AND. 2014-01-05 17:15:30 +00:00
Stephen Williams f89dbd48c8 Add vec4 support for bitwise or/nor/nand/xor/xnor. 2014-01-04 23:48:16 +00:00
Stephen Williams 9fc3e84e93 vec4 cassign to part selects. 2014-01-04 22:58:58 +00:00
Stephen Williams e708a5b59d Handle vec4 part selects / vec4 cassign / repeat statements
These features need to be adapted to the vec4 stack.
2014-01-04 22:11:07 +00:00
Stephen Williams d55e4c0552 Redesign support for system functions that return vec4
Redsign the handling of the return value, including a rework of
the %vpi_func syntax to carry the needed information.

Add a few more arithmetic operator instructions.
2014-01-04 22:06:58 +00:00
Stephen Williams 54926840e6 Handle vec4 stack version of concatenation. 2013-12-28 07:50:37 +02:00
Stephen Williams 5ef077fdf6 Start work on converting vec4 expressions to use stack.
Instead of using a bit4 space to hold thread vectors, create a
vec4 stack--much like the real, string, and object stacks--to
hold intermediate values.
2013-12-27 17:04:42 +02:00
50 changed files with 6407 additions and 8775 deletions
+10
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
}
+3
View File
@@ -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
View File
@@ -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.
+2 -1
View File
@@ -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
View File
@@ -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
+8
View File
@@ -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
+1 -1
View File
@@ -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"
+142 -10
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+293
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+8 -14
View File
@@ -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
View File
@@ -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);
+2 -5
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+217 -430
View File
@@ -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) {
-354
View File
@@ -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;
}
+59
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
-11
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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();
+5
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+13 -17
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -538,7 +538,7 @@ __vpiDecConst::__vpiDecConst(int val)
}
__vpiDecConst::__vpiDecConst(const __vpiDecConst&that)
: value(that.value)
: __vpiHandle(), value(that.value)
{
}
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+4 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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