Skip to content

Commit

Permalink
Add support for LPM_SUBSTITUTE and wider LPM_MUX objects in vlog95 ta…
Browse files Browse the repository at this point in the history
…rget.
  • Loading branch information
martinwhitaker committed Feb 27, 2016
1 parent 9d5f4ad commit a33255f
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 26 deletions.
183 changes: 157 additions & 26 deletions tgt-vlog95/logic_lpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ typedef enum lpm_sign_e {
} lpm_sign_t;

static ivl_signal_t nexus_is_signal(ivl_scope_t scope, ivl_nexus_t nex,
int*base, unsigned*array_word);
int*msb, int*lsb, unsigned*array_word);

/*
* Look to see if the nexus driver is signed.
Expand Down Expand Up @@ -68,12 +68,12 @@ static int nexus_driver_is_signed(ivl_scope_t scope, ivl_nexus_t nex)
* local signal to get the sign information. */
if (ivl_logic_type(t_nlogic) == IVL_LO_BUFZ) {
unsigned array_word = 0;
int base = 0;
int msb = 0, lsb = 0;
ivl_signal_t sig;
assert(ivl_logic_pins(t_nlogic) == 2);
sig = nexus_is_signal(scope,
ivl_logic_pin(t_nlogic, 0),
&base, &array_word);
&msb, &lsb, &array_word);
assert(sig);
is_signed = ivl_signal_signed(sig);
}
Expand All @@ -88,6 +88,19 @@ static int nexus_driver_is_signed(ivl_scope_t scope, ivl_nexus_t nex)
return is_signed;
}

static unsigned get_nexus_width(ivl_nexus_t nex)
{
unsigned idx, count = ivl_nexus_ptrs(nex);

for (idx = 0; idx < count; idx += 1) {
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
ivl_signal_t sig = ivl_nexus_ptr_sig(nex_ptr);
if (sig) return ivl_signal_width(sig);
}
assert(0);
return 0;
}

static lpm_sign_t lpm_get_sign_type(ivl_lpm_t lpm,
unsigned can_skip_unsigned)
{
Expand Down Expand Up @@ -196,6 +209,14 @@ static void emit_gate_strength(ivl_net_logic_t nlogic, unsigned strength_type)
"gate", ivl_logic_file(nlogic), ivl_logic_lineno(nlogic));
}

static void emit_part_selector(int msb, int lsb)
{
if (msb != lsb)
fprintf(vlog_out, "[%d:%d]", msb, lsb);
else
fprintf(vlog_out, "[%d]", lsb);
}

