Basic DFF asynchronous set/reset synthesis support.
This commit is contained in:
parent
ccce9d9271
commit
0f85bf0b9a
|
|
@ -2557,6 +2557,7 @@ class NetProc : public virtual LineInfo {
|
|||
// the flipflop being generated.
|
||||
virtual bool synth_sync(Design*des, NetScope*scope,
|
||||
NetNet*ff_clock, NetNet*ff_ce,
|
||||
NetNet*ff_aclr, NetNet*ff_aset,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const std::vector<NetEvProbe*>&events);
|
||||
|
||||
|
|
@ -2837,6 +2838,7 @@ class NetBlock : public NetProc {
|
|||
|
||||
bool synth_sync(Design*des, NetScope*scope,
|
||||
NetNet*ff_clk, NetNet*ff_ce,
|
||||
NetNet*ff_aclr,NetNet*ff_aset,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const std::vector<NetEvProbe*>&events);
|
||||
|
||||
|
|
@ -2975,6 +2977,7 @@ class NetCondit : public NetProc {
|
|||
|
||||
bool synth_sync(Design*des, NetScope*scope,
|
||||
NetNet*ff_clk, NetNet*ff_ce,
|
||||
NetNet*ff_aclr,NetNet*ff_aset,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const std::vector<NetEvProbe*>&events);
|
||||
|
||||
|
|
@ -3251,6 +3254,7 @@ class NetEvWait : public NetProc {
|
|||
|
||||
virtual bool synth_sync(Design*des, NetScope*scope,
|
||||
NetNet*ff_clk, NetNet*ff_ce,
|
||||
NetNet*ff_aclr,NetNet*ff_aset,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const std::vector<NetEvProbe*>&events);
|
||||
|
||||
|
|
|
|||
120
synth2.cc
120
synth2.cc
|
|
@ -35,6 +35,7 @@ bool NetProc::synth_async(Design*, NetScope*, NexusSet&, NetBus&, NetBus&)
|
|||
|
||||
bool NetProc::synth_sync(Design*des, NetScope*scope,
|
||||
NetNet* /* ff_clk */, NetNet* /* ff_ce */,
|
||||
NetNet* /* ff_aclr*/, NetNet* /* ff_aset*/,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const vector<NetEvProbe*>&events)
|
||||
{
|
||||
|
|
@ -1035,6 +1036,7 @@ bool NetProcTop::synth_async(Design*des)
|
|||
*/
|
||||
bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
||||
NetNet*ff_clk, NetNet*ff_ce,
|
||||
NetNet*ff_aclr,NetNet*ff_aset,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const vector<NetEvProbe*>&events_in)
|
||||
{
|
||||
|
|
@ -1064,6 +1066,7 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|||
nexa that we expect, and the tmp_out is where we want
|
||||
those outputs connected. */
|
||||
bool ok_flag = cur->synth_sync(des, scope, ff_clk, ff_ce,
|
||||
ff_aclr, ff_aset,
|
||||
tmp_set, tmp_out, events_in);
|
||||
flag = flag && ok_flag;
|
||||
|
||||
|
|
@ -1099,6 +1102,7 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|||
*/
|
||||
bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
||||
NetNet*ff_clk, NetNet*ff_ce,
|
||||
NetNet*ff_aclr,NetNet*ff_aset,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const vector<NetEvProbe*>&events_in)
|
||||
{
|
||||
|
|
@ -1118,65 +1122,71 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
|||
if (! expr_input->contains(pin_set))
|
||||
continue;
|
||||
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Forgot how to implement asynchronous set/reset." << endl;
|
||||
return false;
|
||||
#if 0
|
||||
/* Ah, this edge is in the sensitivity list for the
|
||||
expression, so we have an asynchronous
|
||||
input. Synthesize the set/reset input expression. */
|
||||
|
||||
NetNet*rst = expr_->synthesize(des);
|
||||
assert(rst->pin_count() == 1);
|
||||
// Synthesize the set/reset input expression.
|
||||
NetNet*rst = expr_->synthesize(des, scope, expr_);
|
||||
ivl_assert(*this, rst->pin_count() == 1);
|
||||
|
||||
/* XXXX I really should find a way to check that the
|
||||
edge used on the reset input is correct. This would
|
||||
involve interpreting the expression that is fed by the
|
||||
reset expression. */
|
||||
//assert(ev->edge() == NetEvProbe::POSEDGE);
|
||||
ivl_assert(*this, ev->edge() == NetEvProbe::POSEDGE);
|
||||
|
||||
/* Synthesize the true clause to figure out what
|
||||
kind of set/reset we have. */
|
||||
NetNet*asig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, nex_map->pin_count());
|
||||
asig->local_flag(true);
|
||||
// Synthesize the true clause to figure out what kind of
|
||||
// set/reset we have. This should synthesize down to a
|
||||
// constant. If not, we have an asynchronous LOAD, a
|
||||
// very different beast.
|
||||
ivl_assert(*this, if_);
|
||||
bool flag;
|
||||
NetBus tmp_out(scope, nex_out.pin_count());
|
||||
NetBus accumulated_tmp_out(scope, nex_out.pin_count());
|
||||
flag = if_->synth_async(des, scope, nex_map, tmp_out, accumulated_tmp_out);
|
||||
ivl_assert(*this, flag);
|
||||
|
||||
assert(if_ != 0);
|
||||
bool flag = if_->synth_async(des, scope, nex_map, asig);
|
||||
ivl_assert(*this, tmp_out.pin_count()==1);
|
||||
Nexus*rst_nex = tmp_out.pin(0).nexus();
|
||||
|
||||
assert(asig->pin_count() == ff->width());
|
||||
vector<bool> rst_mask = rst_nex->driven_mask();
|
||||
cerr << get_fileline() << ": NetCondit::synth_sync: "
|
||||
<< "rst_mask.size()==" << rst_mask.size()
|
||||
<< ", rst_nex->vector_width()=" << rst_nex->vector_width()
|
||||
<< endl;
|
||||
|
||||
/* Collect the set/reset value into a verinum. If
|
||||
this turns out to be entirely 0 values, then
|
||||
use the Aclr input. Otherwise, use the Aset
|
||||
input and save the set value. */
|
||||
verinum tmp (verinum::V0, ff->width());
|
||||
for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) {
|
||||
|
||||
assert(asig->pin(bit).nexus()->drivers_constant());
|
||||
tmp.set(bit, asig->pin(bit).nexus()->driven_value());
|
||||
ivl_assert(*this, rst_mask.size()==1);
|
||||
if (rst_mask[0]==false) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Asynchronous LOAD not implemented." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(tmp.is_defined());
|
||||
if (tmp.is_zero()) {
|
||||
connect(ff->pin_Aclr(), rst->pin(0));
|
||||
verinum rst_drv = rst_nex->driven_vector();
|
||||
ivl_assert(*this, rst_drv.len()==1);
|
||||
|
||||
if (rst_drv[0]==verinum::V0) {
|
||||
ivl_assert(*this, ff_aclr && ff_aclr->pin_count()==1);
|
||||
// Don't yet support multiple asynchronous reset inputs.
|
||||
ivl_assert(*this, ! ff_aclr->pin(0).is_linked());
|
||||
|
||||
ivl_assert(*this, rst->pin_count()==1);
|
||||
connect(ff_aclr->pin(0), rst->pin(0));
|
||||
|
||||
} else if (rst_drv[0]==verinum::V1) {
|
||||
ivl_assert(*this, ff_aset && ff_aset->pin_count()==1);
|
||||
// Don't yet support multiple asynchronous set inputs.
|
||||
ivl_assert(*this, ! ff_aset->pin(0).is_linked());
|
||||
|
||||
ivl_assert(*this, rst->pin_count()==1);
|
||||
connect(ff_aset->pin(0), rst->pin(0));
|
||||
|
||||
} else {
|
||||
connect(ff->pin_Aset(), rst->pin(0));
|
||||
ff->aset_value(tmp);
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Forgot how to implement asynchronous scramble (set to x/z)." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
delete asig;
|
||||
delete expr_input;
|
||||
|
||||
assert(events_in.count() == 1);
|
||||
assert(else_ != 0);
|
||||
flag = else_->synth_sync(des, scope, ff, nex_map,
|
||||
nex_out, svector<NetEvProbe*>(0))
|
||||
&& flag;
|
||||
DEBUG_SYNTH2_EXIT("NetCondit",flag)
|
||||
return flag;
|
||||
#endif
|
||||
return else_->synth_sync(des, scope, ff_clk, ff_ce,
|
||||
ff_aclr, ff_aset,
|
||||
nex_map, nex_out, vector<NetEvProbe*>(0));
|
||||
}
|
||||
|
||||
delete expr_input;
|
||||
|
|
@ -1302,13 +1312,14 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
|||
connect(ff_ce->pin(0), ce->pin(0));
|
||||
}
|
||||
|
||||
bool flag = if_->synth_sync(des, scope, ff_clk, ff_ce, nex_map, nex_out, events_in);
|
||||
bool flag = if_->synth_sync(des, scope, ff_clk, ff_ce, ff_aclr, ff_aset, nex_map, nex_out, events_in);
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool NetEvWait::synth_sync(Design*des, NetScope*scope,
|
||||
NetNet*ff_clk, NetNet*ff_ce,
|
||||
NetNet*ff_aclr,NetNet*ff_aset,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const vector<NetEvProbe*>&events_in)
|
||||
{
|
||||
|
|
@ -1390,6 +1401,7 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope,
|
|||
|
||||
/* Synthesize the input to the DFF. */
|
||||
bool flag = statement_->synth_sync(des, scope, ff_clk, ff_ce,
|
||||
ff_aclr, ff_aset,
|
||||
nex_map, nex_out, events);
|
||||
|
||||
return flag;
|
||||
|
|
@ -1424,6 +1436,14 @@ bool NetProcTop::synth_sync(Design*des)
|
|||
NetNet::TRI, &netvector_t::scalar_logic);
|
||||
ce->local_flag(true);
|
||||
|
||||
NetNet*aclr = new NetNet(scope(), scope()->local_symbol(),
|
||||
NetNet::TRI, &netvector_t::scalar_logic);
|
||||
aclr->local_flag(true);
|
||||
|
||||
NetNet*aset = new NetNet(scope(), scope()->local_symbol(),
|
||||
NetNet::TRI, &netvector_t::scalar_logic);
|
||||
aset->local_flag(true);
|
||||
|
||||
NetBus nex_d (scope(), nex_set.size());
|
||||
NetBus nex_q (scope(), nex_set.size());
|
||||
|
||||
|
|
@ -1438,7 +1458,7 @@ bool NetProcTop::synth_sync(Design*des)
|
|||
// Connect the input later.
|
||||
|
||||
/* Synthesize the input to the DFF. */
|
||||
bool flag = statement_->synth_sync(des, scope(), clock, ce,
|
||||
bool flag = statement_->synth_sync(des, scope(), clock, ce, aclr, aset,
|
||||
nex_set, nex_d,
|
||||
vector<NetEvProbe*>());
|
||||
if (! flag) {
|
||||
|
|
@ -1473,11 +1493,11 @@ bool NetProcTop::synth_sync(Design*des)
|
|||
connect(clock->pin(0), ff2->pin_Clock());
|
||||
if (ce->is_linked())
|
||||
connect(ce->pin(0), ff2->pin_Enable());
|
||||
if (aclr->is_linked())
|
||||
connect(aclr->pin(0), ff2->pin_Aclr());
|
||||
if (aset->is_linked())
|
||||
connect(aset->pin(0), ff2->pin_Aset());
|
||||
#if 0
|
||||
if (ff->pin_Aset().is_linked())
|
||||
connect(ff->pin_Aset(), ff2->pin_Aset());
|
||||
if (ff->pin_Aclr().is_linked())
|
||||
connect(ff->pin_Aclr(), ff2->pin_Aclr());
|
||||
if (ff->pin_Sset().is_linked())
|
||||
connect(ff->pin_Sset(), ff2->pin_Sset());
|
||||
if (ff->pin_Sclr().is_linked())
|
||||
|
|
|
|||
|
|
@ -517,8 +517,28 @@ static void show_lpm_ff(ivl_lpm_t net)
|
|||
}
|
||||
}
|
||||
|
||||
if (ivl_lpm_async_clr(net)) {
|
||||
nex = ivl_lpm_async_clr(net);
|
||||
fprintf(out, " Aclr: %p\n", nex);
|
||||
if (width_of_nexus(nex) != 1) {
|
||||
fprintf(out, " Aclr: ERROR: Nexus width is %u\n",
|
||||
width_of_nexus(nex));
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ivl_lpm_async_set(net)) {
|
||||
nex = ivl_lpm_async_set(net);
|
||||
fprintf(out, " Aset: %p\n", nex);
|
||||
if (width_of_nexus(nex) != 1) {
|
||||
fprintf(out, " Aset: ERROR: Nexus width is %u\n",
|
||||
width_of_nexus(nex));
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
nex = ivl_lpm_data(net,0);
|
||||
fprintf(out, " D: %p\n", nex);
|
||||
fprintf(out, " D: %p\n", nex);
|
||||
if (width_of_nexus(nex) != width) {
|
||||
fprintf(out, " D: ERROR: Nexus width is %u\n",
|
||||
width_of_nexus(nex));
|
||||
|
|
@ -526,7 +546,7 @@ static void show_lpm_ff(ivl_lpm_t net)
|
|||
}
|
||||
|
||||
nex = ivl_lpm_q(net);
|
||||
fprintf(out, " Q: %p\n", nex);
|
||||
fprintf(out, " Q: %p\n", nex);
|
||||
if (width_of_nexus(nex) != width) {
|
||||
fprintf(out, " Q: ERROR: Nexus width is %u\n",
|
||||
width_of_nexus(nex));
|
||||
|
|
|
|||
|
|
@ -1724,10 +1724,16 @@ static void draw_lpm_ff(ivl_lpm_t net)
|
|||
* generator in V0.10 and later for how this might be done. */
|
||||
assert(ivl_lpm_sync_clr(net) == 0);
|
||||
assert(ivl_lpm_sync_set(net) == 0);
|
||||
assert(ivl_lpm_async_clr(net) == 0);
|
||||
assert(ivl_lpm_async_set(net) == 0);
|
||||
|
||||
fprintf(vvp_out, "L_%p .dff ", net);
|
||||
if (ivl_lpm_async_clr(net)) {
|
||||
assert(! ivl_lpm_async_set(net));
|
||||
fprintf(vvp_out, "L_%p .dff/aclr ", net);
|
||||
} else if (ivl_lpm_async_set(net)) {
|
||||
assert(! ivl_lpm_async_clr(net));
|
||||
fprintf(vvp_out, "L_%p .dff/aset ", net);
|
||||
} else {
|
||||
fprintf(vvp_out, "L_%p .dff ", net);
|
||||
}
|
||||
|
||||
nex = ivl_lpm_data(net,0);
|
||||
assert(nex);
|
||||
|
|
@ -1747,8 +1753,13 @@ static void draw_lpm_ff(ivl_lpm_t net)
|
|||
fprintf(vvp_out, ", C4<1>");
|
||||
}
|
||||
|
||||
/* Stub asynchronous input for now. */
|
||||
fprintf(vvp_out, ", C4<z>");
|
||||
if ( (nex = ivl_lpm_async_clr(net)) ) {
|
||||
fprintf(vvp_out, ", %s", draw_net_input(nex));
|
||||
}
|
||||
|
||||
if ( (nex = ivl_lpm_async_set(net)) ) {
|
||||
fprintf(vvp_out, ", %s", draw_net_input(nex));
|
||||
}
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,16 +192,18 @@ The Verilog language itself does not have a DFF primitive, but post
|
|||
synthesis readily creates DFF devices that are best simulated with a
|
||||
common device. Thus, there is the DFF statement to create DFF devices:
|
||||
|
||||
<label> .dff <d>, <clk>, <ce>, <async-input>;
|
||||
<label> .dff <d>, <clk>, <ce>;
|
||||
<label> .dff/aclr <d>, <clk>, <ce>, <async-input>;
|
||||
<label> .dff/aset <d>, <clk>, <ce>, <async-input>;
|
||||
|
||||
The generated functor is generally synchronous on the <clk> rising
|
||||
edge of <clk>, with the <ce> enable active high. The <clk> and <ce>
|
||||
are single bit vectors (or scalars) on ports 1 and 2. Port-0 is any
|
||||
type of datum at all. The device will transfer the input to the output
|
||||
when it is loaded by a clock. The <async-input> is a special
|
||||
asynchronous input that is immediately stored and transferred to the
|
||||
output when data arrives here. This is useful for implementing
|
||||
asynchronous set/clear functions.
|
||||
asynchronous input that on the rising edge causes the device to
|
||||
clear/set, and force the output to propagate. Thus, they implement DFF
|
||||
with asynchronous clr or set.
|
||||
|
||||
UDP STATEMENTS:
|
||||
|
||||
|
|
|
|||
|
|
@ -207,8 +207,18 @@ extern void compile_cmp_gt_r(char*label, unsigned argc, struct symb_s*argv);
|
|||
extern void compile_dff(char*label,
|
||||
struct symb_s arg_d,
|
||||
struct symb_s arg_c,
|
||||
struct symb_s arg_e,
|
||||
struct symb_s arg_a);
|
||||
struct symb_s arg_e);
|
||||
|
||||
extern void compile_dff_aclr(char*label,
|
||||
struct symb_s arg_d,
|
||||
struct symb_s arg_c,
|
||||
struct symb_s arg_e,
|
||||
struct symb_s arg_a);
|
||||
extern void compile_dff_aset(char*label,
|
||||
struct symb_s arg_d,
|
||||
struct symb_s arg_c,
|
||||
struct symb_s arg_e,
|
||||
struct symb_s arg_a);
|
||||
|
||||
extern void compile_enum2_type(char*label, long width, bool signed_flag,
|
||||
std::list<struct enum_name_s>*names);
|
||||
|
|
|
|||
119
vvp/dff.cc
119
vvp/dff.cc
|
|
@ -65,29 +65,122 @@ void vvp_dff::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
|||
break;
|
||||
|
||||
case 3: // Asynch-D
|
||||
// FIXME! The code generator is writing an input C4<z>
|
||||
// no matter what the intent of this device. This is
|
||||
// almost certainly NOT correct, nor do we want to
|
||||
// propagate that. But that needs to be fixed later.
|
||||
if (bit.size() == 1 && bit.value(0)==BIT4_Z)
|
||||
break;
|
||||
if (d_.size() > bit.size())
|
||||
d_ .copy_bits(bit);
|
||||
else
|
||||
d_ = bit;
|
||||
port.ptr()->send_vec4(d_, 0);
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The recv_clear and recv_set function respond to asynchronout
|
||||
* clear/set input by propagating the desired output.
|
||||
*
|
||||
* NOTE: Don't touch the d_ value, because that tracks the D input,
|
||||
* which may be needed when the device is clocked afterwards.
|
||||
*/
|
||||
void vvp_dff::recv_clear(vvp_net_ptr_t port)
|
||||
{
|
||||
vvp_vector4_t tmp = d_;
|
||||
for (unsigned idx = 0 ; idx < d_.size() ; idx += 1)
|
||||
tmp.set_bit(idx, BIT4_0);
|
||||
|
||||
port.ptr()->send_vec4(tmp, 0);
|
||||
}
|
||||
|
||||
void vvp_dff::recv_set(vvp_net_ptr_t port)
|
||||
{
|
||||
vvp_vector4_t tmp = d_;
|
||||
for (unsigned idx = 0 ; idx < d_.size() ; idx += 1)
|
||||
tmp.set_bit(idx, BIT4_1);
|
||||
|
||||
port.ptr()->send_vec4(tmp, 0);
|
||||
}
|
||||
|
||||
vvp_dff_aclr::vvp_dff_aclr(bool invert_clk, bool invert_ce)
|
||||
: vvp_dff(invert_clk, invert_ce)
|
||||
{
|
||||
a_ = BIT4_X;
|
||||
}
|
||||
|
||||
void vvp_dff_aclr::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
||||
vvp_context_t ctx)
|
||||
{
|
||||
if (port.port() == 3) {
|
||||
|
||||
assert(bit.size()==1);
|
||||
if (a_ == bit.value(0))
|
||||
return;
|
||||
|
||||
a_ = bit.value(0);
|
||||
recv_clear(port);
|
||||
|
||||
} else {
|
||||
vvp_dff::recv_vec4(port, bit, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
vvp_dff_aset::vvp_dff_aset(bool invert_clk, bool invert_ce)
|
||||
: vvp_dff(invert_clk, invert_ce)
|
||||
{
|
||||
a_ = BIT4_X;
|
||||
}
|
||||
|
||||
void vvp_dff_aset::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
||||
vvp_context_t ctx)
|
||||
{
|
||||
if (port.port() == 3) {
|
||||
|
||||
assert(bit.size()==1);
|
||||
if (a_ == bit.value(0))
|
||||
return;
|
||||
|
||||
a_ = bit.value(0);
|
||||
recv_set(port);
|
||||
|
||||
} else {
|
||||
vvp_dff::recv_vec4(port, bit, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void compile_dff(char*label, struct symb_s arg_d,
|
||||
struct symb_s arg_c,
|
||||
struct symb_s arg_e,
|
||||
struct symb_s arg_a)
|
||||
struct symb_s arg_e)
|
||||
{
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
vvp_dff*fun = new vvp_dff(false, false);
|
||||
|
||||
ptr->fun = fun;
|
||||
define_functor_symbol(label, ptr);
|
||||
free(label);
|
||||
input_connect(ptr, 0, arg_d.text);
|
||||
input_connect(ptr, 1, arg_c.text);
|
||||
input_connect(ptr, 2, arg_e.text);
|
||||
}
|
||||
|
||||
void compile_dff_aclr(char*label, struct symb_s arg_d,
|
||||
struct symb_s arg_c,
|
||||
struct symb_s arg_e,
|
||||
struct symb_s arg_a)
|
||||
{
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
vvp_dff*fun = new vvp_dff_aclr(false, false);
|
||||
|
||||
ptr->fun = fun;
|
||||
define_functor_symbol(label, ptr);
|
||||
free(label);
|
||||
input_connect(ptr, 0, arg_d.text);
|
||||
input_connect(ptr, 1, arg_c.text);
|
||||
input_connect(ptr, 2, arg_e.text);
|
||||
input_connect(ptr, 3, arg_a.text);
|
||||
}
|
||||
|
||||
void compile_dff_aset(char*label, struct symb_s arg_d,
|
||||
struct symb_s arg_c,
|
||||
struct symb_s arg_e,
|
||||
struct symb_s arg_a)
|
||||
{
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
vvp_dff*fun = new vvp_dff_aset(false, false);
|
||||
|
||||
ptr->fun = fun;
|
||||
define_functor_symbol(label, ptr);
|
||||
free(label);
|
||||
|
|
|
|||
26
vvp/dff.h
26
vvp/dff.h
|
|
@ -42,6 +42,10 @@ class vvp_dff : public vvp_net_fun_t {
|
|||
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
||||
vvp_context_t);
|
||||
|
||||
protected:
|
||||
void recv_clear(vvp_net_ptr_t port);
|
||||
void recv_set(vvp_net_ptr_t port);
|
||||
|
||||
private:
|
||||
bool iclk_, ice_;
|
||||
vvp_bit4_t clk_cur_;
|
||||
|
|
@ -49,4 +53,26 @@ class vvp_dff : public vvp_net_fun_t {
|
|||
vvp_vector4_t d_;
|
||||
};
|
||||
|
||||
class vvp_dff_aclr : public vvp_dff {
|
||||
|
||||
public:
|
||||
explicit vvp_dff_aclr(bool invert_clk =false, bool invert_ce =false);
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
||||
vvp_context_t);
|
||||
private:
|
||||
vvp_bit4_t a_;
|
||||
};
|
||||
|
||||
class vvp_dff_aset : public vvp_dff {
|
||||
|
||||
public:
|
||||
explicit vvp_dff_aset(bool invert_clk =false, bool invert_ce =false);
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
||||
vvp_context_t);
|
||||
private:
|
||||
vvp_bit4_t a_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -151,6 +151,8 @@ static char* strdupnew(char const *str)
|
|||
".concat8" { return K_CONCAT8; }
|
||||
".delay" { return K_DELAY; }
|
||||
".dff" { return K_DFF; }
|
||||
".dff/aclr" { return K_DFF_ACLR; }
|
||||
".dff/aset" { return K_DFF_ASET; }
|
||||
".enum2" { return K_ENUM2; }
|
||||
".enum2/s" { return K_ENUM2_S; }
|
||||
".enum4" { return K_ENUM4; }
|
||||
|
|
|
|||
14
vvp/parse.y
14
vvp/parse.y
|
|
@ -83,7 +83,7 @@ static struct __vpiModPath*modpath_dst = 0;
|
|||
%token K_CMP_EEQ K_CMP_EQ K_CMP_EQX K_CMP_EQZ
|
||||
%token K_CMP_EQ_R K_CMP_NEE K_CMP_NE K_CMP_NE_R
|
||||
%token K_CMP_GE K_CMP_GE_R K_CMP_GE_S K_CMP_GT K_CMP_GT_R K_CMP_GT_S
|
||||
%token K_CONCAT K_CONCAT8 K_DEBUG K_DELAY K_DFF
|
||||
%token K_CONCAT K_CONCAT8 K_DEBUG K_DELAY K_DFF K_DFF_ACLR K_DFF_ASET
|
||||
%token K_ENUM2 K_ENUM2_S K_ENUM4 K_ENUM4_S K_EVENT K_EVENT_OR
|
||||
%token K_EXPORT K_EXTEND_S K_FUNCTOR K_IMPORT K_ISLAND K_MODPATH
|
||||
%token K_NET K_NET_S K_NET_R K_NET_2S K_NET_2U
|
||||
|
|
@ -491,10 +491,16 @@ statement
|
|||
modpath_src_list ';'
|
||||
{ modpath_dst = 0; }
|
||||
|
||||
/* DFF nodes have an output and take exactly 4 inputs. */
|
||||
/* DFF nodes have an output and take up to 4 inputs. */
|
||||
|
||||
| T_LABEL K_DFF symbol ',' symbol ',' symbol ',' symbol ';'
|
||||
{ compile_dff($1, $3, $5, $7, $9); }
|
||||
| T_LABEL K_DFF symbol ',' symbol ',' symbol ';'
|
||||
{ compile_dff($1, $3, $5, $7); }
|
||||
|
||||
| T_LABEL K_DFF_ACLR symbol ',' symbol ',' symbol ',' symbol ';'
|
||||
{ compile_dff_aclr($1, $3, $5, $7, $9); }
|
||||
|
||||
| T_LABEL K_DFF_ASET symbol ',' symbol ',' symbol ',' symbol ';'
|
||||
{ compile_dff_aset($1, $3, $5, $7, $9); }
|
||||
|
||||
/* The various reduction operator nodes take a single input. */
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue