Skip to content

Commit d5fb0f4

Browse files
committed
Handle some tricky conditions assignments to parts.
When for example assigning to foo[<x>] within a contitional, and doing synthesis, we need to create a NetSubstitute device to manage the l-value bit selects.
1 parent c1e533d commit d5fb0f4

24 files changed

+499
-51
lines changed

design_dump.cc

+15
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,21 @@ void NetPartSelect::dump_node(ostream&o, unsigned ind) const
778778
dump_obj_attr(o, ind+4);
779779
}
780780

781+
void NetSubstitute::dump_node(ostream&fd, unsigned ind) const
782+
{
783+
fd << setw(ind) << "" << "NetSubstitute: "
784+
<< name();
785+
if (rise_time())
786+
fd << " #(" << *rise_time()
787+
<< "," << *fall_time()
788+
<< "," << *decay_time() << ")";
789+
else
790+
fd << " #(.,.,.)";
791+
fd << " width=" << wid_ << " base=" << off_ <<endl;
792+
dump_node_pins(fd, ind+4);
793+
dump_obj_attr(fd, ind+4);
794+
}
795+
781796
void NetReplicate::dump_node(ostream&o, unsigned ind) const
782797
{
783798
o << setw(ind) << "" << "NetReplicate: "

emit.cc

+5
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ bool NetSignExtend::emit_node(struct target_t*tgt) const
167167
return tgt->sign_extend(this);
168168
}
169169

170+
bool NetSubstitute::emit_node(struct target_t*tgt) const
171+
{
172+
return tgt->substitute(this);
173+
}
174+
170175
bool NetUReduce::emit_node(struct target_t*tgt) const
171176
{
172177
return tgt->ureduce(this);

ivl_target.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ typedef enum ivl_lpm_type_e {
328328
IVL_LPM_SHIFTR = 7,
329329
IVL_LPM_SIGN_EXT=27,
330330
IVL_LPM_SUB = 8,
331+
IVL_LPM_SUBSTITUTE=39,
331332
/* IVL_LPM_RAM = 9, / obsolete */
332333
IVL_LPM_UFUNC = 14
333334
} ivl_lpm_type_t;
@@ -1409,7 +1410,7 @@ extern ivl_nexus_t ivl_lpm_sync_set(ivl_lpm_t net);
14091410
extern ivl_expr_t ivl_lpm_sset_value(ivl_lpm_t net);
14101411
/* IVL_LPM_ARRAY */
14111412
extern ivl_signal_t ivl_lpm_array(ivl_lpm_t net);
1412-
/* IVL_LPM_PART */
1413+
/* IVL_LPM_PART IVL_LPM_SUBSTITUTE */
14131414
extern unsigned ivl_lpm_base(ivl_lpm_t net);
14141415
/* IVL_LPM_FF */
14151416
extern ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net);
@@ -1419,14 +1420,14 @@ extern ivl_scope_t ivl_lpm_define(ivl_lpm_t net);
14191420
extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net);
14201421
/* IVL_LPM_ADD IVL_LPM_CONCAT IVL_LPM_FF IVL_LPM_PART IVL_LPM_MULT
14211422
IVL_LPM_MUX IVL_LPM_POW IVL_LPM_SHIFTL IVL_LPM_SHIFTR IVL_LPM_SUB
1422-
IVL_LPM_UFUNC */
1423+
IVL_LPM_UFUNC IVL_LPM_SUBSTITUTE */
14231424
extern ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx);
14241425
/* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_POW IVL_LPM_SUB IVL_LPM_CMP_EQ
14251426
IVL_LPM_CMP_EEQ IVL_LPM_CMP_EQX IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE */
14261427
extern ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx);
14271428
/* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_PART IVL_LPM_POW
14281429
IVL_LPM_SUB IVL_LPM_UFUNC IVL_LPM_CMP_EEQ IVL_LPM_CMP_EQX
1429-
IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE */
1430+
IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE IVL_LPM_SUBSTITUTE */
14301431
extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net);
14311432
extern ivl_drive_t ivl_lpm_drive0(ivl_lpm_t net);
14321433
extern ivl_drive_t ivl_lpm_drive1(ivl_lpm_t net);

net_nex_output.cc

+11-12
Original file line numberDiff line numberDiff line change
@@ -60,19 +60,18 @@ void NetAssign_::nex_output(NexusSet&out)
6060
}
6161
Nexus*nex = sig_->pin(use_word).nexus();
6262
if (base_) {
63-
long tmp = 0;
64-
bool flag = eval_as_long(tmp, base_);
65-
if (!flag) {
66-
// Unable to evaluate the bit/part select of
67-
// the l-value, so this is a mux. Pretty
68-
// sure I don't know how to handle this yet
69-
// in synthesis, so punt for now.
70-
use_base = 0;
71-
use_wid = nex->vector_width();
7263

73-
} else {
74-
use_base = tmp;
75-
}
64+
// Unable to evaluate the bit/part select of
65+
// the l-value, so this is a mux. Pretty
66+
// sure I don't know how to handle this yet
67+
// in synthesis, so punt for now.
68+
69+
// Even with constant bit/part select, we want to
70+
// return the entire signal as an output. The
71+
// context will need to sort out which bits are
72+
// actually assigned.
73+
use_base = 0;
74+
use_wid = nex->vector_width();
7675
}
7776
out.add(nex, use_base, use_wid);
7877
}

netlist.cc

+14
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,20 @@ unsigned NetPartSelect::base() const
989989
return off_;
990990
}
991991

992+
NetSubstitute::NetSubstitute(NetNet*sig, NetNet*sub, unsigned wid, unsigned off)
993+
: NetNode(sig->scope(), sig->scope()->local_symbol(), 3), wid_(wid), off_(off)
994+
{
995+
pin(0).set_dir(Link::OUTPUT);
996+
pin(1).set_dir(Link::INPUT);
997+
pin(2).set_dir(Link::INPUT);
998+
connect(pin(1), sig->pin(0));
999+
connect(pin(2), sub->pin(0));
1000+
}
1001+
1002+
NetSubstitute::~NetSubstitute()
1003+
{
1004+
}
1005+
9921006
NetProc::NetProc()
9931007
: next_(0)
9941008
{

netlist.h

+34
Original file line numberDiff line numberDiff line change
@@ -2192,6 +2192,40 @@ class NetPartSelect : public NetNode {
21922192
bool signed_flag_;
21932193
};
21942194

2195+
/*
2196+
* This device supports simple substitution of a part within a wider
2197+
* vector. For example, this:
2198+
*
2199+
* wire [7:0] foo = NetSubstitute(bar, bat, off);
2200+
*
2201+
* meaus that bar is a vector the same width as foo, bat is a narrower
2202+
* vector. The off is a constant offset into the bar vector. This
2203+
* looks something like this:
2204+
*
2205+
* foo = bar;
2206+
* foo[off +: <width_of_bat>] = bat;
2207+
*
2208+
* There is no direct way in Verilog to express this (as a single
2209+
* device), it instead turns up in certain synthesis situation,
2210+
* i.e. the example above.
2211+
*/
2212+
class NetSubstitute : public NetNode {
2213+
2214+
public:
2215+
NetSubstitute(NetNet*sig, NetNet*sub, unsigned wid, unsigned off);
2216+
~NetSubstitute();
2217+
2218+
inline unsigned width() const { return wid_; }
2219+
inline unsigned base() const { return off_; }
2220+
2221+
virtual void dump_node(ostream&, unsigned ind) const;
2222+
virtual bool emit_node(struct target_t*tgt) const;
2223+
2224+
private:
2225+
unsigned wid_;
2226+
unsigned off_;
2227+
};
2228+
21952229
/*
21962230
* The NetBUFZ is a magic device that represents the continuous
21972231
* assign, with the output being the target register and the input

0 commit comments

Comments
 (0)