From cf1b83b8f015e4a3e0bbbb44548b79656f81bee9 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 23 Jun 2012 08:35:55 -0700 Subject: [PATCH] Implement comparison operators for strings. --- tgt-vvp/eval_expr.c | 120 +++++++++++++++++++++++++++++++++++++++++- tgt-vvp/eval_string.c | 41 +++++++++------ vvp/codes.h | 2 + vvp/compile.cc | 2 + vvp/opcodes.txt | 7 +++ vvp/vthread.cc | 46 +++++++++++++++- 6 files changed, 199 insertions(+), 19 deletions(-) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 3e7b548d0..7f3f12082 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -459,6 +459,39 @@ static struct vector_info draw_binary_expr_eq_real(ivl_expr_t expr) return res; } +static struct vector_info draw_binary_expr_eq_string(ivl_expr_t expr) +{ + ivl_expr_t le = ivl_expr_oper1(expr); + ivl_expr_t re = ivl_expr_oper2(expr); + + struct vector_info res; + res.base = allocate_vector(1); + res.wid = 1; + assert(res.base); + + draw_eval_string(le); + draw_eval_string(re); + + fprintf(vvp_out, " %%cmp/str;\n"); + + switch (ivl_expr_opcode(expr)) { + + case 'e': /* == */ + fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base); + break; + + case 'n': /* != */ + fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base); + fprintf(vvp_out, " %%inv %u, 1;\n", res.base); + break; + + default: + assert(0); + } + + return res; +} + static struct vector_info draw_binary_expr_eq(ivl_expr_t expr, unsigned ewid, int stuff_ok_flag) @@ -476,13 +509,30 @@ static struct vector_info draw_binary_expr_eq(ivl_expr_t expr, return draw_binary_expr_eq_real(expr); } + if ((ivl_expr_value(le) == IVL_VT_STRING) + && (ivl_expr_value(re) == IVL_VT_STRING)) { + return draw_binary_expr_eq_string(expr); + } + + if ((ivl_expr_value(le) == IVL_VT_STRING) + && (ivl_expr_type(re) == IVL_EX_STRING)) { + return draw_binary_expr_eq_string(expr); + } + + if ((ivl_expr_type(le) == IVL_EX_STRING) + && (ivl_expr_value(re) == IVL_VT_STRING)) { + return draw_binary_expr_eq_string(expr); + } + if (number_is_immediate(re,16,0) && !number_is_unknown(re)) return draw_eq_immediate(expr, ewid, le, re, stuff_ok_flag); assert(ivl_expr_value(le) == IVL_VT_LOGIC - || ivl_expr_value(le) == IVL_VT_BOOL); + || ivl_expr_value(le) == IVL_VT_BOOL + || ivl_expr_value(le) == IVL_VT_STRING); assert(ivl_expr_value(re) == IVL_VT_LOGIC - || ivl_expr_value(re) == IVL_VT_BOOL); + || ivl_expr_value(re) == IVL_VT_BOOL + || ivl_expr_value(re) == IVL_VT_STRING); wid = ivl_expr_width(le); if (ivl_expr_width(re) > wid) @@ -825,6 +875,57 @@ static struct vector_info draw_binary_expr_le_real(ivl_expr_t expr) return res; } +static struct vector_info draw_binary_expr_le_string(ivl_expr_t expr) +{ + struct vector_info res; + + ivl_expr_t le = ivl_expr_oper1(expr); + ivl_expr_t re = ivl_expr_oper2(expr); + + res.base = allocate_vector(1); + res.wid = 1; + + assert(res.base); + + /* The %cmp/str function implements < and <= operands. To get + the > and >= results, simply switch the order of the + operands. */ + switch (ivl_expr_opcode(expr)) { + case '<': + case 'L': + draw_eval_string(le); + draw_eval_string(re); + break; + case '>': + case 'G': + draw_eval_string(re); + draw_eval_string(le); + break; + default: + assert(0); + } + + switch (ivl_expr_opcode(expr)) { + case '<': + case '>': + fprintf(vvp_out, " %%cmp/str;\n"); + fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base); + break; + + case 'L': /* <= */ + case 'G': /* >= */ + fprintf(vvp_out, " %%cmp/str;\n"); + fprintf(vvp_out, " %%or 5, 4, 1;\n"); + fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base); + break; + + default: + assert(0); + } + + return res; +} + static struct vector_info draw_binary_expr_le_bool(ivl_expr_t expr, unsigned wid) { @@ -919,6 +1020,21 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr, return draw_binary_expr_le_bool(expr, wid); } + if ((ivl_expr_value(le) == IVL_VT_STRING) + && (ivl_expr_value(re) == IVL_VT_STRING)) { + return draw_binary_expr_le_string(expr); + } + + if ((ivl_expr_value(le) == IVL_VT_STRING) + && (ivl_expr_type(re) == IVL_EX_STRING)) { + return draw_binary_expr_le_string(expr); + } + + if ((ivl_expr_type(le) == IVL_EX_STRING) + && (ivl_expr_value(re) == IVL_VT_STRING)) { + return draw_binary_expr_eq_string(expr); + } + assert(ivl_expr_value(le) == IVL_VT_LOGIC || ivl_expr_value(le) == IVL_VT_BOOL); assert(ivl_expr_value(re) == IVL_VT_LOGIC diff --git a/tgt-vvp/eval_string.c b/tgt-vvp/eval_string.c index 8c208a91e..bdb1a82dc 100644 --- a/tgt-vvp/eval_string.c +++ b/tgt-vvp/eval_string.c @@ -20,32 +20,41 @@ # include "vvp_priv.h" # include +static void fallback_eval(ivl_expr_t expr) +{ + struct vector_info res = draw_eval_expr(expr, 0); + fprintf(vvp_out, " %%pushv/str %u, %u; Cast BOOL/LOGIC to string\n", + res.base, res.wid); + if (res.base > 0) + clr_vector(res); +} + +static void string_ex_signal(ivl_expr_t expr) +{ + ivl_signal_t sig = ivl_expr_signal(expr); + + if (ivl_signal_data_type(sig) == IVL_VT_STRING) { + fprintf(vvp_out, " %%load/str v%p_0;\n", sig); + return; + } + + fallback_eval(expr); +} void draw_eval_string(ivl_expr_t expr) { - struct vector_info res; switch (ivl_expr_type(expr)) { case IVL_EX_STRING: fprintf(vvp_out, " %%pushi/str \"%s\";\n", ivl_expr_string(expr)); break; + case IVL_EX_SIGNAL: + string_ex_signal(expr); + break; + default: - switch (ivl_expr_value(expr)) { - - case IVL_VT_BOOL: - case IVL_VT_LOGIC: - res = draw_eval_expr(expr, 0); - fprintf(vvp_out, " %%pushv/str %u, %u; Cast BOOL/LOGIC to string\n", - res.base, res.wid); - if (res.base > 0) - clr_vector(res); - break; - - default: - assert(0); - break; - } + fallback_eval(expr); break; } } diff --git a/vvp/codes.h b/vvp/codes.h index a7fe23dde..5f44d3366 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -68,6 +68,7 @@ extern bool of_CAST2(vthread_t thr, vvp_code_t code); extern bool of_CMPIS(vthread_t thr, vvp_code_t code); extern bool of_CMPIU(vthread_t thr, vvp_code_t code); extern bool of_CMPS(vthread_t thr, vvp_code_t code); +extern bool of_CMPSTR(vthread_t thr, vvp_code_t code); extern bool of_CMPU(vthread_t thr, vvp_code_t code); extern bool of_CMPWR(vthread_t thr, vvp_code_t code); extern bool of_CMPWS(vthread_t thr, vvp_code_t code); @@ -121,6 +122,7 @@ extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code); extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code); extern bool of_LOAD_AVP0_S(vthread_t thr, vvp_code_t code); extern bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t code); +extern bool of_LOAD_STR(vthread_t thr, vvp_code_t code); extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code); extern bool of_LOAD_VP0(vthread_t thr, vvp_code_t code); extern bool of_LOAD_VP0_S(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index b53e9b61b..13722d388 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -117,6 +117,7 @@ static const struct opcode_table_s opcode_table[] = { { "%cassign/x0",of_CASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%cast2", of_CAST2, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%cmp/s", of_CMPS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, + { "%cmp/str",of_CMPSTR, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%cmp/u", of_CMPU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%cmp/wr", of_CMPWR, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, { "%cmp/ws", of_CMPWS, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, @@ -169,6 +170,7 @@ static const struct opcode_table_s opcode_table[] = { { "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} }, { "%load/avp0/s",of_LOAD_AVP0_S,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} }, { "%load/avx.p",of_LOAD_AVX_P,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} }, + { "%load/str",of_LOAD_STR,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} }, { "%load/v", of_LOAD_VEC,3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} }, { "%load/vp0",of_LOAD_VP0,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} }, { "%load/vp0/s",of_LOAD_VP0_S,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 9103d75c2..9a2791378 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -280,6 +280,13 @@ instruction will also treat x values in either operand as don't care. Only bit 4 is set by these instructions. +* %cmp/str + +This instruction pops the top two strings from the string stack and +compares them. The results of the comparison go into bits 4 and 5: + + 4: eq (equal) + 5: lt (less than) * %cvt/sr , * %cvt/rs , diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 51f8ef47a..32cbe5e36 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1491,6 +1491,36 @@ bool of_CMPS(vthread_t thr, vvp_code_t cp) return true; } +bool of_CMPSTR(vthread_t thr, vvp_code_t) +{ + assert(thr->stack_str.size() >= 2); + string re = thr->stack_str.back(); + thr->stack_str.pop_back(); + string le = thr->stack_str.back(); + thr->stack_str.pop_back(); + + int rc = strcmp(le.c_str(), re.c_str()); + + vvp_bit4_t eq; + vvp_bit4_t lt; + + if (rc == 0) { + eq = BIT4_1; + lt = BIT4_0; + } else if (rc < 0) { + eq = BIT4_0; + lt = BIT4_1; + } else { + eq = BIT4_0; + lt = BIT4_0; + } + + thr_put_bit(thr, 4, eq); + thr_put_bit(thr, 5, lt); + + return true; +} + bool of_CMPIS(vthread_t thr, vvp_code_t cp) { vvp_bit4_t eq = BIT4_1; @@ -3153,6 +3183,20 @@ bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t cp) return true; } +bool of_LOAD_STR(vthread_t thr, vvp_code_t cp) +{ + vvp_net_t*net = cp->net; + + + vvp_fun_signal_string*fun = dynamic_cast (net->fun); + assert(fun); + + const string&val = fun->get_string(); + thr->stack_str.push_back(val); + + return true; +} + /* %load/v ,