Add a routine to say if a logical came from a CA and some other fixes.
This patch adds code that allows the targets to determine if a logical gate came from a continuous assignment. This helps some of the targets generate code that more closely matches the input. It also reworks/simplifies the synthesis of && and || since the compiler has already converted the two operands to single bit form and fixes a mismatched delete from a previous patch.
This commit is contained in:
parent
ceaa79e95d
commit
eb0df40a73
|
|
@ -184,22 +184,22 @@ NetNet* NetEBBits::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
||||||
|
|
||||||
switch (op()) {
|
switch (op()) {
|
||||||
case '&':
|
case '&':
|
||||||
gate = new NetLogic(scope, oname, 3, NetLogic::AND, width);
|
gate = new NetLogic(scope, oname, 3, NetLogic::AND, width, true);
|
||||||
break;
|
break;
|
||||||
case 'A':
|
case 'A':
|
||||||
gate = new NetLogic(scope, oname, 3, NetLogic::NAND, width);
|
gate = new NetLogic(scope, oname, 3, NetLogic::NAND, width, true);
|
||||||
break;
|
break;
|
||||||
case '|':
|
case '|':
|
||||||
gate = new NetLogic(scope, oname, 3, NetLogic::OR, width);
|
gate = new NetLogic(scope, oname, 3, NetLogic::OR, width, true);
|
||||||
break;
|
break;
|
||||||
case '^':
|
case '^':
|
||||||
gate = new NetLogic(scope, oname, 3, NetLogic::XOR, width);
|
gate = new NetLogic(scope, oname, 3, NetLogic::XOR, width, true);
|
||||||
break;
|
break;
|
||||||
case 'O':
|
case 'O':
|
||||||
gate = new NetLogic(scope, oname, 3, NetLogic::NOR, width);
|
gate = new NetLogic(scope, oname, 3, NetLogic::NOR, width, true);
|
||||||
break;
|
break;
|
||||||
case 'X':
|
case 'X':
|
||||||
gate = new NetLogic(scope, oname, 3, NetLogic::XNOR, width);
|
gate = new NetLogic(scope, oname, 3, NetLogic::XNOR, width, true);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
gate = NULL;
|
gate = NULL;
|
||||||
|
|
@ -286,7 +286,7 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
||||||
operation. Make an XNOR gate instead of a comparator. */
|
operation. Make an XNOR gate instead of a comparator. */
|
||||||
if ((width == 1) && (op_ == 'e') && !real_args) {
|
if ((width == 1) && (op_ == 'e') && !real_args) {
|
||||||
NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
|
NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
|
||||||
3, NetLogic::XNOR, 1);
|
3, NetLogic::XNOR, 1, true);
|
||||||
gate->set_line(*this);
|
gate->set_line(*this);
|
||||||
connect(gate->pin(0), osig->pin(0));
|
connect(gate->pin(0), osig->pin(0));
|
||||||
connect(gate->pin(1), lsig->pin(0));
|
connect(gate->pin(1), lsig->pin(0));
|
||||||
|
|
@ -300,7 +300,7 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
||||||
an XOR instead of an XNOR gate. */
|
an XOR instead of an XNOR gate. */
|
||||||
if ((width == 1) && (op_ == 'n') && !real_args) {
|
if ((width == 1) && (op_ == 'n') && !real_args) {
|
||||||
NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
|
NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
|
||||||
3, NetLogic::XOR, 1);
|
3, NetLogic::XOR, 1, true);
|
||||||
gate->set_line(*this);
|
gate->set_line(*this);
|
||||||
connect(gate->pin(0), osig->pin(0));
|
connect(gate->pin(0), osig->pin(0));
|
||||||
connect(gate->pin(1), lsig->pin(0));
|
connect(gate->pin(1), lsig->pin(0));
|
||||||
|
|
@ -520,11 +520,12 @@ NetNet* NetEBLogic::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
||||||
|
|
||||||
if (lsig == 0 || rsig == 0) return 0;
|
if (lsig == 0 || rsig == 0) return 0;
|
||||||
|
|
||||||
/* You cannot currently do logical operations on real values. */
|
/* Any real value should have already been converted to a bit value. */
|
||||||
if (lsig->data_type() == IVL_VT_REAL ||
|
if (lsig->data_type() == IVL_VT_REAL ||
|
||||||
rsig->data_type() == IVL_VT_REAL) {
|
rsig->data_type() == IVL_VT_REAL) {
|
||||||
cerr << get_fileline() << ": sorry: " << human_readable_op(op_)
|
cerr << get_fileline() << ": internal error: "
|
||||||
<< " is currently unsupported for real values." << endl;
|
<< human_readable_op(op_)
|
||||||
|
<< " is missing real to bit conversion." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -535,60 +536,30 @@ NetNet* NetEBLogic::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
||||||
osig->data_type(expr_type());
|
osig->data_type(expr_type());
|
||||||
osig->local_flag(true);
|
osig->local_flag(true);
|
||||||
|
|
||||||
|
|
||||||
if (op() == 'o') {
|
|
||||||
|
|
||||||
/* Logic OR can handle the reduction *and* the logical
|
|
||||||
comparison with a single wide OR gate. So handle this
|
|
||||||
magically. */
|
|
||||||
|
|
||||||
perm_string oname = scope->local_symbol();
|
|
||||||
|
|
||||||
NetLogic*olog = new NetLogic(scope, oname,
|
|
||||||
lsig->pin_count()+rsig->pin_count()+1,
|
|
||||||
NetLogic::OR, 1);
|
|
||||||
olog->set_line(*this);
|
|
||||||
|
|
||||||
connect(osig->pin(0), olog->pin(0));
|
|
||||||
|
|
||||||
unsigned pin = 1;
|
|
||||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx = 1)
|
|
||||||
connect(olog->pin(pin+idx), lsig->pin(idx));
|
|
||||||
|
|
||||||
pin += lsig->pin_count();
|
|
||||||
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx = 1)
|
|
||||||
connect(olog->pin(pin+idx), rsig->pin(idx));
|
|
||||||
|
|
||||||
des->add_node(olog);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
assert(op() == 'a');
|
|
||||||
|
|
||||||
/* Create the logic AND gate. This is a single bit
|
|
||||||
output, with inputs for each of the operands. */
|
|
||||||
NetLogic*olog;
|
NetLogic*olog;
|
||||||
perm_string oname = scope->local_symbol();
|
perm_string oname = scope->local_symbol();
|
||||||
|
|
||||||
olog = new NetLogic(scope, oname, 3, NetLogic::AND, 1);
|
/* Create the logic OR/AND gate. This has a single bit output,
|
||||||
olog->set_line(*this);
|
* with single bit inputs for the two operands. */
|
||||||
|
if (op() == 'o') {
|
||||||
|
olog = new NetLogic(scope, oname, 3, NetLogic::OR, 1, true);
|
||||||
|
} else {
|
||||||
|
assert(op() == 'a');
|
||||||
|
olog = new NetLogic(scope, oname, 3, NetLogic::AND, 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
connect(osig->pin(0), olog->pin(0));
|
olog->set_line(*this);
|
||||||
des->add_node(olog);
|
des->add_node(olog);
|
||||||
|
|
||||||
/* XXXX Here, I need to reduce the parameters with
|
connect(osig->pin(0), olog->pin(0));
|
||||||
reduction or. */
|
|
||||||
|
|
||||||
|
/* The left and right operands have already been reduced to a
|
||||||
/* By this point, the left and right parameters have been
|
* single bit value, so just connect then to the logic gate. */
|
||||||
reduced to single bit values. Now we just connect them to
|
|
||||||
the logic gate. */
|
|
||||||
assert(lsig->pin_count() == 1);
|
assert(lsig->pin_count() == 1);
|
||||||
connect(lsig->pin(0), olog->pin(1));
|
connect(lsig->pin(0), olog->pin(1));
|
||||||
|
|
||||||
assert(rsig->pin_count() == 1);
|
assert(rsig->pin_count() == 1);
|
||||||
connect(rsig->pin(0), olog->pin(2));
|
connect(rsig->pin(0), olog->pin(2));
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return osig;
|
return osig;
|
||||||
}
|
}
|
||||||
|
|
@ -879,7 +850,7 @@ NetNet* NetEUBits::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
||||||
|
|
||||||
switch (op()) {
|
switch (op()) {
|
||||||
case '~':
|
case '~':
|
||||||
gate = new NetLogic(scope, oname, 2, NetLogic::NOT, width);
|
gate = new NetLogic(scope, oname, 2, NetLogic::NOT, width, true);
|
||||||
gate->set_line(*this);
|
gate->set_line(*this);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
1
ivl.def
1
ivl.def
|
|
@ -92,6 +92,7 @@ ivl_logic_delay
|
||||||
ivl_logic_drive0
|
ivl_logic_drive0
|
||||||
ivl_logic_drive1
|
ivl_logic_drive1
|
||||||
ivl_logic_file
|
ivl_logic_file
|
||||||
|
ivl_logic_is_cassign
|
||||||
ivl_logic_lineno
|
ivl_logic_lineno
|
||||||
ivl_logic_name
|
ivl_logic_name
|
||||||
ivl_logic_pin
|
ivl_logic_pin
|
||||||
|
|
|
||||||
|
|
@ -996,6 +996,7 @@ extern ivl_expr_t ivl_logic_delay(ivl_net_logic_t net, unsigned transition);
|
||||||
extern ivl_drive_t ivl_logic_drive0(ivl_net_logic_t net);
|
extern ivl_drive_t ivl_logic_drive0(ivl_net_logic_t net);
|
||||||
extern ivl_drive_t ivl_logic_drive1(ivl_net_logic_t net);
|
extern ivl_drive_t ivl_logic_drive1(ivl_net_logic_t net);
|
||||||
extern unsigned ivl_logic_width(ivl_net_logic_t net);
|
extern unsigned ivl_logic_width(ivl_net_logic_t net);
|
||||||
|
extern unsigned ivl_logic_is_cassign(ivl_net_logic_t net);
|
||||||
|
|
||||||
/* DEPRECATED */
|
/* DEPRECATED */
|
||||||
extern const char* ivl_logic_attr(ivl_net_logic_t net, const char*key);
|
extern const char* ivl_logic_attr(ivl_net_logic_t net, const char*key);
|
||||||
|
|
|
||||||
|
|
@ -2441,8 +2441,8 @@ ivl_variable_type_t NetECast::expr_type() const
|
||||||
}
|
}
|
||||||
|
|
||||||
NetLogic::NetLogic(NetScope*s, perm_string n, unsigned pins,
|
NetLogic::NetLogic(NetScope*s, perm_string n, unsigned pins,
|
||||||
TYPE t, unsigned wid)
|
TYPE t, unsigned wid, bool is_cassign__)
|
||||||
: NetNode(s, n, pins), type_(t), width_(wid)
|
: NetNode(s, n, pins), type_(t), width_(wid), is_cassign_(is_cassign__)
|
||||||
{
|
{
|
||||||
pin(0).set_dir(Link::OUTPUT);
|
pin(0).set_dir(Link::OUTPUT);
|
||||||
for (unsigned idx = 1 ; idx < pins ; idx += 1) {
|
for (unsigned idx = 1 ; idx < pins ; idx += 1) {
|
||||||
|
|
@ -2460,6 +2460,11 @@ unsigned NetLogic::width() const
|
||||||
return width_;
|
return width_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NetLogic::is_cassign() const
|
||||||
|
{
|
||||||
|
return is_cassign_;
|
||||||
|
}
|
||||||
|
|
||||||
NetUReduce::NetUReduce(NetScope*scope__, perm_string n,
|
NetUReduce::NetUReduce(NetScope*scope__, perm_string n,
|
||||||
NetUReduce::TYPE t, unsigned wid)
|
NetUReduce::TYPE t, unsigned wid)
|
||||||
: NetNode(scope__, n, 2), type_(t), width_(wid)
|
: NetNode(scope__, n, 2), type_(t), width_(wid)
|
||||||
|
|
|
||||||
|
|
@ -2008,10 +2008,11 @@ class NetLogic : public NetNode {
|
||||||
PMOS, XNOR, XOR };
|
PMOS, XNOR, XOR };
|
||||||
|
|
||||||
explicit NetLogic(NetScope*s, perm_string n, unsigned pins,
|
explicit NetLogic(NetScope*s, perm_string n, unsigned pins,
|
||||||
TYPE t, unsigned wid);
|
TYPE t, unsigned wid, bool is_cassign__=false);
|
||||||
|
|
||||||
TYPE type() const;
|
TYPE type() const;
|
||||||
unsigned width() const;
|
unsigned width() const;
|
||||||
|
bool is_cassign() const;
|
||||||
|
|
||||||
virtual void dump_node(ostream&, unsigned ind) const;
|
virtual void dump_node(ostream&, unsigned ind) const;
|
||||||
virtual bool emit_node(struct target_t*) const;
|
virtual bool emit_node(struct target_t*) const;
|
||||||
|
|
@ -2020,6 +2021,7 @@ class NetLogic : public NetNode {
|
||||||
private:
|
private:
|
||||||
TYPE type_;
|
TYPE type_;
|
||||||
unsigned width_;
|
unsigned width_;
|
||||||
|
bool is_cassign_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -747,6 +747,12 @@ extern "C" unsigned ivl_logic_lineno(ivl_net_logic_t net)
|
||||||
return net->lineno;
|
return net->lineno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" unsigned ivl_logic_is_cassign(ivl_net_logic_t net)
|
||||||
|
{
|
||||||
|
assert(net);
|
||||||
|
return net->is_cassign;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" const char* ivl_logic_attr(ivl_net_logic_t net, const char*key)
|
extern "C" const char* ivl_logic_attr(ivl_net_logic_t net, const char*key)
|
||||||
{
|
{
|
||||||
assert(net);
|
assert(net);
|
||||||
|
|
|
||||||
7
t-dll.cc
7
t-dll.cc
|
|
@ -759,6 +759,7 @@ bool dll_target::bufz(const NetBUFZ*net)
|
||||||
|
|
||||||
obj->type_ = net->transparent()? IVL_LO_BUFT : IVL_LO_BUFZ;
|
obj->type_ = net->transparent()? IVL_LO_BUFT : IVL_LO_BUFZ;
|
||||||
obj->width_= net->width();
|
obj->width_= net->width();
|
||||||
|
obj->is_cassign = 0;
|
||||||
obj->npins_= 2;
|
obj->npins_= 2;
|
||||||
obj->pins_ = new ivl_nexus_t[2];
|
obj->pins_ = new ivl_nexus_t[2];
|
||||||
FILE_NAME(obj, net);
|
FILE_NAME(obj, net);
|
||||||
|
|
@ -920,6 +921,9 @@ void dll_target::logic(const NetLogic*net)
|
||||||
obj->type_ = IVL_LO_NONE;
|
obj->type_ = IVL_LO_NONE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* Some of the logical gates are used to represent operators in a
|
||||||
|
* continuous assignment, so set a flag if that is the case. */
|
||||||
|
obj->is_cassign = net->is_cassign();
|
||||||
|
|
||||||
/* Connect all the ivl_nexus_t objects to the pins of the
|
/* Connect all the ivl_nexus_t objects to the pins of the
|
||||||
device. */
|
device. */
|
||||||
|
|
@ -1273,6 +1277,7 @@ void dll_target::udp(const NetUDP*net)
|
||||||
/* The NetUDP class hasn't learned about width yet, so we
|
/* The NetUDP class hasn't learned about width yet, so we
|
||||||
assume a width of 1. */
|
assume a width of 1. */
|
||||||
obj->width_ = 1;
|
obj->width_ = 1;
|
||||||
|
obj->is_cassign = 0;
|
||||||
|
|
||||||
static map<perm_string,ivl_udp_t> udps;
|
static map<perm_string,ivl_udp_t> udps;
|
||||||
ivl_udp_t u;
|
ivl_udp_t u;
|
||||||
|
|
@ -2352,7 +2357,7 @@ void dll_target::convert_module_ports(const NetScope*net)
|
||||||
ivl_signal_t sig = find_signal(des_, nets[idx]);
|
ivl_signal_t sig = find_signal(des_, nets[idx]);
|
||||||
scop->u_.nex[idx] = nexus_sig_make(sig, 0);
|
scop->u_.nex[idx] = nexus_sig_make(sig, 0);
|
||||||
}
|
}
|
||||||
delete nets;
|
delete [] nets;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue