vvp support for dynamic arrays.
This words completely for single-dimension dynamic arrays of 32bit integers. These changes also act as a stub for other target types.
This commit is contained in:
parent
fdc92ea464
commit
94e217f02b
28
elab_expr.cc
28
elab_expr.cc
|
|
@ -3676,6 +3676,20 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
|||
|
||||
NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1, need_const);
|
||||
|
||||
if (netdarray_t*darray = net->sig()->darray_type()) {
|
||||
// Special case: This is a select of a dynamic
|
||||
// array. Generate a NetESelect and attach it to
|
||||
// the NetESignal. This should be interpreted as
|
||||
// an array word select downstream.
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Bit select of a dynamic array becomes NetESelect." << endl;
|
||||
}
|
||||
NetESelect*res = new NetESelect(net, mux, darray->vector_width());
|
||||
res->set_line(*net);
|
||||
return res;
|
||||
}
|
||||
|
||||
// If the bit select is constant, then treat it similar
|
||||
// to the part select, so that I save the effort of
|
||||
// making a mux part in the netlist.
|
||||
|
|
@ -3754,20 +3768,6 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
|||
return res;
|
||||
}
|
||||
|
||||
if (netdarray_t*darray = net->sig()->darray_type()) {
|
||||
// Special case: This is a select of a dynamic
|
||||
// array. Generate a NetESelect ant attach it to
|
||||
// the NetESignal. This should be interpreted as
|
||||
// an array word select downstream.
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Bit select of a dynamic array becomes NetESelect." << endl;
|
||||
}
|
||||
NetESelect*res = new NetESelect(net, mux, darray->vector_width());
|
||||
res->set_line(*net);
|
||||
return res;
|
||||
}
|
||||
|
||||
long idx = net->sig()->sb_to_idx(prefix_indices,msv);
|
||||
|
||||
if (idx >= (long)net->vector_width() || idx < 0) {
|
||||
|
|
|
|||
|
|
@ -2447,7 +2447,10 @@ long NetESignal::msi() const
|
|||
|
||||
ivl_variable_type_t NetESignal::expr_type() const
|
||||
{
|
||||
return net_->data_type();
|
||||
if (net_->darray_type())
|
||||
return IVL_VT_DARRAY;
|
||||
else
|
||||
return net_->data_type();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -209,6 +209,7 @@ static void show_signal_expression(ivl_expr_t net, unsigned ind)
|
|||
ivl_expr_t word = ivl_expr_oper1(net);
|
||||
|
||||
ivl_signal_t sig = ivl_expr_signal(net);
|
||||
const char*vt_sig = data_type_string(ivl_signal_data_type(sig));
|
||||
unsigned dimensions = ivl_signal_dimensions(sig);
|
||||
unsigned word_count = ivl_signal_array_count(sig);
|
||||
|
||||
|
|
@ -218,8 +219,8 @@ static void show_signal_expression(ivl_expr_t net, unsigned ind)
|
|||
stub_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(out, "%*s<signal=%s, words=%u, width=%u, %s type=%s>\n", ind, "",
|
||||
ivl_expr_name(net), word_count, width, sign, vt);
|
||||
fprintf(out, "%*s<signal=%s, words=%u, width=%u, %s type=%s (%s)>\n", ind, "",
|
||||
ivl_expr_name(net), word_count, width, sign, vt, vt_sig);
|
||||
|
||||
/* If the expression refers to a signal array, then there must
|
||||
also be a word select expression, and if the signal is not an
|
||||
|
|
|
|||
|
|
@ -187,6 +187,12 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
|
|||
if (ivl_expr_value(vexpr) == IVL_VT_STRING)
|
||||
return 0;
|
||||
|
||||
/* If the sub-expression is a DARRAY, then this select
|
||||
is a dynamic-array word select. Handle that
|
||||
elsewhere. */
|
||||
if (ivl_expr_value(vexpr) == IVL_VT_DARRAY)
|
||||
return 0;
|
||||
|
||||
/* The signal is part of an array. */
|
||||
/* Add &APV<> code here when it is finished. */
|
||||
bexpr = ivl_expr_oper2(expr);
|
||||
|
|
|
|||
|
|
@ -2812,6 +2812,19 @@ static struct vector_info draw_select_expr(ivl_expr_t expr, unsigned wid,
|
|||
return res;
|
||||
}
|
||||
|
||||
/* Special case: The sub-expression is a DARRAY variable, so
|
||||
do a dynamic array word load. */
|
||||
if (ivl_expr_value(sube) == IVL_VT_DARRAY) {
|
||||
ivl_signal_t sig = ivl_expr_signal(sube);
|
||||
assert(sig);
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
draw_eval_expr_into_integer(shift, 3);
|
||||
fprintf(vvp_out, " %%load/dar %u, v%p_0, %u;\n",
|
||||
res.base, sig, res.wid);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (ivl_expr_type(sube) == IVL_EX_SIGNAL) {
|
||||
res = draw_select_signal(expr, sube, shift, ivl_expr_width(expr),
|
||||
wid);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ static int eval_darray_new(ivl_expr_t ex)
|
|||
draw_eval_expr_into_integer(size_expr, size_reg);
|
||||
clr_word(size_reg);
|
||||
|
||||
fprintf(vvp_out, " %%new/darray %u;\n", size_reg);
|
||||
// XXXX: Assume elements are 32bit integers.
|
||||
fprintf(vvp_out, " %%new/darray %u, \"sb32\";\n", size_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -773,14 +773,30 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net)
|
|||
ivl_expr_t rval = ivl_stmt_rval(net);
|
||||
ivl_expr_t part = ivl_lval_part_off(lval);
|
||||
ivl_signal_t var= ivl_lval_sig(lval);
|
||||
ivl_expr_t mux = ivl_lval_idx(lval);
|
||||
|
||||
assert(ivl_stmt_lvals(net) == 1);
|
||||
assert(ivl_stmt_opcode(net) == 0);
|
||||
assert(ivl_lval_mux(lval) == 0);
|
||||
assert(part == 0);
|
||||
|
||||
errors += draw_eval_object(rval);
|
||||
fprintf(vvp_out, " %%store/obj v%p_0;\n", var);
|
||||
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
|
||||
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);
|
||||
|
||||
} else {
|
||||
errors += draw_eval_object(rval);
|
||||
fprintf(vvp_out, " %%store/obj v%p_0;\n", var);
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ 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_STR(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);
|
||||
|
|
@ -163,6 +164,7 @@ 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_SET_AR(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_VEC(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_X0(vthread_t thr, vvp_code_t code);
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%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/str",of_LOAD_STR,1,{OA_FUNC_PTR, OA_NONE, 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} },
|
||||
|
|
@ -192,7 +193,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%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} },
|
||||
{ "%new/darray",of_NEW_DARRAY,1,{OA_NUMBER,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} },
|
||||
|
|
@ -211,6 +212,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%set/ar", of_SET_AR, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%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/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/wr", of_SET_WORDR,2,{OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
|
|
|
|||
|
|
@ -597,6 +597,15 @@ bit, and the <index> is the selector for the bit to use. If <index> is
|
|||
out of range, then x is loaded. The index value is incremented by one
|
||||
if it is defined (bit 4 is not 1).
|
||||
|
||||
* %load/dar <bit>, <functor-label>, <wid>
|
||||
|
||||
This instruction loads an array word from a dynamic array. The
|
||||
<label> refers to the variable object, and the <bit>/<wid> are the
|
||||
location in local vector space where the extracted word goes. The
|
||||
index is implicitly extracted from index register 3.
|
||||
|
||||
(See also %set/dar)
|
||||
|
||||
* %load/v <bit>, <functor-label>, <wid>
|
||||
|
||||
This instruction loads a vector value from the given functor node into
|
||||
|
|
@ -721,13 +730,16 @@ means the following:
|
|||
otherwise x
|
||||
|
||||
|
||||
* %new/darray <idx>
|
||||
* %new/darray <idx>, "<type>"
|
||||
|
||||
Create a new array (of int objects) with a size. the <idx> is the
|
||||
address of an index variable that contains the computed array size to
|
||||
use. See also %delete/obj
|
||||
use. The <type> is a string that expresses the type of the elements of
|
||||
the array. See also %delete/obj
|
||||
|
||||
NOTE: For now, assume this is an array of int values.
|
||||
The supported types are:
|
||||
|
||||
"sb32" - signed bool 32bits
|
||||
|
||||
* %nor <dst>, <src>, <wid>
|
||||
|
||||
|
|
@ -832,6 +844,12 @@ Release the force on the real signal that is represented by the functor
|
|||
statement. The <type> is 0 for nets and 1 for registers. See the other
|
||||
%release commands above.
|
||||
|
||||
* %set/dar <var-label>, <bit>, <wid>
|
||||
|
||||
This sets a vector to a word of the dynamic array. Index register 3
|
||||
contains the word address within the dynamic array, and <bit>,<wid>
|
||||
specifies the thread vector to be written.
|
||||
|
||||
* %set/v <var-label>, <bit>, <wid>
|
||||
|
||||
This sets a vector to a variable, and is used to implement blocking
|
||||
|
|
|
|||
|
|
@ -3098,6 +3098,32 @@ bool of_LOAD_AV(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %load/dar <bit>, <array-label>, <index>;
|
||||
*/
|
||||
bool of_LOAD_DAR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned bit = cp->bit_idx[0];
|
||||
unsigned wid = cp->bit_idx[1];
|
||||
unsigned adr = thr->words[3].w_int;
|
||||
vvp_net_t*net = cp->net;
|
||||
|
||||
assert(net);
|
||||
vvp_fun_signal_object*obj = dynamic_cast<vvp_fun_signal_object*> (net->fun);
|
||||
assert(obj);
|
||||
|
||||
vvp_darray*darray = dynamic_cast<vvp_darray*>(obj->get_object());
|
||||
assert(darray);
|
||||
|
||||
vvp_vector4_t word;
|
||||
darray->get_word(adr, word);
|
||||
assert(word.size() == wid);
|
||||
|
||||
thr->bits4.set_vec(bit, word);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %load/vp0, %load/vp0/s, %load/avp0 and %load/avp0/s share this function.
|
||||
*/
|
||||
|
|
@ -3927,9 +3953,15 @@ bool of_NAND(vthread_t thr, vvp_code_t cp)
|
|||
|
||||
bool of_NEW_DARRAY(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
size_t size = thr->words[cp->number].w_int;
|
||||
const char*text = cp->text;
|
||||
size_t size = thr->words[cp->bit_idx[0]].w_int;
|
||||
|
||||
vvp_object_t obj = new vvp_darray (size);
|
||||
vvp_object_t obj;
|
||||
if (strcmp(text,"sb32") == 0) {
|
||||
obj = new vvp_darray_atom<int32_t>(size);
|
||||
} else {
|
||||
obj = new vvp_darray (size);
|
||||
}
|
||||
|
||||
thr->stack_obj.push_back(obj);
|
||||
|
||||
|
|
@ -4457,6 +4489,28 @@ bool of_SET_AV(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %set/dar <label>, <bit>, <wid>
|
||||
*/
|
||||
bool of_SET_DAR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned bit = cp->bit_idx[0];
|
||||
unsigned wid = cp->bit_idx[1];
|
||||
unsigned adr = thr->words[3].w_int;
|
||||
|
||||
/* Make a vector of the desired width. */
|
||||
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
|
||||
|
||||
vvp_net_t*net = cp->net;
|
||||
vvp_fun_signal_object*obj = dynamic_cast<vvp_fun_signal_object*> (net->fun);
|
||||
assert(obj);
|
||||
|
||||
vvp_darray*darray = dynamic_cast<vvp_darray*>(obj->get_object());
|
||||
assert(darray);
|
||||
|
||||
darray->set_word(adr, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This implements the "%set/v <label>, <bit>, <wid>" instruction.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,11 @@
|
|||
*/
|
||||
|
||||
# include "vvp_object.h"
|
||||
# include "vvp_net.h"
|
||||
# include <iostream>
|
||||
# include <typeinfo>
|
||||
|
||||
using namespace std;
|
||||
|
||||
vvp_object::~vvp_object()
|
||||
{
|
||||
|
|
@ -26,3 +31,40 @@ vvp_object::~vvp_object()
|
|||
vvp_darray::~vvp_darray()
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_darray::set_word(unsigned adr, const vvp_vector4_t&)
|
||||
{
|
||||
cerr << "XXXX set_word not implemented for " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
void vvp_darray::get_word(unsigned, vvp_vector4_t&)
|
||||
{
|
||||
cerr << "XXXX get_word not implemented for " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
template <> vvp_darray_atom<int32_t>::~vvp_darray_atom()
|
||||
{
|
||||
}
|
||||
|
||||
template <> void vvp_darray_atom<int32_t>::set_word(unsigned adr, const vvp_vector4_t&value)
|
||||
{
|
||||
if (adr >= array_.size())
|
||||
return;
|
||||
vector4_to_value(value, array_[adr], true, false);
|
||||
}
|
||||
|
||||
template <> void vvp_darray_atom<int32_t>::get_word(unsigned adr, vvp_vector4_t&value)
|
||||
{
|
||||
if (adr >= array_.size()) {
|
||||
value = vvp_vector4_t(32, BIT4_X);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t word = array_[adr];
|
||||
vvp_vector4_t tmp (32, BIT4_0);
|
||||
for (unsigned idx = 0 ; idx < 32 ; idx += 1) {
|
||||
if (word&1) tmp.set_bit(idx, BIT4_1);
|
||||
word >>= 1;
|
||||
}
|
||||
value = tmp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,10 @@
|
|||
*/
|
||||
|
||||
# include <stdlib.h>
|
||||
# include <vector>
|
||||
|
||||
typedef class vvp_object*vvp_object_t;
|
||||
class vvp_vector4_t;
|
||||
|
||||
class vvp_object {
|
||||
public:
|
||||
|
|
@ -33,12 +35,30 @@ class vvp_darray : public vvp_object {
|
|||
|
||||
public:
|
||||
inline vvp_darray(size_t siz) : size_(siz) { }
|
||||
~vvp_darray();
|
||||
virtual ~vvp_darray();
|
||||
|
||||
inline size_t get_size(void) const { return size_; }
|
||||
|
||||
virtual void set_word(unsigned adr, const vvp_vector4_t&value);
|
||||
|
||||
virtual void get_word(unsigned adr, vvp_vector4_t&value);
|
||||
|
||||
private:
|
||||
size_t size_;
|
||||
};
|
||||
|
||||
template <class TYPE> class vvp_darray_atom : public vvp_darray {
|
||||
|
||||
public:
|
||||
inline vvp_darray_atom(size_t siz) : vvp_darray(siz), array_(siz) { }
|
||||
~vvp_darray_atom();
|
||||
|
||||
void set_word(unsigned adr, const vvp_vector4_t&value);
|
||||
|
||||
void get_word(unsigned adr, vvp_vector4_t&value);
|
||||
|
||||
private:
|
||||
std::vector<TYPE> array_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue