Handle concatenation of SystemVerilog strings.
This commit is contained in:
parent
2bd3d9ed5d
commit
f77bdf7e38
|
|
@ -1422,7 +1422,7 @@ void NetEConcat::dump(ostream&o) const
|
|||
else
|
||||
o << "{";
|
||||
|
||||
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
|
||||
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
|
||||
if (parms_[idx])
|
||||
o << ", " << *parms_[idx];
|
||||
else
|
||||
|
|
|
|||
|
|
@ -110,10 +110,10 @@ NetEBShift* NetEBShift::dup_expr() const
|
|||
|
||||
NetEConcat* NetEConcat::dup_expr() const
|
||||
{
|
||||
NetEConcat*dup = new NetEConcat(parms_.count(), repeat_);
|
||||
NetEConcat*dup = new NetEConcat(parms_.size(), repeat_, expr_type_);
|
||||
ivl_assert(*this, dup);
|
||||
dup->set_line(*this);
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
|
||||
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1)
|
||||
if (parms_[idx]) {
|
||||
NetExpr*tmp = parms_[idx]->dup_expr();
|
||||
ivl_assert(*this, tmp);
|
||||
|
|
|
|||
29
elab_expr.cc
29
elab_expr.cc
|
|
@ -1782,15 +1782,36 @@ NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope,
|
|||
unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&)
|
||||
{
|
||||
expr_width_ = 0;
|
||||
enum {NO, MAYBE, YES} expr_is_string = MAYBE;
|
||||
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
|
||||
// Add in the width of this sub-expression.
|
||||
expr_width_ += parms_[idx]->test_width(des, scope, width_modes_[idx]);
|
||||
|
||||
// If we already know this is not a string, then move on.
|
||||
if (expr_is_string == NO)
|
||||
continue;
|
||||
|
||||
// If this expression is a string, then the
|
||||
// concatenation is a string until we find a reason to
|
||||
// deny it.
|
||||
if (parms_[idx]->expr_type()==IVL_VT_STRING) {
|
||||
expr_is_string = YES;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is a string literal, then this may yet be a string.
|
||||
if (dynamic_cast<PEString*> (parms_[idx]))
|
||||
continue;
|
||||
|
||||
// Failed to allow a string result.
|
||||
expr_is_string = NO;
|
||||
}
|
||||
|
||||
expr_type_ = IVL_VT_LOGIC;
|
||||
expr_type_ = (expr_is_string==YES)? IVL_VT_STRING : IVL_VT_LOGIC;
|
||||
signed_flag_ = false;
|
||||
|
||||
/* If there is a repeat expression, then evaluate the constant
|
||||
value and set the repeat count. */
|
||||
// If there is a repeat expression, then evaluate the constant
|
||||
// value and set the repeat count.
|
||||
if (repeat_ && (scope != tested_scope_)) {
|
||||
NetExpr*tmp = elab_and_eval(des, scope, repeat_, -1, true);
|
||||
if (tmp == 0) return 0;
|
||||
|
|
@ -1919,7 +1940,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
/* Make the empty concat expression. */
|
||||
NetEConcat*concat = new NetEConcat(parm_cnt, repeat_count_);
|
||||
NetEConcat*concat = new NetEConcat(parm_cnt, repeat_count_, expr_type_);
|
||||
concat->set_line(*this);
|
||||
|
||||
/* Remove any zero width constants. */
|
||||
|
|
|
|||
|
|
@ -1127,7 +1127,7 @@ NetEConst* NetEConcat::eval_tree()
|
|||
}
|
||||
|
||||
unsigned gap = 0;
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
|
||||
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
|
||||
|
||||
// Parameter not here? This is an error, but presumably
|
||||
// already caught and we are here just to catch more.
|
||||
|
|
@ -1178,7 +1178,7 @@ NetEConst* NetEConcat::eval_tree()
|
|||
|
||||
unsigned cur = 0;
|
||||
bool is_string_flag = true;
|
||||
for (unsigned idx = parms_.count() ; idx > 0 ; idx -= 1) {
|
||||
for (unsigned idx = parms_.size() ; idx > 0 ; idx -= 1) {
|
||||
NetEConst*expr = dynamic_cast<NetEConst*>(parms_[idx-1]);
|
||||
if (expr == 0)
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -702,11 +702,11 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
|||
NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
||||
{
|
||||
/* First, synthesize the operands. */
|
||||
unsigned num_parms = parms_.count();
|
||||
NetNet**tmp = new NetNet*[parms_.count()];
|
||||
unsigned num_parms = parms_.size();
|
||||
NetNet**tmp = new NetNet*[parms_.size()];
|
||||
bool flag = true;
|
||||
ivl_variable_type_t data_type = IVL_VT_NO_TYPE;
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
|
||||
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
|
||||
if (parms_[idx]->expr_width() == 0) {
|
||||
/* We need to synthesize a replication of zero. */
|
||||
tmp[idx] = parms_[idx]->synthesize(des, scope, root);
|
||||
|
|
@ -754,8 +754,8 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
|||
unsigned count_input_width = 0;
|
||||
unsigned cur_pin = 1;
|
||||
for (unsigned rpt = 0; rpt < repeat(); rpt += 1) {
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
|
||||
unsigned concat_item = parms_.count()-idx-1;
|
||||
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
|
||||
unsigned concat_item = parms_.size()-idx-1;
|
||||
if (tmp[concat_item] == 0) continue;
|
||||
connect(concat->pin(cur_pin), tmp[concat_item]->pin(0));
|
||||
cur_pin += 1;
|
||||
|
|
|
|||
13
net_expr.cc
13
net_expr.cc
|
|
@ -184,18 +184,23 @@ bool NetEBShift::has_width() const
|
|||
return left_->has_width();
|
||||
}
|
||||
|
||||
NetEConcat::NetEConcat(unsigned cnt, unsigned r)
|
||||
: parms_(cnt), repeat_(r)
|
||||
NetEConcat::NetEConcat(unsigned cnt, unsigned r, ivl_variable_type_t vt)
|
||||
: parms_(cnt), repeat_(r), expr_type_(vt)
|
||||
{
|
||||
expr_width(0);
|
||||
}
|
||||
|
||||
NetEConcat::~NetEConcat()
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
|
||||
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1)
|
||||
delete parms_[idx];
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetEConcat::expr_type() const
|
||||
{
|
||||
return expr_type_;
|
||||
}
|
||||
|
||||
bool NetEConcat::has_width() const
|
||||
{
|
||||
return true;
|
||||
|
|
@ -203,7 +208,7 @@ bool NetEConcat::has_width() const
|
|||
|
||||
void NetEConcat::set(unsigned idx, NetExpr*e)
|
||||
{
|
||||
assert(idx < parms_.count());
|
||||
assert(idx < parms_.size());
|
||||
assert(parms_[idx] == 0);
|
||||
parms_[idx] = e;
|
||||
expr_width( expr_width() + repeat_ * e->expr_width() );
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ NexusSet* NetEConcat::nex_input(bool rem_out)
|
|||
{
|
||||
if (parms_[0] == NULL) return NULL;
|
||||
NexusSet*result = parms_[0]->nex_input(rem_out);
|
||||
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
|
||||
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
|
||||
if (parms_[idx] == NULL) {
|
||||
delete result;
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -3747,16 +3747,17 @@ class NetEBShift : public NetEBinary {
|
|||
class NetEConcat : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEConcat(unsigned cnt, unsigned repeat =1);
|
||||
NetEConcat(unsigned cnt, unsigned repeat, ivl_variable_type_t vt);
|
||||
~NetEConcat();
|
||||
|
||||
// Manipulate the parameters.
|
||||
void set(unsigned idx, NetExpr*e);
|
||||
|
||||
unsigned repeat() const { return repeat_; }
|
||||
unsigned nparms() const { return parms_.count() ; }
|
||||
unsigned nparms() const { return parms_.size() ; }
|
||||
NetExpr* parm(unsigned idx) const { return parms_[idx]; }
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual bool has_width() const;
|
||||
virtual NetEConcat* dup_expr() const;
|
||||
|
|
@ -3766,8 +3767,9 @@ class NetEConcat : public NetExpr {
|
|||
virtual void dump(ostream&) const;
|
||||
|
||||
private:
|
||||
svector<NetExpr*>parms_;
|
||||
std::vector<NetExpr*>parms_;
|
||||
unsigned repeat_;
|
||||
ivl_variable_type_t expr_type_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ void dll_target::expr_concat(const NetEConcat*net)
|
|||
assert(cur);
|
||||
|
||||
cur->type_ = IVL_EX_CONCAT;
|
||||
cur->value_ = IVL_VT_VECTOR;
|
||||
cur->value_ = net->expr_type();
|
||||
cur->width_ = net->expr_width();
|
||||
cur->signed_ = net->has_sign() ? 1 : 0;
|
||||
cur->sized_ = 1;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ struct args_info {
|
|||
char*text;
|
||||
int vec_flag; /* True if the vec must be released. */
|
||||
struct vector_info vec;
|
||||
/* String Stack position if this argument is a calculated string. */
|
||||
int str_flag;
|
||||
unsigned str_stack;
|
||||
struct args_info *child; /* Arguments can be nested. */
|
||||
};
|
||||
|
||||
|
|
@ -265,6 +268,11 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
|||
|
||||
ivl_parameter_t par;
|
||||
|
||||
/* 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 str_stack_need = 0;
|
||||
|
||||
/* Figure out how many expressions are going to be evaluated
|
||||
for this task call. I won't need to evaluate expressions
|
||||
for items that are VPI objects directly. */
|
||||
|
|
@ -376,7 +384,17 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
|||
"W<%u,r>", args[idx].vec.base);
|
||||
break;
|
||||
case IVL_VT_STRING:
|
||||
/* STRING expressions not supported yet. */
|
||||
/* Eval the string into the stack, and tell VPI
|
||||
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].str_stack = str_stack_need;
|
||||
str_stack_need += 1;
|
||||
buffer[0] = 0;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
|
@ -388,7 +406,16 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
|||
for (idx = 0 ; idx < parm_count ; idx += 1) {
|
||||
struct args_info*ptr;
|
||||
|
||||
fprintf(vvp_out, ", %s", args[idx].text);
|
||||
if (args[idx].str_flag) {
|
||||
/* If this is a string stack reference, then
|
||||
calculate the stack depth and use that to
|
||||
generate the completed string. */
|
||||
unsigned pos = str_stack_need - args[idx].str_stack - 1;
|
||||
fprintf(vvp_out, ", S<%u,str>",pos);
|
||||
} 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) {
|
||||
|
|
@ -409,6 +436,9 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
|||
free(args);
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
|
||||
if (str_stack_need > 0)
|
||||
fprintf(vvp_out, " %%pop/str %u;\n", str_stack_need);
|
||||
}
|
||||
|
||||
void draw_vpi_task_call(ivl_statement_t tnet)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,36 @@ static void fallback_eval(ivl_expr_t expr)
|
|||
clr_vector(res);
|
||||
}
|
||||
|
||||
static void string_ex_concat(ivl_expr_t expr)
|
||||
{
|
||||
unsigned repeat;
|
||||
|
||||
assert(ivl_expr_parms(expr) != 0);
|
||||
assert(ivl_expr_repeat(expr) != 0);
|
||||
|
||||
/* Push the first string onto the stack, no matter what. */
|
||||
draw_eval_string(ivl_expr_parm(expr,0));
|
||||
|
||||
for (repeat = 0 ; repeat < ivl_expr_repeat(expr) ; repeat += 1) {
|
||||
unsigned idx;
|
||||
for (idx = (repeat==0)? 1 : 0 ; idx < ivl_expr_parms(expr) ; idx += 1) {
|
||||
ivl_expr_t sub = ivl_expr_parm(expr,idx);
|
||||
|
||||
/* Special case: If operand is a string literal,
|
||||
then concat it using the %concati/str
|
||||
instruction. */
|
||||
if (ivl_expr_type(sub) == IVL_EX_STRING) {
|
||||
fprintf(vvp_out, " %%concati/str \"%s\";\n",
|
||||
ivl_expr_string(sub));
|
||||
continue;
|
||||
}
|
||||
|
||||
draw_eval_string(sub);
|
||||
fprintf(vvp_out, " %%concat/str;\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void string_ex_signal(ivl_expr_t expr)
|
||||
{
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
|
|
@ -53,6 +83,10 @@ void draw_eval_string(ivl_expr_t expr)
|
|||
string_ex_signal(expr);
|
||||
break;
|
||||
|
||||
case IVL_EX_CONCAT:
|
||||
string_ex_concat(expr);
|
||||
break;
|
||||
|
||||
default:
|
||||
fallback_eval(expr);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ extern bool of_CMPWS(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_CMPWU(vthread_t thr, vvp_code_t code);
|
||||
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_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);
|
||||
|
|
@ -147,6 +149,7 @@ extern bool of_NORR(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_POP_STR(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);
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%cmp/z", of_CMPZ, 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} },
|
||||
{ "%cvt/rs", of_CVT_RS, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%cvt/ru", of_CVT_RU, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%cvt/rv", of_CVT_RV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
|
|
@ -195,6 +197,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%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} },
|
||||
{ "%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, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
|
|
@ -504,6 +507,12 @@ bool vpi_handle_resolv_list_s::resolve(bool mes)
|
|||
|
||||
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 == strlen(label())) {
|
||||
|
||||
val.ptr = vpip_make_vthr_str_stack(base);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -255,6 +255,11 @@ static char* strdupnew(char const *str)
|
|||
assert(yylval.text);
|
||||
return T_SYMBOL; }
|
||||
|
||||
"S<"[0-9]*",str>" {
|
||||
yylval.text = strdup(yytext);
|
||||
assert(yylval.text);
|
||||
return T_SYMBOL; }
|
||||
|
||||
"T<"[0-9]*","[0-9]*","[us]">" {
|
||||
yylval.text = strdup(yytext);
|
||||
assert(yylval.text);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -12,13 +12,26 @@ operands. In no case are there more than 3 operands. This chapter
|
|||
describes the specific behavior of each opcode, in enough detail
|
||||
(I hope) that its complete effect can be predicted.
|
||||
|
||||
General principles of Arithmetic:
|
||||
General Principles of Arithmetic (current plan):
|
||||
|
||||
The binary arithmetic instruction in general takes three parameters,
|
||||
the left operand, the right operand, and the base. The left operand is
|
||||
replaced with the result, which is the same width as the left and
|
||||
right operands.
|
||||
|
||||
General Principles of Arithmetic (new plan):
|
||||
|
||||
For strings, all arithmetic is stack based. That is, there is an
|
||||
abstract stack of strings from which operations pull their operands
|
||||
and push their results. This is somewhat like FORTH (or an HP calculator
|
||||
RPN notation) and spares the need to keep register addresses in
|
||||
operands. I may find this leads to a more compact form of instruction
|
||||
code, and may lead to more efficient operators overall, and in
|
||||
particular I may find improved efficiency overall; so after the
|
||||
experience of implementing it for strings, I'll want to change other
|
||||
types around to using this method as well. Keep this in mind whenever
|
||||
considering adding new instructions to vvp.
|
||||
|
||||
* %abs/wr <bit-o>, <bit-i>
|
||||
|
||||
This instruction calculates the absolute value of a real value. It uses
|
||||
|
|
@ -288,6 +301,18 @@ compares them. The results of the comparison go into bits 4 and 5:
|
|||
4: eq (equal)
|
||||
5: lt (less than)
|
||||
|
||||
For the purposes of calculating the lt bit, the top string is the
|
||||
right operand and the string underneath is the left operand. This
|
||||
instruction removes two strings from the stack.
|
||||
|
||||
* %concat/str
|
||||
* %concati/str <string>
|
||||
|
||||
Pop the top string, and concatenate it to the new top string. Or think
|
||||
of it as possing the tail, then the head, concatenating them, and
|
||||
pushing the result. The stack starts with two strings in the stack,
|
||||
and ends with one string in the stack.
|
||||
|
||||
* %cvt/sr <bit-l>, <bit-r>
|
||||
* %cvt/rs <bit-l>, <bit-r>
|
||||
|
||||
|
|
@ -741,6 +766,12 @@ destination vector in register space. The destination may overlap
|
|||
the source bit. The <dst> may not be 0-3. This is useful for zero
|
||||
or sign extending a vector.
|
||||
|
||||
* %pop/str <num>
|
||||
|
||||
Pop this many items from the string stack. This is the opposite of the
|
||||
%pushX/str opcode which pushes a string to the stack. The %pop/str is
|
||||
not normally needed because the %store/str includes an implicit pop,
|
||||
but sometimes it is necessary to pop explicitly.
|
||||
|
||||
* %pow <bit-l>, <bit-r>, <wid>
|
||||
* %pow/s <bit-l>, <bit-r>, <wid>
|
||||
|
|
|
|||
|
|
@ -610,6 +610,7 @@ vpiHandle vpip_make_real_param(char*name, double value, bool local_flag,
|
|||
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_A(char*label, unsigned index);
|
||||
vpiHandle vpip_make_vthr_A(char*label, char*symbol);
|
||||
|
|
|
|||
|
|
@ -635,3 +635,66 @@ void vpi_handle_delete()
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
class __vpiVThrStrStack : public __vpiHandle {
|
||||
public:
|
||||
__vpiVThrStrStack(unsigned depth);
|
||||
int get_type_code(void) const;
|
||||
int vpi_get(int code);
|
||||
void vpi_get_value(p_vpi_value val);
|
||||
private:
|
||||
const char* name;
|
||||
unsigned depth_;
|
||||
};
|
||||
|
||||
__vpiVThrStrStack::__vpiVThrStrStack(unsigned d)
|
||||
: depth_(d)
|
||||
{
|
||||
}
|
||||
|
||||
int __vpiVThrStrStack::get_type_code(void) const
|
||||
{ return vpiConstant; }
|
||||
|
||||
int __vpiVThrStrStack::vpi_get(int code)
|
||||
{
|
||||
switch (code) {
|
||||
case vpiConstType:
|
||||
return vpiStringConst;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void __vpiVThrStrStack::vpi_get_value(p_vpi_value vp)
|
||||
{
|
||||
string val;
|
||||
char*rbuf = 0;
|
||||
|
||||
if (vpip_current_vthread)
|
||||
val = vthread_get_str_stack(vpip_current_vthread, depth_);
|
||||
|
||||
switch (vp->format) {
|
||||
|
||||
case vpiObjTypeVal:
|
||||
vp->format = vpiStringVal;
|
||||
case vpiStringVal:
|
||||
rbuf = need_result_buf(val.size()+1, RBUF_VAL);
|
||||
strcpy(rbuf, val.c_str());
|
||||
vp->value.str = rbuf;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "vvp error: get %d not supported "
|
||||
"by vpiConstant (String)\n", (int)vp->format);
|
||||
|
||||
vp->format = vpiSuppressVal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
vpiHandle vpip_make_vthr_str_stack(unsigned depth)
|
||||
{
|
||||
struct __vpiVThrStrStack*obj = new __vpiVThrStrStack(depth);
|
||||
return obj;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,6 +189,13 @@ void vthread_put_real(struct vthread_s*thr, unsigned addr, double val)
|
|||
thr->words[addr].w_real = val;
|
||||
}
|
||||
|
||||
string vthread_get_str_stack(struct vthread_s*thr, unsigned depth)
|
||||
{
|
||||
assert(depth < thr->stack_str.size());
|
||||
unsigned use_index = thr->stack_str.size()-1-depth;
|
||||
return thr->stack_str[use_index];
|
||||
}
|
||||
|
||||
template <class T> T coerce_to_width(const T&that, unsigned width)
|
||||
{
|
||||
if (that.size() == width)
|
||||
|
|
@ -1817,6 +1824,29 @@ bool of_CMPZ(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %concat/str;
|
||||
*/
|
||||
bool of_CONCAT_STR(vthread_t thr, vvp_code_t)
|
||||
{
|
||||
assert(thr->stack_str.size() >= 1);
|
||||
string text = thr->stack_str.back();
|
||||
thr->stack_str.pop_back();
|
||||
thr->stack_str.back().append(text);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %concati/str <string>;
|
||||
*/
|
||||
bool of_CONCATI_STR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
const char*text = cp->text;
|
||||
assert(thr->stack_str.size() >= 1);
|
||||
thr->stack_str.back().append(text);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_CVT_RS(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
int64_t r = thr->words[cp->bit_idx[1]].w_int;
|
||||
|
|
@ -4112,6 +4142,21 @@ bool of_NOR(vthread_t thr, vvp_code_t cp)
|
|||
return cp->opcode(thr, cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* %pop/str <number>
|
||||
*/
|
||||
bool of_POP_STR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned cnt = cp->number;
|
||||
assert(cnt <= thr->stack_str.size());
|
||||
|
||||
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
|
||||
thr->stack_str.pop_back();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_POW(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
assert(cp->bit_idx[0] >= 4);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
# include "vvp_net.h"
|
||||
|
||||
# include <string>
|
||||
|
||||
/*
|
||||
* A vthread is a simulation thread that executes instructions when
|
||||
* they are scheduled. This structure contains all the thread specific
|
||||
|
|
@ -117,6 +119,11 @@ extern void vthread_put_bit(struct vthread_s*thr, unsigned addr, vvp_bit4_t bit)
|
|||
extern double vthread_get_real(struct vthread_s*thr, unsigned addr);
|
||||
extern void vthread_put_real(struct vthread_s*thr, unsigned addr, double val);
|
||||
|
||||
/* Get the string from the requested position in the vthread string
|
||||
stack. The top of the stack is depth==0, and items below are
|
||||
depth==1, etc. */
|
||||
extern std::string vthread_get_str_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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue