Browse files

Handle concatenation of SystemVerilog strings.

  • Loading branch information...
1 parent 2bd3d9e commit f77bdf7e3887f314398bbf5787fcf42b78a257e1 @steveicarus committed Jun 24, 2012
Showing with 283 additions and 27 deletions.
  1. +1 −1 design_dump.cc
  2. +2 −2 dup_expr.cc
  3. +25 −4 elab_expr.cc
  4. +2 −2 eval_tree.cc
  5. +5 −5 expr_synth.cc
  6. +9 −4 net_expr.cc
  7. +1 −1 net_nex_input.cc
  8. +5 −3 netlist.h
  9. +1 −1 t-dll-expr.cc
  10. +32 −2 tgt-vvp/draw_vpi.c
  11. +34 −0 tgt-vvp/eval_string.c
  12. +3 −0 vvp/codes.h
  13. +9 −0 vvp/compile.cc
  14. +5 −0 vvp/lexor.lex
  15. +33 −2 vvp/opcodes.txt
  16. +1 −0 vvp/vpi_priv.h
  17. +63 −0 vvp/vpi_vthr_vector.cc
  18. +45 −0 vvp/vthread.cc
  19. +7 −0 vvp/vthread.h
View
2 design_dump.cc
@@ -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
View
4 dup_expr.cc
@@ -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);
View
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. */
View
4 eval_tree.cc
@@ -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;
View
10 expr_synth.cc
@@ -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;
View
13 net_expr.cc
@@ -184,26 +184,31 @@ 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;
}
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() );
View
2 net_nex_input.cc
@@ -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;
View
8 netlist.h
@@ -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_;
};
View
2 t-dll-expr.cc
@@ -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;
View
34 tgt-vvp/draw_vpi.c
@@ -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)
View
34 tgt-vvp/eval_string.c
@@ -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;
View
3 vvp/codes.h
@@ -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);
View
9 vvp/compile.cc
@@ -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);
}
}
View
5 vvp/lexor.lex
@@ -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);
View
35 vvp/opcodes.txt
@@ -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>
View
1 vvp/vpi_priv.h
@@ -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);
View
63 vvp/vpi_vthr_vector.cc
@@ -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;
+}
View
45 vvp/vthread.cc
@@ -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);
View
7 vvp/vthread.h
@@ -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);

0 comments on commit f77bdf7

Please sign in to comment.