Handle strings as class object properties.
While we are at it, fix a handling of null strings in string expressions.
This commit is contained in:
parent
106850ca7d
commit
c49b21115a
|
|
@ -80,3 +80,8 @@ ivl_type_s* real_type_t::elaborate_type(Design*, NetScope*) const
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ivl_type_s* string_type_t::elaborate_type(Design*, NetScope*) const
|
||||
{
|
||||
return &netstring_t::type_string;
|
||||
}
|
||||
|
|
|
|||
10
netscalar.cc
10
netscalar.cc
|
|
@ -23,6 +23,7 @@ using namespace std;
|
|||
|
||||
netreal_t netreal_t::type_real;
|
||||
netreal_t netreal_t::type_shortreal;
|
||||
netstring_t netstring_t::type_string;
|
||||
|
||||
netreal_t::~netreal_t()
|
||||
{
|
||||
|
|
@ -32,3 +33,12 @@ ivl_variable_type_t netreal_t::base_type() const
|
|||
{
|
||||
return IVL_VT_REAL;
|
||||
}
|
||||
|
||||
netstring_t::~netstring_t()
|
||||
{
|
||||
}
|
||||
|
||||
ivl_variable_type_t netstring_t::base_type() const
|
||||
{
|
||||
return IVL_VT_STRING;
|
||||
}
|
||||
|
|
|
|||
12
netscalar.h
12
netscalar.h
|
|
@ -34,4 +34,16 @@ class netreal_t : public ivl_type_s {
|
|||
static netreal_t type_shortreal;
|
||||
};
|
||||
|
||||
class netstring_t : public ivl_type_s {
|
||||
|
||||
public:
|
||||
inline explicit netstring_t() { }
|
||||
~netstring_t();
|
||||
|
||||
ivl_variable_type_t base_type() const;
|
||||
|
||||
public:
|
||||
static netstring_t type_string;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -181,6 +181,8 @@ struct real_type_t : public data_type_t {
|
|||
struct string_type_t : public data_type_t {
|
||||
inline explicit string_type_t() { }
|
||||
~string_type_t();
|
||||
|
||||
ivl_type_s* elaborate_type(Design*des, NetScope*scope) const;
|
||||
};
|
||||
|
||||
struct class_type_t : public data_type_t {
|
||||
|
|
|
|||
|
|
@ -214,6 +214,9 @@ static void show_property_expression(ivl_expr_t net, unsigned ind)
|
|||
if (ivl_expr_value(net) == IVL_VT_REAL) {
|
||||
fprintf(out, "%*s<property base=%s, prop=%s, real>\n", ind, "",
|
||||
ivl_signal_basename(sig), pnam);
|
||||
} else if (ivl_expr_value(net) == IVL_VT_STRING) {
|
||||
fprintf(out, "%*s<property base=%s, prop=%s, string>\n", ind, "",
|
||||
ivl_signal_basename(sig), pnam);
|
||||
} else {
|
||||
fprintf(out, "%*s<property base=%s, prop=%s, width=%u, %s>\n", ind, "",
|
||||
ivl_signal_basename(sig), pnam, ivl_expr_width(net), signed_flag);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2012-2013 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
|
||||
|
|
@ -60,6 +60,15 @@ static void string_ex_concat(ivl_expr_t expr)
|
|||
}
|
||||
}
|
||||
|
||||
static void string_ex_property(ivl_expr_t expr)
|
||||
{
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
unsigned pidx = ivl_expr_property_idx(expr);
|
||||
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
||||
fprintf(vvp_out, " %%prop/str %u;\n", pidx);
|
||||
}
|
||||
|
||||
static void string_ex_signal(ivl_expr_t expr)
|
||||
{
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
|
|
@ -100,6 +109,22 @@ static void string_ex_select(ivl_expr_t expr)
|
|||
fprintf(vvp_out, " %%load/dar/str v%p_0;\n", sig);
|
||||
}
|
||||
|
||||
static void string_ex_string(ivl_expr_t expr)
|
||||
{
|
||||
const char*val = ivl_expr_string(expr);
|
||||
|
||||
/* Special case: The elaborator converts the string "" to an
|
||||
8-bit zero, which is in turn escaped to the 4-character
|
||||
string \000. Detect this special case and convert it back
|
||||
to an empty string. [Perhaps elaboration should be fixed?] */
|
||||
if (ivl_expr_width(expr)==8 && (strcmp(val,"\\000") == 0)) {
|
||||
fprintf(vvp_out, " %%pushi/str \"\";\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%pushi/str \"%s\";\n", val);
|
||||
}
|
||||
|
||||
static void string_ex_substr(ivl_expr_t expr)
|
||||
{
|
||||
ivl_expr_t arg;
|
||||
|
|
@ -129,7 +154,7 @@ void draw_eval_string(ivl_expr_t expr)
|
|||
|
||||
switch (ivl_expr_type(expr)) {
|
||||
case IVL_EX_STRING:
|
||||
fprintf(vvp_out, " %%pushi/str \"%s\";\n", ivl_expr_string(expr));
|
||||
string_ex_string(expr);
|
||||
break;
|
||||
|
||||
case IVL_EX_SIGNAL:
|
||||
|
|
@ -140,6 +165,10 @@ void draw_eval_string(ivl_expr_t expr)
|
|||
string_ex_concat(expr);
|
||||
break;
|
||||
|
||||
case IVL_EX_PROPERTY:
|
||||
string_ex_property(expr);
|
||||
break;
|
||||
|
||||
case IVL_EX_SELECT:
|
||||
string_ex_select(expr);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -869,6 +869,16 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net)
|
|||
fprintf(vvp_out, " %%store/prop/r %d;\n", prop_idx);
|
||||
fprintf(vvp_out, " %%pop/obj 1;\n");
|
||||
|
||||
} else if (ivl_type_base(prop_type) == IVL_VT_STRING) {
|
||||
|
||||
/* Calculate the real value into the real value
|
||||
stack. The %store/prop/r will pop the stack
|
||||
value. */
|
||||
draw_eval_string(rval);
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
||||
fprintf(vvp_out, " %%store/prop/str %d;\n", prop_idx);
|
||||
fprintf(vvp_out, " %%pop/obj 1;\n");
|
||||
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@ class class_property_t {
|
|||
virtual void set_real(char*buf, double val);
|
||||
virtual double get_real(char*buf);
|
||||
|
||||
virtual void set_string(char*buf, const std::string&val);
|
||||
virtual string get_string(char*buf);
|
||||
|
||||
protected:
|
||||
size_t offset_;
|
||||
};
|
||||
|
|
@ -90,6 +93,17 @@ double class_property_t::get_real(char*)
|
|||
return 0.0;
|
||||
}
|
||||
|
||||
void class_property_t::set_string(char*, const string&)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
string class_property_t::get_string(char*)
|
||||
{
|
||||
assert(0);
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
template <class T> class property_atom : public class_property_t {
|
||||
|
|
@ -126,6 +140,26 @@ template <class T> class property_real : public class_property_t {
|
|||
double get_real(char*buf);
|
||||
};
|
||||
|
||||
class property_string : public class_property_t {
|
||||
public:
|
||||
inline explicit property_string(void) { }
|
||||
~property_string() { }
|
||||
|
||||
size_t instance_size() const { return sizeof(std::string); }
|
||||
|
||||
public:
|
||||
void construct(char*buf) const
|
||||
{ /* string*tmp = */ new (buf+offset_) string; }
|
||||
|
||||
void destruct(char*buf) const
|
||||
{ string*tmp = reinterpret_cast<string*> (buf+offset_);
|
||||
tmp->~string();
|
||||
}
|
||||
|
||||
void set_string(char*buf, const string&);
|
||||
string get_string(char*buf);
|
||||
};
|
||||
|
||||
template <class T> void property_atom<T>::set_vec4(char*buf, const vvp_vector4_t&val)
|
||||
{
|
||||
T*tmp = reinterpret_cast<T*> (buf+offset_);
|
||||
|
|
@ -158,6 +192,18 @@ template <class T> double property_real<T>::get_real(char*buf)
|
|||
return *tmp;
|
||||
}
|
||||
|
||||
void property_string::set_string(char*buf, const string&val)
|
||||
{
|
||||
string*tmp = reinterpret_cast<string*>(buf+offset_);
|
||||
*tmp = val;
|
||||
}
|
||||
|
||||
string property_string::get_string(char*buf)
|
||||
{
|
||||
string*tmp = reinterpret_cast<string*>(buf+offset_);
|
||||
return *tmp;
|
||||
}
|
||||
|
||||
/* **** */
|
||||
|
||||
class_type::class_type(const string&nam, size_t nprop)
|
||||
|
|
@ -189,6 +235,8 @@ void class_type::set_property(size_t idx, const string&name, const string&type)
|
|||
properties_[idx].type = new property_atom<int64_t>;
|
||||
else if (type == "r")
|
||||
properties_[idx].type = new property_real<double>;
|
||||
else if (type == "S")
|
||||
properties_[idx].type = new property_string;
|
||||
else
|
||||
properties_[idx].type = 0;
|
||||
}
|
||||
|
|
@ -275,6 +323,21 @@ double class_type::get_real(class_type::inst_t obj, size_t pid) const
|
|||
return properties_[pid].type->get_real(buf);
|
||||
}
|
||||
|
||||
void class_type::set_string(class_type::inst_t obj, size_t pid,
|
||||
const string&val) const
|
||||
{
|
||||
char*buf = reinterpret_cast<char*> (obj);
|
||||
assert(pid < properties_.size());
|
||||
properties_[pid].type->set_string(buf, val);
|
||||
}
|
||||
|
||||
string class_type::get_string(class_type::inst_t obj, size_t pid) const
|
||||
{
|
||||
char*buf = reinterpret_cast<char*> (obj);
|
||||
assert(pid < properties_.size());
|
||||
return properties_[pid].type->get_string(buf);
|
||||
}
|
||||
|
||||
int class_type::get_type_code(void) const
|
||||
{
|
||||
return vpiClassDefn;
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ class class_type : public __vpiHandle {
|
|||
void get_vec4(inst_t inst, size_t pid, vvp_vector4_t&val) const;
|
||||
void set_real(inst_t inst, size_t pid, double val) const;
|
||||
double get_real(inst_t inst, size_t pid) const;
|
||||
void set_string(inst_t inst, size_t pid, const std::string&val) const;
|
||||
std::string get_string(inst_t inst, size_t pid) const;
|
||||
|
||||
public: // VPI related methods
|
||||
int get_type_code(void) const;
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ 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_PROP_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PROP_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PROP_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PUSHI_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PUSHI_REAL(vthread_t thr, vvp_code_t code);
|
||||
|
|
@ -186,6 +187,7 @@ extern bool of_STORE_DAR_R(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_STORE_DAR_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_OBJ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_REAL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_REALA(vthread_t thr, vvp_code_t code);
|
||||
|
|
|
|||
|
|
@ -213,8 +213,9 @@ 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, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%prop/r", of_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%prop/v", of_PROP_V, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%prop/r", of_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%prop/str",of_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%prop/v", of_PROP_V, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%pushi/real",of_PUSHI_REAL,2,{OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%pushi/str", of_PUSHI_STR, 1,{OA_STRING, OA_NONE, OA_NONE} },
|
||||
{ "%pushv/str", of_PUSHV_STR, 2, {OA_BIT1,OA_BIT2, OA_NONE} },
|
||||
|
|
@ -232,8 +233,9 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%store/dar/r", of_STORE_DAR_R, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%store/dar/str",of_STORE_DAR_STR, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%store/obj", of_STORE_OBJ, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%store/prop/r",of_STORE_PROP_R,1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%store/prop/v",of_STORE_PROP_V,3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%store/prop/r", of_STORE_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%store/prop/str",of_STORE_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%store/prop/v", of_STORE_PROP_V, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%store/real", of_STORE_REAL, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%store/reala", of_STORE_REALA, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%store/str", of_STORE_STR, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
|
|
|
|||
|
|
@ -890,9 +890,11 @@ the result.
|
|||
|
||||
* %prop/v <pid>, <base>, <wid>
|
||||
* %prop/r <pid>
|
||||
* %prop/str <pid>
|
||||
|
||||
Write the vector (/v) or real value (/r) into property number <pid> of
|
||||
the class object on the top of the object stack. The real value is popped.
|
||||
Write the vector (/v) or real value (/r) or string (/str) into
|
||||
property number <pid> of the class object on the top of the object
|
||||
stack. The real value is popped.
|
||||
|
||||
The class object stack is NOT popped.
|
||||
|
||||
|
|
@ -1015,6 +1017,7 @@ variable given by the label.
|
|||
See also %load/obj.
|
||||
|
||||
* %store/prop/r <index>
|
||||
* %store/prop/str <index>
|
||||
* %store/prop/v <index>, <bit>, <wid>
|
||||
|
||||
The %store/prop/r pops a real value from the real stack and stores it
|
||||
|
|
|
|||
|
|
@ -4552,6 +4552,25 @@ bool of_PROP_R(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %prop/str <pid>
|
||||
*
|
||||
* Load a string value from the cobject and push it onto the real value
|
||||
* stack.
|
||||
*/
|
||||
bool of_PROP_STR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned pid = cp->number;
|
||||
|
||||
vvp_object_t&obj = thr->peek_object();
|
||||
vvp_cobject*cobj = obj.peek<vvp_cobject>();
|
||||
|
||||
string val = cobj->get_string(pid);
|
||||
thr->push_str(val);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %prop/v <pid> <base> <wid>
|
||||
*
|
||||
|
|
@ -5114,6 +5133,27 @@ bool of_STORE_PROP_R(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %store/prop/str <id>
|
||||
*
|
||||
* Pop a string value from the string stack, and store the value into
|
||||
* the property of the object references by the top of the stack. Do NOT
|
||||
* pop the object stack.
|
||||
*/
|
||||
bool of_STORE_PROP_STR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
size_t pid = cp->number;
|
||||
string val = thr->pop_str();
|
||||
|
||||
vvp_object_t&obj = thr->peek_object();
|
||||
vvp_cobject*cobj = obj.peek<vvp_cobject>();
|
||||
assert(cobj);
|
||||
|
||||
cobj->set_string(pid, val);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %store/prop/v <id> <base> <wid>
|
||||
*
|
||||
|
|
|
|||
|
|
@ -54,3 +54,13 @@ double vvp_cobject::get_real(size_t pid)
|
|||
{
|
||||
return defn_->get_real(properties_, pid);
|
||||
}
|
||||
|
||||
void vvp_cobject::set_string(size_t pid, const string&val)
|
||||
{
|
||||
defn_->set_string(properties_, pid, val);
|
||||
}
|
||||
|
||||
string vvp_cobject::get_string(size_t pid)
|
||||
{
|
||||
return defn_->get_string(properties_, pid);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
# include <string>
|
||||
# include <stdint.h>
|
||||
# include "vvp_object.h"
|
||||
# include "class_type.h"
|
||||
|
|
@ -37,6 +38,9 @@ class vvp_cobject : public vvp_object {
|
|||
void set_real(size_t pid, double val);
|
||||
double get_real(size_t pid);
|
||||
|
||||
void set_string(size_t pid, const std::string&val);
|
||||
std::string get_string(size_t pid);
|
||||
|
||||
private:
|
||||
const class_type* defn_;
|
||||
// For now, only support 32bit bool signed properties.
|
||||
|
|
|
|||
Loading…
Reference in New Issue