/*
* Look for a single driver behind an LPM that passes strength information
* and get the real drive information from it.
Expand Down Expand Up @@ -758,7 +779,7 @@ static ivl_signal_t find_output_signal(ivl_scope_t scope, ivl_nexus_t nex,
}

static ivl_signal_t nexus_is_signal(ivl_scope_t scope, ivl_nexus_t nex,
int*base, unsigned*array_word)
int*msb, int*lsb, unsigned*array_word)
{
unsigned idx, count = ivl_nexus_ptrs(nex);
ivl_lpm_t lpm = 0;
Expand All @@ -767,10 +788,16 @@ static ivl_signal_t nexus_is_signal(ivl_scope_t scope, ivl_nexus_t nex,
ivl_signal_t sig;
/* Look for a signal in the local scope first. */
sig = find_local_signal(scope, nex, array_word);
if (sig) return sig;
if (sig) {
get_sig_msb_lsb(sig, msb, lsb);
return sig;
}
/* Now look for an output signal driving into the local scope. */
sig = find_output_signal(scope, nex, array_word);
if (sig) return sig;
if (sig) {
get_sig_msb_lsb(sig, msb, lsb);
return sig;
}
/* Now scan the nexus looking for a driver. */
for (idx = 0; idx < count; idx += 1) {
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
Expand All @@ -785,11 +812,18 @@ static ivl_signal_t nexus_is_signal(ivl_scope_t scope, ivl_nexus_t nex,
/* The real signal could be hidden behind a select. */
if (ivl_lpm_type(t_lpm) == IVL_LPM_PART_VP) {
t_sig = nexus_is_signal(scope, ivl_lpm_data(t_lpm, 0),
base, array_word);
msb, lsb, array_word);
}

if (t_sig) *base += ivl_lpm_base(t_lpm);
else lpm = t_lpm;
if (t_sig) {
if (*msb >= *lsb) {
*lsb += ivl_lpm_base(t_lpm);
*msb = *lsb + (int)ivl_lpm_width(t_lpm) - 1;
} else {
*lsb -= ivl_lpm_base(t_lpm);
*msb = *lsb - (int)ivl_lpm_width(t_lpm) + 1;
}
} else lpm = t_lpm;
}
if (t_net_const) {
assert(! net_const);
Expand All @@ -802,7 +836,7 @@ static ivl_signal_t nexus_is_signal(ivl_scope_t scope, ivl_nexus_t nex,
assert(ivl_logic_pins(t_nlogic) == 2);
t_sig = nexus_is_signal(scope,
ivl_logic_pin(t_nlogic, 1),
base, array_word);
msb, lsb, array_word);
} else nlogic = t_nlogic;
}
if (t_sig) {
Expand All @@ -821,9 +855,9 @@ static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm,
unsigned width = ivl_lpm_width(lpm);
unsigned array_word = 0;
int base = ivl_lpm_base(lpm);
int msb, lsb;
int msb = 0, lsb = 0;
ivl_signal_t sig = nexus_is_signal(scope, ivl_lpm_data(lpm, 0),
&base, &array_word);
&msb, &lsb, &array_word);

if (sign_extend && !allow_signed) {
fprintf(stderr, "%s:%u: vlog95 error: >>> operator is not "
Expand Down Expand Up @@ -854,9 +888,9 @@ static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm,
fprintf(vlog_out, "[%d]", array_idx);
}

get_sig_msb_lsb(sig, &msb, &lsb);
if (sign_extend) {
assert(base != lsb);
// HERE: This looks wrong.
if (msb >= lsb) base += lsb;
else base = lsb - base;
fprintf(vlog_out, " >>> %d)", base);
Expand All @@ -880,7 +914,7 @@ static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm,
}
} else {
/* Skip a select of the entire bit. */
if ((msb == lsb) && (lsb == base)) return;
if ((msb == lsb) && (base == 0)) return;
fprintf(vlog_out, "[");
if (msb >= lsb) base += lsb;
else base = lsb - base;
Expand Down Expand Up @@ -926,6 +960,103 @@ static void emit_lpm_func(ivl_scope_t scope, ivl_lpm_t lpm)
}
}

static void emit_mux_select_bit(ivl_scope_t scope, ivl_lpm_t lpm, unsigned bit)
{
unsigned array_word = 0;
int msb = 0, lsb = 0;

ivl_signal_t sig = nexus_is_signal(scope, ivl_lpm_select(lpm),
&msb, &lsb, &array_word);
assert(sig);
emit_scope_call_path(scope, ivl_signal_scope(sig));
emit_id(ivl_signal_basename(sig));
if (ivl_signal_dimensions(sig)) {
int array_idx = (int) array_word + ivl_signal_array_base(sig);
fprintf(vlog_out, "[%d]", array_idx);
}
if (msb >= lsb) {
fprintf(vlog_out, "[%d]", lsb + (int)bit);
} else {
fprintf(vlog_out, "[%d]", lsb - (int)bit);
}
}

static void emit_lpm_mux(ivl_scope_t scope, ivl_lpm_t lpm,
unsigned sel_bit, unsigned offset)
{
assert(sel_bit < sizeof(unsigned)*8);
fprintf(vlog_out, "(");
emit_mux_select_bit(scope, lpm, sel_bit);
fprintf(vlog_out, " ? ");
if (sel_bit > 0) {
emit_lpm_mux(scope, lpm, sel_bit - 1, offset + (1U << sel_bit));
fprintf(vlog_out, " : ");
emit_lpm_mux(scope, lpm, sel_bit - 1, offset);
} else {
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, offset + 1), 0, 0);
fprintf(vlog_out, " : ");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, offset + 0), 0, 0);
}
fprintf(vlog_out, ")");
}

