First pass at getting strings to work.
In vvp, create the .var/str variable for representing strings, and handle strings in the $display system task. Add to vvp threads the concept of a stack of strings. This is going to be how complex objects are to me handled in the future: forth-like operation stacks. Also add the first two instructions to minimally get strings to work. In the parser, handle the variable declaration and make it available to the ivl_target.h code generator. The vvp code generator can use this information to generate the code for new vvp support.
This commit is contained in:
parent
ea420d94ac
commit
d48362b861
|
|
@ -113,8 +113,8 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
|
|||
net_link.o net_modulo.o \
|
||||
net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \
|
||||
net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \
|
||||
pform_disciplines.o pform_dump.o pform_pclass.o pform_struct_type.o \
|
||||
pform_types.o \
|
||||
pform_disciplines.o pform_dump.o pform_pclass.o pform_string_type.o \
|
||||
pform_struct_type.o pform_types.o \
|
||||
symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \
|
||||
Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PGate.o \
|
||||
PGenerate.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \
|
||||
|
|
|
|||
5
parse.y
5
parse.y
|
|
@ -898,8 +898,9 @@ data_type /* IEEE1800-2005: A.2.2.1 */
|
|||
else $$ = $1;
|
||||
}
|
||||
| K_string
|
||||
{ yyerror(@1, "sorry: String data type not supported.");
|
||||
$$ = 0;
|
||||
{ string_type_t*tmp = new string_type_t;
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
|
|
|
|||
5
pform.cc
5
pform.cc
|
|
@ -2829,6 +2829,11 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list<pe
|
|||
return;
|
||||
}
|
||||
|
||||
if (string_type_t*string_type = dynamic_cast<string_type_t*> (data_type)) {
|
||||
pform_set_string_type(string_type, names, attr);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
2
pform.h
2
pform.h
|
|
@ -310,6 +310,8 @@ extern void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list<
|
|||
|
||||
extern void pform_set_struct_type(struct_type_t*struct_type, std::list<perm_string>*names, std::list<named_pexpr_t>*attr);
|
||||
|
||||
extern void pform_set_string_type(string_type_t*string_type, std::list<perm_string>*names, std::list<named_pexpr_t>*attr);
|
||||
|
||||
/* pform_set_attrib and pform_set_type_attrib exist to support the
|
||||
$attribute syntax, which can only set string values to
|
||||
attributes. The functions keep the value strings that are
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2012 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "pform.h"
|
||||
# include "parse_misc.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
static void pform_set_string_type(string_type_t*string_type, perm_string name, list<named_pexpr_t>*attr)
|
||||
{
|
||||
PWire*net = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_STRING);
|
||||
pform_bind_attributes(net->attributes, attr, true);
|
||||
}
|
||||
|
||||
void pform_set_string_type(string_type_t*string_type, list<perm_string>*names, list<named_pexpr_t>*attr)
|
||||
{
|
||||
for (list<perm_string>::iterator cur = names->begin()
|
||||
; cur != names->end() ; ++ cur) {
|
||||
pform_set_string_type(string_type, *cur, attr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -23,3 +23,7 @@
|
|||
data_type_t::~data_type_t()
|
||||
{
|
||||
}
|
||||
|
||||
string_type_t::~string_type_t()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,6 +156,11 @@ struct real_type_t : public data_type_t {
|
|||
type_t type_code;
|
||||
};
|
||||
|
||||
struct string_type_t : public data_type_t {
|
||||
inline explicit string_type_t() { }
|
||||
~string_type_t();
|
||||
};
|
||||
|
||||
struct class_type_t : public data_type_t {
|
||||
inline explicit class_type_t(perm_string n)
|
||||
: name(n) { }
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ EXTERN_C_START
|
|||
#define vpiIntVar 612
|
||||
#define vpiByteVar 614
|
||||
#define vpiLogicVar vpiReg
|
||||
#define vpiStringVar 616
|
||||
#define vpiBitVar 620
|
||||
|
||||
/********* TYPESPECS *************/
|
||||
|
|
|
|||
|
|
@ -1274,6 +1274,10 @@ static void show_signal(ivl_signal_t net)
|
|||
data_type = "real";
|
||||
break;
|
||||
|
||||
case IVL_VT_STRING:
|
||||
data_type = "string";
|
||||
break;
|
||||
|
||||
default:
|
||||
data_type = "?data?";
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -731,6 +731,34 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int show_stmt_assign_sig_string(ivl_statement_t net)
|
||||
{
|
||||
struct vector_info res;
|
||||
ivl_lval_t lval = ivl_stmt_lval(net, 0);
|
||||
ivl_expr_t rval = ivl_stmt_rval(net);
|
||||
ivl_signal_t var;
|
||||
assert(ivl_stmt_lvals(net) == 1);
|
||||
assert(ivl_stmt_opcode(net) == 0);
|
||||
|
||||
var = ivl_lval_sig(lval);
|
||||
|
||||
switch (ivl_expr_value(rval)) {
|
||||
case IVL_VT_BOOL:
|
||||
case IVL_VT_LOGIC:
|
||||
res = draw_eval_expr(rval, 0);
|
||||
fprintf(vvp_out, " %%pushv/str %u, %u;\n",
|
||||
res.base, res.wid);
|
||||
fprintf(vvp_out, " %%store/str v%p_0;\n", var);
|
||||
if (res.base > 0)
|
||||
clr_vector(res);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int show_stmt_assign(ivl_statement_t net)
|
||||
{
|
||||
|
|
@ -746,5 +774,9 @@ int show_stmt_assign(ivl_statement_t net)
|
|||
return show_stmt_assign_sig_real(net);
|
||||
}
|
||||
|
||||
if (sig && (ivl_signal_data_type(sig) == IVL_VT_STRING)) {
|
||||
return show_stmt_assign_sig_string(net);
|
||||
}
|
||||
|
||||
return show_stmt_assign_vector(net);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -502,6 +502,11 @@ static void draw_reg_in_scope(ivl_signal_t sig)
|
|||
vvp_mangle_name(ivl_signal_basename(sig)),
|
||||
swapped ? first: last, swapped ? last : first, msb, lsb);
|
||||
|
||||
} else if (ivl_signal_data_type(sig) == IVL_VT_STRING) {
|
||||
fprintf(vvp_out, "v%p_0 .var/str \"%s\";%s\n", sig,
|
||||
vvp_mangle_name(ivl_signal_basename(sig)),
|
||||
ivl_signal_local(sig)? " Local signal" : "");
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(vvp_out, "v%p_0 .var%s %s\"%s\", %d %d;%s\n",
|
||||
|
|
|
|||
|
|
@ -964,6 +964,16 @@ static char *get_display(unsigned int *rtnsz, const struct strobe_cb_info *info)
|
|||
memcpy(rtn+size-1, buf, width);
|
||||
break;
|
||||
|
||||
/* Process string variables like string constants: interpret
|
||||
the contained strings like format strings. */
|
||||
case vpiStringVar:
|
||||
value.format = vpiStringVal;
|
||||
vpi_get_value(item, &value);
|
||||
width = strlen(value.value.str);
|
||||
rtn = realloc(rtn, (size+width)*sizeof(char));
|
||||
memcpy(rtn+size-1, value.value.str, width);
|
||||
break;
|
||||
|
||||
case vpiSysFuncCall:
|
||||
func_name = vpi_get_str(vpiName, item);
|
||||
if (strcmp(func_name, "$time") == 0) {
|
||||
|
|
@ -1071,6 +1081,7 @@ static int sys_check_args(vpiHandle callh, vpiHandle argv, const PLI_BYTE8*name,
|
|||
case vpiLongIntVar:
|
||||
case vpiTimeVar:
|
||||
case vpiRealVar:
|
||||
case vpiStringVar:
|
||||
case vpiSysFuncCall:
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ dllib=@DLLIB@
|
|||
MDIR1 = -DMODULE_DIR1='"$(libdir)/ivl$(suffix)"'
|
||||
|
||||
V = vpi_modules.o vpi_callback.o vpi_const.o vpi_event.o vpi_iter.o vpi_mcd.o \
|
||||
vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_tasks.o vpi_time.o \
|
||||
vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_string.o vpi_tasks.o vpi_time.o \
|
||||
vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \
|
||||
vpip_to_dec.o vpip_format.o vvp_vpi.o
|
||||
|
||||
|
|
|
|||
|
|
@ -284,6 +284,7 @@ general syntax of a variable is:
|
|||
<label> .var/2s "name", <msb> <lsb>; Signed bool/bit variable
|
||||
<label> .var/real "name", <msb>, <lsb>; real variable
|
||||
<label> .var/i "name", <msb>, <lsb>; vpiIntegerVar variable
|
||||
<label> .var/str "name"; vpiStringVar variable
|
||||
|
||||
The "name" is the declared base name of the original variable, for the
|
||||
sake of VPI code that might access it. The variable is placed in the
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ extern bool of_PAD(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_PUSHV_STR(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);
|
||||
|
|
@ -160,6 +161,7 @@ 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_STORE_STR(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);
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%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} },
|
||||
{ "%pushv/str", of_PUSHV_STR, 2, {OA_BIT1,OA_BIT2, OA_NONE} },
|
||||
{ "%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} },
|
||||
|
|
@ -205,6 +206,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%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/str",of_STORE_STR,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%sub", of_SUB, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%sub/wr", of_SUB_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%subi", of_SUBI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
|
|
@ -310,6 +312,11 @@ vvp_net_t* vvp_net_lookup(const char*label)
|
|||
return sig->net;
|
||||
}
|
||||
|
||||
case vpiStringVar: {
|
||||
__vpiStringVar*sig = dynamic_cast<__vpiStringVar*>(vpi);
|
||||
return sig->get_net();
|
||||
}
|
||||
|
||||
case vpiNamedEvent: {
|
||||
__vpiNamedEvent*tmp = dynamic_cast<__vpiNamedEvent*>(vpi);
|
||||
return tmp->funct;
|
||||
|
|
|
|||
|
|
@ -455,8 +455,8 @@ extern void compile_variable(char*label, char*name,
|
|||
int msb, int lsb, int vpi_type_code,
|
||||
bool signed_flag, bool local_flag);
|
||||
|
||||
extern void compile_var_real(char*label, char*name,
|
||||
int msb, int lsb);
|
||||
extern void compile_var_real(char*label, char*name);
|
||||
extern void compile_var_string(char*label, char*name);
|
||||
|
||||
/*
|
||||
* This function is used to create a scope port
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@ static char* strdupnew(char const *str)
|
|||
".var" { return K_VAR; }
|
||||
".var/real" { return K_VAR_R; }
|
||||
".var/s" { return K_VAR_S; }
|
||||
".var/str" { return K_VAR_STR; }
|
||||
".var/i" { return K_VAR_I; /* integer */ }
|
||||
".var/2s" { return K_VAR_2S; /* byte/shortint/int/longint signed */ }
|
||||
".var/2u" { return K_VAR_2U; /* byte/shortint/int/longint unsigned */ }
|
||||
|
|
|
|||
|
|
@ -750,6 +750,9 @@ replaces the left operand.
|
|||
This opcode raises <bit-l> (real) to the power of <bit-r> (real). The
|
||||
result replaces the left operand.
|
||||
|
||||
* %pushv/str <src>, <wid>
|
||||
|
||||
Convert a vector to a string and push the string to the string stack.
|
||||
|
||||
* %release/net <functor-label>, <base>, <width>
|
||||
* %release/reg <functor-label>, <base>, <width>
|
||||
|
|
@ -849,6 +852,11 @@ top bits. %shiftr/s/i0 is a signed shift, so the value is sign-extended.
|
|||
|
||||
For a negative shift %shiftr/i0 will pad the value with 'bx.
|
||||
|
||||
* %store/str <var-label>
|
||||
|
||||
This pops the top of the string stack and writes it to the string
|
||||
varible.
|
||||
|
||||
* %sub <bit-l>, <bit-r>, <wid>
|
||||
|
||||
This instruction arithmetically subtracts the right vector out of the
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ static struct __vpiModPath*modpath_dst = 0;
|
|||
%token K_RESOLV K_SCOPE K_SFUNC K_SFUNC_E K_SHIFTL K_SHIFTR K_SHIFTRS
|
||||
%token K_THREAD K_TIMESCALE K_TRAN K_TRANIF0 K_TRANIF1 K_TRANVP
|
||||
%token K_UFUNC K_UFUNC_E K_UDP K_UDP_C K_UDP_S
|
||||
%token K_VAR K_VAR_S K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U
|
||||
%token K_VAR K_VAR_S K_VAR_STR K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U
|
||||
%token K_vpi_call K_vpi_call_w K_vpi_call_i
|
||||
%token K_vpi_func K_vpi_func_r
|
||||
%token K_disable K_fork
|
||||
|
|
@ -697,7 +697,10 @@ statement
|
|||
{ compile_variable($1, $4, $6, $7, vpiIntVar, false, $3); }
|
||||
|
||||
| T_LABEL K_VAR_R T_STRING ',' signed_t_number signed_t_number ';'
|
||||
{ compile_var_real($1, $3, $5, $6); }
|
||||
{ compile_var_real($1, $3); }
|
||||
|
||||
| T_LABEL K_VAR_STR T_STRING ';'
|
||||
{ compile_var_string($1, $3); }
|
||||
|
||||
/* Net statements are similar to .var statements, except that they
|
||||
declare nets, and they have an input list. */
|
||||
|
|
|
|||
|
|
@ -794,6 +794,16 @@ void vvp_wire_real::get_signal_value(struct t_vpi_value*vp)
|
|||
real_signal_value(vp, real_value());
|
||||
}
|
||||
|
||||
void vvp_fun_signal_string_aa::get_signal_value(struct t_vpi_value*vp)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
#if 0
|
||||
void vvp_wire_string::get_signal_value(struct t_vpi_value*vp)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
#endif
|
||||
void vvp_wire_vec4::get_value(struct t_vpi_value*val)
|
||||
{
|
||||
get_signal_value(val);
|
||||
|
|
@ -808,3 +818,9 @@ void vvp_wire_real::get_value(struct t_vpi_value*val)
|
|||
{
|
||||
get_signal_value(val);
|
||||
}
|
||||
#if 0
|
||||
void vvp_wire_string::get_value(struct t_vpi_value*val)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -902,6 +902,11 @@ void vpi_get_value(vpiHandle expr, s_vpi_value*vp)
|
|||
assert(expr);
|
||||
assert(vp);
|
||||
|
||||
// Never bother with suppressed values. All the derived
|
||||
// classes can ignore this type.
|
||||
if (vp->format == vpiSuppressVal)
|
||||
return;
|
||||
|
||||
expr->vpi_get_value(vp);
|
||||
|
||||
if (vpi_trace) switch (vp->format) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
# include "config.h"
|
||||
|
||||
# include <set>
|
||||
# include <string>
|
||||
|
||||
/*
|
||||
* Added to use some "vvp_fun_modpath_src"
|
||||
|
|
@ -477,6 +478,23 @@ struct __vpiRealVar : public __vpiHandle {
|
|||
extern struct __vpiScope* vpip_scope(__vpiRealVar*sig);
|
||||
extern vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net);
|
||||
|
||||
class __vpiStringVar : public __vpiHandle {
|
||||
|
||||
public:
|
||||
__vpiStringVar(__vpiScope*scope, const char*name, vvp_net_t*net);
|
||||
|
||||
int get_type_code(void) const;
|
||||
void vpi_get_value(p_vpi_value val);
|
||||
|
||||
inline vvp_net_t* get_net() const { return net_; }
|
||||
|
||||
private:
|
||||
struct __vpiScope* scope_;
|
||||
const char*name_;
|
||||
vvp_net_t*net_;
|
||||
};
|
||||
|
||||
extern vpiHandle vpip_make_string_var(const char*name, vvp_net_t*net);
|
||||
|
||||
/*
|
||||
* When a loaded VPI module announces a system task/function, one
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2012 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "compile.h"
|
||||
# include "vpi_priv.h"
|
||||
# include "vvp_net_sig.h"
|
||||
# include "schedule.h"
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
# include "vvp_cleanup.h"
|
||||
#endif
|
||||
# include <cstdio>
|
||||
# include <cstdlib>
|
||||
# include <cstring>
|
||||
# include <cassert>
|
||||
# include "ivl_alloc.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
__vpiStringVar::__vpiStringVar(__vpiScope*sc, const char*na, vvp_net_t*ne)
|
||||
: scope_(sc), name_(na), net_(ne)
|
||||
{
|
||||
}
|
||||
|
||||
int __vpiStringVar::get_type_code(void) const
|
||||
{ return vpiStringVar; }
|
||||
|
||||
void __vpiStringVar::vpi_get_value(p_vpi_value val)
|
||||
{
|
||||
vvp_fun_signal_string*fun = dynamic_cast<vvp_fun_signal_string*> (net_->fun);
|
||||
assert(fun);
|
||||
string str = fun->get_string();
|
||||
|
||||
if (val->format == vpiStringVal || val->format == vpiObjTypeVal) {
|
||||
char*rbuf = need_result_buf(str.size()+1, RBUF_VAL);
|
||||
strcpy(rbuf, str.c_str());
|
||||
val->format = vpiStringVal;
|
||||
val->value.str = rbuf;
|
||||
return;
|
||||
}
|
||||
|
||||
val->format = vpiSuppressVal;
|
||||
}
|
||||
|
||||
vpiHandle vpip_make_string_var(const char*name, vvp_net_t*net)
|
||||
{
|
||||
struct __vpiScope*scope = vpip_peek_current_scope();
|
||||
const char*use_name = name ? vpip_name_string(name) : 0;
|
||||
|
||||
struct __vpiStringVar*obj = new __vpiStringVar(scope, use_name, net);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
|
@ -99,6 +99,13 @@ struct vthread_s {
|
|||
double w_real;
|
||||
} words[16];
|
||||
|
||||
/* Strings are operated on using a forth-like operator
|
||||
set. Items at the top of the stack (back()) are the objects
|
||||
operated on except for special cases. New objects are
|
||||
pushed onto the top (back()) and pulled from the top
|
||||
(back()) only. */
|
||||
vector<string> stack_str;
|
||||
|
||||
/* My parent sets this when it wants me to wake it up. */
|
||||
unsigned i_am_joining :1;
|
||||
unsigned i_have_ended :1;
|
||||
|
|
@ -4141,6 +4148,41 @@ bool of_POW_WR(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool of_PUSHV_STR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned src = cp->bit_idx[0];
|
||||
unsigned wid = cp->bit_idx[1];
|
||||
|
||||
vvp_vector4_t vec = vthread_bits_to_vector(thr, src, wid);
|
||||
size_t slen = (vec.size() + 7)/8;
|
||||
vector<char>buf;
|
||||
buf.reserve(slen);
|
||||
|
||||
for (size_t idx = 0 ; idx < vec.size() ; idx += 8) {
|
||||
char tmp = 0;
|
||||
size_t trans = 8;
|
||||
if (idx+trans > vec.size())
|
||||
trans = vec.size() - idx;
|
||||
|
||||
for (size_t bdx = 0 ; bdx < trans ; bdx += 1) {
|
||||
if (vec.value(idx+bdx) == BIT4_1)
|
||||
tmp |= 1 << bdx;
|
||||
}
|
||||
|
||||
if (tmp != 0)
|
||||
buf.push_back(tmp);
|
||||
}
|
||||
|
||||
string val;
|
||||
for (vector<char>::reverse_iterator cur = buf.rbegin()
|
||||
; cur != buf.rend() ; ++cur) {
|
||||
val.push_back(*cur);
|
||||
}
|
||||
|
||||
thr->stack_str.push_back(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* These implement the %release/net and %release/reg instructions. The
|
||||
* %release/net instruction applies to a net kind of functor by
|
||||
|
|
@ -4478,6 +4520,22 @@ bool of_SHIFTR_S_I0(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool of_STORE_STR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
/* set the value into port 0 of the destination. */
|
||||
vvp_net_ptr_t ptr (cp->net, 0);
|
||||
|
||||
assert(!thr->stack_str.empty());
|
||||
|
||||
string val= thr->stack_str.back();
|
||||
thr->stack_str.pop_back();
|
||||
|
||||
vvp_send_string(ptr, val, thr->wt_context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool of_SUB(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
assert(cp->bit_idx[0] >= 4);
|
||||
|
|
|
|||
|
|
@ -1432,7 +1432,7 @@ void vvp_vector4_t::set_to_x()
|
|||
}
|
||||
}
|
||||
|
||||
char* vvp_vector4_t::as_string(char*buf, size_t buf_len)
|
||||
char* vvp_vector4_t::as_string(char*buf, size_t buf_len) const
|
||||
{
|
||||
char*res = buf;
|
||||
*buf++ = 'C';
|
||||
|
|
@ -2956,6 +2956,13 @@ void vvp_net_fun_t::recv_long_pv(vvp_net_ptr_t, long, unsigned, unsigned)
|
|||
assert(0);
|
||||
}
|
||||
|
||||
void vvp_net_fun_t::recv_string(vvp_net_ptr_t, const std::string&bit, vvp_context_t)
|
||||
{
|
||||
fprintf(stderr, "internal error: %s: recv_string(%s) not implemented\n",
|
||||
typeid(*this).name(), bit.c_str());
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void vvp_net_fun_t::force_flag(void)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ class vvp_vector4_t {
|
|||
void set_to_x();
|
||||
|
||||
// Display the value into the buf as a string.
|
||||
char*as_string(char*buf, size_t buf_len);
|
||||
char*as_string(char*buf, size_t buf_len) const;
|
||||
|
||||
void invert();
|
||||
vvp_vector4_t& operator &= (const vvp_vector4_t&that);
|
||||
|
|
@ -1082,6 +1082,7 @@ class vvp_net_t {
|
|||
void send_vec8(const vvp_vector8_t&val);
|
||||
void send_real(double val, vvp_context_t context);
|
||||
void send_long(long val);
|
||||
void send_string(const std::string&val, vvp_context_t context);
|
||||
|
||||
void send_vec4_pv(const vvp_vector4_t&val,
|
||||
unsigned base, unsigned wid, unsigned vwid,
|
||||
|
|
@ -1156,6 +1157,8 @@ class vvp_net_fun_t {
|
|||
virtual void recv_real(vvp_net_ptr_t port, double bit,
|
||||
vvp_context_t context);
|
||||
virtual void recv_long(vvp_net_ptr_t port, long bit);
|
||||
virtual void recv_string(vvp_net_ptr_t port, const std::string&bit,
|
||||
vvp_context_t context);
|
||||
|
||||
// Part select variants of above
|
||||
virtual void recv_vec4_pv(vvp_net_ptr_t p, const vvp_vector4_t&bit,
|
||||
|
|
@ -1514,6 +1517,18 @@ extern void vvp_send_long(vvp_net_ptr_t ptr, long val);
|
|||
extern void vvp_send_long_pv(vvp_net_ptr_t ptr, long val,
|
||||
unsigned base, unsigned width);
|
||||
|
||||
inline void vvp_send_string(vvp_net_ptr_t ptr, const std::string&val, vvp_context_t context)
|
||||
{
|
||||
while (vvp_net_t*cur = ptr.ptr()) {
|
||||
vvp_net_ptr_t next = cur->port[ptr.port()];
|
||||
|
||||
if (cur->fun)
|
||||
cur->fun->recv_string(ptr, val, context);
|
||||
|
||||
ptr = next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Part-vector versions of above functions. This function uses the
|
||||
* corresponding recv_vec4_pv method in the vvp_net_fun_t functor to
|
||||
|
|
@ -1654,6 +1669,13 @@ inline void vvp_net_t::send_real(double val, vvp_context_t context)
|
|||
}
|
||||
|
||||
|
||||
inline void vvp_net_t::send_string(const std::string&val, vvp_context_t context)
|
||||
{
|
||||
assert(!fil);
|
||||
vvp_send_string(out_, val, context);
|
||||
}
|
||||
|
||||
|
||||
inline bool vvp_net_fil_t::test_force_mask(unsigned bit) const
|
||||
{
|
||||
if (bit >= force_mask_.size())
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
# include "vvp_net_sig.h"
|
||||
# include "statistics.h"
|
||||
# include "vpi_priv.h"
|
||||
# include <vector>
|
||||
# include <cassert>
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
# include <valgrind/memcheck.h>
|
||||
|
|
@ -30,6 +31,8 @@
|
|||
|
||||
# include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* The filter_mask_ method takes as an input the value to propagate,
|
||||
* the mask of what is being forced, and returns a propagation
|
||||
|
|
@ -585,6 +588,83 @@ void vvp_fun_signal_real_aa::operator delete(void*)
|
|||
assert(0);
|
||||
}
|
||||
|
||||
|
||||
vvp_fun_signal_string_sa::vvp_fun_signal_string_sa()
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_fun_signal_string_sa::recv_string(vvp_net_ptr_t ptr, const std::string&bit,
|
||||
vvp_context_t)
|
||||
{
|
||||
assert(ptr.port() == 0);
|
||||
|
||||
if (needs_init_ || value_ != bit) {
|
||||
value_ = bit;
|
||||
needs_init_ = false;
|
||||
|
||||
ptr.ptr()->send_string(bit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
vvp_fun_signal_string_aa::vvp_fun_signal_string_aa()
|
||||
{
|
||||
context_idx_ = vpip_add_item_to_context(this, vpip_peek_context_scope());
|
||||
}
|
||||
|
||||
vvp_fun_signal_string_aa::~vvp_fun_signal_string_aa()
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void vvp_fun_signal_string_aa::alloc_instance(vvp_context_t)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void vvp_fun_signal_string_aa::reset_instance(vvp_context_t)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
unsigned vvp_fun_signal_string_aa::value_size() const
|
||||
{
|
||||
assert(0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
vvp_bit4_t vvp_fun_signal_string_aa::value(unsigned) const
|
||||
{
|
||||
assert(0);
|
||||
return BIT4_X;
|
||||
}
|
||||
|
||||
vvp_scalar_t vvp_fun_signal_string_aa::scalar_value(unsigned) const
|
||||
{
|
||||
assert(0);
|
||||
return vvp_scalar_t();
|
||||
}
|
||||
|
||||
void vvp_fun_signal_string_aa::vec4_value(vvp_vector4_t&) const
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
double vvp_fun_signal_string_aa::real_value() const
|
||||
{
|
||||
assert(0);
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void* vvp_fun_signal_string_aa::operator new(std::size_t size)
|
||||
{
|
||||
return vvp_net_fun_t::heap_.alloc(size);
|
||||
}
|
||||
|
||||
void vvp_fun_signal_string_aa::operator delete(void*)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
vvp_fun_force::vvp_fun_force()
|
||||
{
|
||||
}
|
||||
|
|
@ -1058,3 +1138,67 @@ double vvp_wire_real::real_value() const
|
|||
else
|
||||
return bit_;
|
||||
}
|
||||
|
||||
#if 0
|
||||
vvp_wire_string::vvp_wire_string()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned vvp_wire_string::filter_size() const
|
||||
{
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vvp_wire_string::force_fil_vec4(const vvp_vector4_t&, vvp_vector2_t)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
void vvp_wire_string::force_fil_vec8(const vvp_vector8_t&, vvp_vector2_t)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
void vvp_wire_string::force_fil_real(double, vvp_vector2_t)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void vvp_wire_string::release(vvp_net_ptr_t ptr, bool net_flag)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void vvp_wire_string::release_pv(vvp_net_ptr_t, unsigned, unsigned, bool)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
unsigned vvp_wire_string::value_size() const
|
||||
{
|
||||
assert(0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
vvp_bit4_t vvp_wire_string::value(unsigned) const
|
||||
{
|
||||
assert(0);
|
||||
return BIT4_X;
|
||||
}
|
||||
|
||||
vvp_scalar_t vvp_wire_string::scalar_value(unsigned) const
|
||||
{
|
||||
assert(0);
|
||||
return vvp_scalar_t();
|
||||
}
|
||||
|
||||
void vvp_wire_string::vec4_value(vvp_vector4_t&) const
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
double vvp_wire_string::real_value() const
|
||||
{
|
||||
assert(0);
|
||||
return 0.0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
# include "config.h"
|
||||
# include "vpi_user.h"
|
||||
# include "vvp_net.h"
|
||||
# include <string>
|
||||
# include <cstddef>
|
||||
# include <cstdlib>
|
||||
# include <cstring>
|
||||
|
|
@ -261,6 +262,63 @@ class vvp_fun_signal_real_aa : public vvp_fun_signal_real, public automatic_sign
|
|||
};
|
||||
|
||||
|
||||
class vvp_fun_signal_string : public vvp_fun_signal_base {
|
||||
|
||||
public:
|
||||
explicit vvp_fun_signal_string() {};
|
||||
|
||||
unsigned size() const { return 1; }
|
||||
|
||||
inline const std::string& get_string() const { return value_; }
|
||||
|
||||
protected:
|
||||
std::string value_;
|
||||
};
|
||||
|
||||
/*
|
||||
* Statically allocated vvp_fun_signal_string.
|
||||
*/
|
||||
class vvp_fun_signal_string_sa : public vvp_fun_signal_string {
|
||||
|
||||
public:
|
||||
explicit vvp_fun_signal_string_sa();
|
||||
|
||||
void recv_string(vvp_net_ptr_t port, const std::string&bit,
|
||||
vvp_context_t context);
|
||||
};
|
||||
|
||||
/*
|
||||
* Automatically allocated vvp_fun_signal_real.
|
||||
*/
|
||||
class vvp_fun_signal_string_aa : public vvp_fun_signal_string, public automatic_signal_base, public automatic_hooks_s {
|
||||
|
||||
public:
|
||||
explicit vvp_fun_signal_string_aa();
|
||||
~vvp_fun_signal_string_aa();
|
||||
|
||||
void alloc_instance(vvp_context_t context);
|
||||
void reset_instance(vvp_context_t context);
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
void free_instance(vvp_context_t context);
|
||||
#endif
|
||||
|
||||
// Get information about the vector value.
|
||||
unsigned value_size() const;
|
||||
vvp_bit4_t value(unsigned idx) const;
|
||||
vvp_scalar_t scalar_value(unsigned idx) const;
|
||||
void vec4_value(vvp_vector4_t&) const;
|
||||
double real_value() const;
|
||||
void get_signal_value(struct t_vpi_value*vp);
|
||||
|
||||
public: // These objects are only permallocated.
|
||||
static void* operator new(std::size_t size);
|
||||
static void operator delete(void*obj);
|
||||
|
||||
private:
|
||||
unsigned context_idx_;
|
||||
};
|
||||
|
||||
|
||||
/* vvp_wire
|
||||
* The vvp_wire is different from vvp_variable objects in that it
|
||||
* exists only as a filter. The vvp_wire class tree is for
|
||||
|
|
@ -388,4 +446,34 @@ class vvp_wire_real : public vvp_wire_base {
|
|||
double force_;
|
||||
};
|
||||
|
||||
#if 0
|
||||
class vvp_wire_string : public vvp_wire_base {
|
||||
|
||||
public:
|
||||
explicit vvp_wire_string(void);
|
||||
|
||||
// Abstract methods from vvp_vpi_callback
|
||||
void get_value(struct t_vpi_value*value);
|
||||
// Abstract methods from vvp_net_fil_t
|
||||
unsigned filter_size() const;
|
||||
void force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask);
|
||||
void force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask);
|
||||
void force_fil_real(double val, vvp_vector2_t mask);
|
||||
void release(vvp_net_ptr_t ptr, bool net_flag);
|
||||
void release_pv(vvp_net_ptr_t ptr, unsigned base, unsigned wid, bool net_flag);
|
||||
|
||||
// Implementation of vvp_signal_value methods
|
||||
unsigned value_size() const;
|
||||
vvp_bit4_t value(unsigned idx) const;
|
||||
vvp_scalar_t scalar_value(unsigned idx) const;
|
||||
void vec4_value(vvp_vector4_t&) const;
|
||||
double real_value() const;
|
||||
|
||||
void get_signal_value(struct t_vpi_value*vp);
|
||||
|
||||
private:
|
||||
std::string value_;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
39
vvp/words.cc
39
vvp/words.cc
|
|
@ -65,9 +65,8 @@ static void __compile_var_real(char*label, char*name,
|
|||
delete[] name;
|
||||
}
|
||||
|
||||
void compile_var_real(char*label, char*name, int msb, int lsb)
|
||||
void compile_var_real(char*label, char*name)
|
||||
{
|
||||
assert(msb == 0 && lsb == 0);
|
||||
__compile_var_real(label, name, 0, 0);
|
||||
}
|
||||
|
||||
|
|
@ -79,6 +78,42 @@ void compile_varw_real(char*label, vvp_array_t array,
|
|||
__compile_var_real(label, 0, array, addr);
|
||||
}
|
||||
|
||||
static void __compile_var_string(char*label, char*name,
|
||||
vvp_array_t array, unsigned long array_addr)
|
||||
{
|
||||
vvp_net_t*net = new vvp_net_t;
|
||||
|
||||
if (vpip_peek_current_scope()->is_automatic) {
|
||||
vvp_fun_signal_string_aa*tmp = new vvp_fun_signal_string_aa;
|
||||
net->fil = tmp;
|
||||
net->fun = tmp;
|
||||
} else {
|
||||
net->fil = 0;
|
||||
net->fun = new vvp_fun_signal_string_sa;
|
||||
}
|
||||
|
||||
define_functor_symbol(label, net);
|
||||
|
||||
vpiHandle obj = vpip_make_string_var(name, net);
|
||||
compile_vpi_symbol(label, obj);
|
||||
|
||||
if (name) {
|
||||
assert(!array);
|
||||
vpip_attach_to_current_scope(obj);
|
||||
}
|
||||
if (array) {
|
||||
assert(!name);
|
||||
array_attach_word(array, array_addr, obj);
|
||||
}
|
||||
delete[]label;
|
||||
delete[] name;
|
||||
}
|
||||
|
||||
void compile_var_string(char*label, char*name)
|
||||
{
|
||||
__compile_var_string(label, name, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* A variable is a special functor, so we allocate that functor and
|
||||
* write the label into the symbol table.
|
||||
|
|
|
|||
Loading…
Reference in New Issue