Add support for real valued compressed assignment statements in tgt-vvp.

This commit is contained in:
Martin Whitaker 2016-02-23 20:58:30 +00:00
parent a7066e3686
commit 3fede95f5e
1 changed files with 188 additions and 33 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011-2015 Stephen Williams (steve@icarus.com) * Copyright (c) 2011-2016 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -37,20 +37,20 @@
enum slice_type_e { enum slice_type_e {
SLICE_NO_TYPE = 0, SLICE_NO_TYPE = 0,
SLICE_SIMPLE_VECTOR, SLICE_SIMPLE_WORD,
SLICE_PART_SELECT_STATIC, SLICE_PART_SELECT_STATIC,
SLICE_PART_SELECT_DYNAMIC, SLICE_PART_SELECT_DYNAMIC,
SLICE_MEMORY_WORD_STATIC, SLICE_MEMORY_WORD_STATIC,
SLICE_MEMORY_WORD_DYNAMIC SLICE_MEMORY_WORD_DYNAMIC
}; };
struct vec_slice_info { struct slice_info {
enum slice_type_e type; enum slice_type_e type;
union { union {
struct { struct {
unsigned long use_word; unsigned long use_word;
} simple_vector; } simple_word;
struct { struct {
unsigned long part_off; unsigned long part_off;
@ -76,7 +76,7 @@ struct vec_slice_info {
} u_; } u_;
}; };
static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice, static void get_vec_from_lval_slice(ivl_lval_t lval, struct slice_info*slice,
unsigned wid) unsigned wid)
{ {
ivl_signal_t sig = ivl_lval_sig(lval); ivl_signal_t sig = ivl_lval_sig(lval);
@ -109,8 +109,8 @@ static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice
if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0 if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0
&& part_off==0 && wid==ivl_signal_width(sig)) { && part_off==0 && wid==ivl_signal_width(sig)) {
slice->type = SLICE_SIMPLE_VECTOR; slice->type = SLICE_SIMPLE_WORD;
slice->u_.simple_vector.use_word = use_word; slice->u_.simple_word.use_word = use_word;
if (signal_is_return_value(sig)) { if (signal_is_return_value(sig)) {
assert(use_word==0); assert(use_word==0);
fprintf(vvp_out, " %%retload/vec4 0;\n"); fprintf(vvp_out, " %%retload/vec4 0;\n");
@ -121,12 +121,17 @@ static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice
} else if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0) { } else if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0) {
assert(use_word == 0); assert(use_word == 0);
assert(!signal_is_return_value(sig)); // NOT IMPLEMENTED //assert(!signal_is_return_value(sig)); // NOT IMPLEMENTED
slice->type = SLICE_PART_SELECT_STATIC; slice->type = SLICE_PART_SELECT_STATIC;
slice->u_.part_select_static.part_off = part_off; slice->u_.part_select_static.part_off = part_off;
if (signal_is_return_value(sig)) {
assert(use_word==0);
fprintf(vvp_out, " %%retload/vec4 0;\n");
} else {
fprintf(vvp_out, " %%load/vec4 v%p_%lu;\n", sig, use_word); fprintf(vvp_out, " %%load/vec4 v%p_%lu;\n", sig, use_word);
}
fprintf(vvp_out, " %%pushi/vec4 %lu, 0, 32;\n", part_off); fprintf(vvp_out, " %%pushi/vec4 %lu, 0, 32;\n", part_off);
fprintf(vvp_out, " %%part/u %u;\n", wid); fprintf(vvp_out, " %%part/u %u;\n", wid);
@ -185,7 +190,7 @@ static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice
* leaves in the slices the information needed to store the slice * leaves in the slices the information needed to store the slice
* results back. * results back.
*/ */
static void get_vec_from_lval(ivl_statement_t net, struct vec_slice_info*slices) static void get_vec_from_lval(ivl_statement_t net, struct slice_info*slices)
{ {
unsigned lidx; unsigned lidx;
unsigned cur_bit; unsigned cur_bit;
@ -212,7 +217,7 @@ static void get_vec_from_lval(ivl_statement_t net, struct vec_slice_info*slices)
} }
static void put_vec_to_ret_slice(ivl_signal_t sig, struct vec_slice_info*slice, static void put_vec_to_ret_slice(ivl_signal_t sig, struct slice_info*slice,
unsigned wid) unsigned wid)
{ {
int part_off_idx; int part_off_idx;
@ -229,8 +234,8 @@ static void put_vec_to_ret_slice(ivl_signal_t sig, struct vec_slice_info*slice,
assert(0); assert(0);
break; break;
case SLICE_SIMPLE_VECTOR: case SLICE_SIMPLE_WORD:
assert(slice->u_.simple_vector.use_word == 0); assert(slice->u_.simple_word.use_word == 0);
fprintf(vvp_out, " %%ret/vec4 0, 0, %u;\n", wid); fprintf(vvp_out, " %%ret/vec4 0, 0, %u;\n", wid);
break; break;
@ -255,7 +260,7 @@ static void put_vec_to_ret_slice(ivl_signal_t sig, struct vec_slice_info*slice,
} }
} }
static void put_vec_to_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice, static void put_vec_to_lval_slice(ivl_lval_t lval, struct slice_info*slice,
unsigned wid) unsigned wid)
{ {
//unsigned skip_set = transient_id++; //unsigned skip_set = transient_id++;
@ -283,9 +288,9 @@ static void put_vec_to_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice,
assert(0); assert(0);
break; break;
case SLICE_SIMPLE_VECTOR: case SLICE_SIMPLE_WORD:
fprintf(vvp_out, " %%store/vec4 v%p_%lu, 0, %u;\n", fprintf(vvp_out, " %%store/vec4 v%p_%lu, 0, %u;\n",
sig, slice->u_.simple_vector.use_word, wid); sig, slice->u_.simple_word.use_word, wid);
break; break;
case SLICE_PART_SELECT_STATIC: case SLICE_PART_SELECT_STATIC:
@ -329,7 +334,7 @@ static void put_vec_to_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice,
} }
} }
static void put_vec_to_lval(ivl_statement_t net, struct vec_slice_info*slices) static void put_vec_to_lval(ivl_statement_t net, struct slice_info*slices)
{ {
unsigned lidx; unsigned lidx;
unsigned cur_bit; unsigned cur_bit;
@ -482,7 +487,7 @@ static int show_stmt_assign_vector(ivl_statement_t net)
ivl_expr_t rval = ivl_stmt_rval(net); ivl_expr_t rval = ivl_stmt_rval(net);
//struct vector_info res; //struct vector_info res;
//struct vector_info lres = {0, 0}; //struct vector_info lres = {0, 0};
struct vec_slice_info*slices = 0; struct slice_info*slices = 0;
int idx_reg; int idx_reg;
/* If this is a compressed assignment, then get the contents /* If this is a compressed assignment, then get the contents
@ -490,7 +495,7 @@ static int show_stmt_assign_vector(ivl_statement_t net)
calculation. */ calculation. */
if (ivl_stmt_opcode(net) != 0) { if (ivl_stmt_opcode(net) != 0) {
fprintf(vvp_out, " ; show_stmt_assign_vector: Get l-value for compressed %c= operand\n", ivl_stmt_opcode(net)); fprintf(vvp_out, " ; show_stmt_assign_vector: Get l-value for compressed %c= operand\n", ivl_stmt_opcode(net));
slices = calloc(ivl_stmt_lvals(net), sizeof(struct vec_slice_info)); slices = calloc(ivl_stmt_lvals(net), sizeof(struct slice_info));
get_vec_from_lval(net, slices); get_vec_from_lval(net, slices);
} }
@ -628,22 +633,113 @@ static int show_stmt_assign_vector(ivl_statement_t net)
return 0; return 0;
} }
/* static void get_real_from_lval(ivl_lval_t lval, struct slice_info*slice)
* This function assigns a value to a real variable. This is destined {
* for /dev/null when typed ivl_signal_t takes over all the real ivl_signal_t sig = ivl_lval_sig(lval);
* variable support. ivl_expr_t word_ix = ivl_lval_idx(lval);
*/ unsigned long use_word = 0;
static int show_stmt_assign_sig_real(ivl_statement_t net)
/* If the word index is a constant expression, then evaluate
it to select the word, and pay no further heed to the
expression itself. */
if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) {
assert(! number_is_unknown(word_ix));
use_word = get_number_immediate(word_ix);
word_ix = 0;
}
if (ivl_signal_dimensions(sig)==0 && word_ix==0) {
slice->type = SLICE_SIMPLE_WORD;
slice->u_.simple_word.use_word = use_word;
if (signal_is_return_value(sig)) {
assert(use_word==0);
fprintf(vvp_out, " %%retload/real 0;\n");
} else {
fprintf(vvp_out, " %%load/real v%p_%lu;\n", sig, use_word);
}
} else if (ivl_signal_dimensions(sig) > 0 && word_ix == 0) {
assert(!signal_is_return_value(sig)); // NOT IMPLEMENTED
slice->type = SLICE_MEMORY_WORD_STATIC;
slice->u_.memory_word_static.use_word = use_word;
if (use_word < ivl_signal_array_count(sig)) {
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n",
use_word);
fprintf(vvp_out, " %%load/reala v%p, 3;\n", sig);
} else {
fprintf(vvp_out, " %%pushi/real 0, 0;\n");
}
} else if (ivl_signal_dimensions(sig) > 0 && word_ix != 0) {
assert(!signal_is_return_value(sig)); // NOT IMPLEMENTED
slice->type = SLICE_MEMORY_WORD_DYNAMIC;
slice->u_.memory_word_dynamic.word_idx_reg = allocate_word();
slice->u_.memory_word_dynamic.x_flag = allocate_flag();
draw_eval_expr_into_integer(word_ix, slice->u_.memory_word_dynamic.word_idx_reg);
fprintf(vvp_out, " %%flag_mov %u, 4;\n", slice->u_.memory_word_dynamic.x_flag);
fprintf(vvp_out, " %%load/reala v%p, %d;\n", sig, slice->u_.memory_word_dynamic.word_idx_reg);
} else {
assert(0);
}
}
static void put_real_to_lval(ivl_lval_t lval, struct slice_info*slice)
{
ivl_signal_t sig = ivl_lval_sig(lval);
/* Special Case: If the l-value signal is named after its scope,
and the scope is a function, then this is an assign to a return
value and should be handled differently. */
if (signal_is_return_value(sig)) {
assert(slice->u_.simple_word.use_word == 0);
fprintf(vvp_out, " %%ret/real 0;\n");
return;
}
switch (slice->type) {
default:
fprintf(vvp_out, " ; XXXX slice->type=%d\n", slice->type);
assert(0);
break;
case SLICE_SIMPLE_WORD:
fprintf(vvp_out, " %%store/real v%p_%lu;\n",
sig, slice->u_.simple_word.use_word);
break;
case SLICE_MEMORY_WORD_STATIC:
if (slice->u_.memory_word_static.use_word < ivl_signal_array_count(sig)) {
int word_idx = allocate_word();
fprintf(vvp_out," %%flag_set/imm 4, 0;\n");
fprintf(vvp_out," %%ix/load %d, %lu, 0;\n", word_idx, slice->u_.memory_word_static.use_word);
fprintf(vvp_out," %%store/reala v%p, %d;\n", sig, word_idx);
clr_word(word_idx);
} else {
fprintf(vvp_out," ; Skip this slice write to v%p [%lu]\n", sig, slice->u_.memory_word_static.use_word);
}
break;
case SLICE_MEMORY_WORD_DYNAMIC:
fprintf(vvp_out, " %%flag_mov 4, %u;\n", slice->u_.memory_word_dynamic.x_flag);
fprintf(vvp_out, " %%store/reala v%p, %d;\n", sig, slice->u_.memory_word_dynamic.word_idx_reg);
clr_word(slice->u_.memory_word_dynamic.word_idx_reg);
clr_flag(slice->u_.memory_word_dynamic.x_flag);
break;
}
}
static void store_real_to_lval(ivl_lval_t lval)
{ {
ivl_lval_t lval;
ivl_signal_t var; ivl_signal_t var;
assert(ivl_stmt_opcode(net) == 0);
draw_eval_real(ivl_stmt_rval(net));
assert(ivl_stmt_lvals(net) == 1);
lval = ivl_stmt_lval(net, 0);
var = ivl_lval_sig(lval); var = ivl_lval_sig(lval);
assert(var != 0); assert(var != 0);
@ -656,12 +752,12 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
assert(ivl_signal_dimensions(var) == 0); assert(ivl_signal_dimensions(var) == 0);
fprintf(vvp_out, " %%ret/real 0; Assign to %s\n", fprintf(vvp_out, " %%ret/real 0; Assign to %s\n",
ivl_signal_basename(var)); ivl_signal_basename(var));
return 0; return;
} }
if (ivl_signal_dimensions(var) == 0) { if (ivl_signal_dimensions(var) == 0) {
fprintf(vvp_out, " %%store/real v%p_0;\n", var); fprintf(vvp_out, " %%store/real v%p_0;\n", var);
return 0; return;
} }
// For now, only support 1-dimensional arrays. // For now, only support 1-dimensional arrays.
@ -697,7 +793,66 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
} }
clr_word(word_ix); clr_word(word_ix);
}
/*
* This function assigns a value to a real variable. This is destined
* for /dev/null when typed ivl_signal_t takes over all the real
* variable support.
*/
static int show_stmt_assign_sig_real(ivl_statement_t net)
{
struct slice_info*slice = 0;
ivl_lval_t lval;
assert(ivl_stmt_lvals(net) == 1);
lval = ivl_stmt_lval(net, 0);
/* If this is a compressed assignment, then get the contents
of the l-value. We need this value as part of the r-value
calculation. */
if (ivl_stmt_opcode(net) != 0) {
fprintf(vvp_out, " ; show_stmt_assign_real: Get l-value for compressed %c= operand\n", ivl_stmt_opcode(net));
slice = calloc(1, sizeof(struct slice_info));
get_real_from_lval(lval, slice);
}
draw_eval_real(ivl_stmt_rval(net));
switch (ivl_stmt_opcode(net)) {
case 0:
store_real_to_lval(lval);
if (slice) free(slice);
return 0;
case '+':
fprintf(vvp_out, " %%add/wr;\n");
break;
case '-':
fprintf(vvp_out, " %%sub/wr;\n");
break;
case '*':
fprintf(vvp_out, " %%mul/wr;\n");
break;
case '/':
fprintf(vvp_out, " %%div/wr;\n");
break;
case '%':
fprintf(vvp_out, " %%mod/wr;\n");
break;
default:
fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", ivl_stmt_opcode(net));
assert(0);
break;
}
put_real_to_lval(lval, slice);
free(slice);
return 0; return 0;
} }