static void emit_lpm_substitute(ivl_scope_t scope, ivl_lpm_t lpm)
{
unsigned array_word = 0;
int msb = 0, lsb = 0;
unsigned base = ivl_lpm_base(lpm);
unsigned width;
int psb;

/* Find the wider signal. */
ivl_signal_t sig = nexus_is_signal(scope, ivl_lpm_data(lpm, 0),
&msb, &lsb, &array_word);
assert(sig);

// Get the width of the part being substituted.
width = get_nexus_width(ivl_lpm_data(lpm, 1));

fprintf(vlog_out, "{");

if (msb >= lsb) {
psb = lsb + base + width;
} else {
psb = lsb - base - width;
}
if (psb <= msb) {
emit_scope_call_path(scope, ivl_signal_scope(sig));
emit_id(ivl_signal_basename(sig));
if (ivl_signal_dimensions(sig)) {
int array_idx = (int) array_word + ivl_signal_array_base(sig);
fprintf(vlog_out, "[%d]", array_idx);
}
emit_part_selector(msb, psb);

fprintf(vlog_out, ", ");
}

emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0);

if (msb >= lsb) {
psb = lsb + base - 1;
} else {
psb = lsb - base + 1;
}
if (psb >= lsb) {
fprintf(vlog_out, ", ");

emit_scope_call_path(scope, ivl_signal_scope(sig));
emit_id(ivl_signal_basename(sig));
if (ivl_signal_dimensions(sig)) {
int array_idx = (int) array_word + ivl_signal_array_base(sig);
fprintf(vlog_out, "[%d]", array_idx);
}
emit_part_selector(psb, lsb);
}

fprintf(vlog_out, "}");
}

static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm,
unsigned sign_extend)
{
Expand Down Expand Up @@ -1087,13 +1218,17 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm,
fprintf(vlog_out, ")");
break;
case IVL_LPM_MUX:
fprintf(vlog_out, "(");
emit_nexus_as_ca(scope, ivl_lpm_select(lpm), 0, 0);
fprintf(vlog_out, " ? ");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0);
fprintf(vlog_out, " : ");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0, 0);
fprintf(vlog_out, ")");
if (ivl_lpm_selects(lpm) > 1) {
emit_lpm_mux(scope, lpm, ivl_lpm_selects(lpm) - 1, 0);
} else {
fprintf(vlog_out, "(");
emit_nexus_as_ca(scope, ivl_lpm_select(lpm), 0, 0);
fprintf(vlog_out, " ? ");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0);
fprintf(vlog_out, " : ");
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0, 0);
fprintf(vlog_out, ")");
}
break;
case IVL_LPM_PART_PV:
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 1, 0);
Expand Down Expand Up @@ -1188,11 +1323,7 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm,
fprintf(vlog_out, ")");
break;
case IVL_LPM_SUBSTITUTE:
fprintf(vlog_out, "<unknown>");
fprintf(stderr, "%s:%u: vlog95 sorry: Substitute LPMs are "
"not currently translated.\n",
ivl_lpm_file(lpm), ivl_lpm_lineno(lpm));
vlog_errors += 1;
emit_lpm_substitute(scope, lpm);
break;
case IVL_LPM_UFUNC:
emit_scope_path(scope, ivl_lpm_define(lpm));
Expand Down
2 changes: 2 additions & 0 deletions tgt-vlog95/vlog95-s.conf
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
functor:synth2
functor:synth
functor:syn-rules
functor:synthsplit
functor:nodangle
flag:DLL=vlog95.tgt
flag:DISABLE_CONCATZ_GENERATION=true

0 comments on commit a33255f

Please sign in to comment.