diff --git a/ivl_target.h b/ivl_target.h index a5d27ed80..216ed39a2 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -336,7 +336,8 @@ typedef enum ivl_lpm_type_e { IVL_LPM_SUB = 8, IVL_LPM_SUBSTITUTE=39, /* IVL_LPM_RAM = 9, / obsolete */ - IVL_LPM_UFUNC = 14 + IVL_LPM_UFUNC = 14, + IVL_LPM_LATCH = 40 } ivl_lpm_type_t; /* The path edge type is the edge type used to select a specific @@ -1313,6 +1314,11 @@ extern unsigned ivl_lpm_lineno(ivl_lpm_t net); * single ivl_lpm_data input are the same with, ivl_lpm_width. This * device carries a vector like other LPM devices. * + * - Latch (IVL_LPM_LATCH) + * This data is an asynchronous latch. The ivl_lpm_q output and + * single ivl_lpm_data input are the same with, ivl_lpm_width. This + * device carries a vector like other LPM devices. + * * - Memory port (IVL_LPM_RAM) (deprecated in favor of IVL_LPM_ARRAY) * These are structural ports into a memory device. They represent * address/data ports of a memory device that the context can hook to @@ -1428,18 +1434,18 @@ extern unsigned ivl_lpm_negedge(ivl_lpm_t net); extern ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net); /* IVL_LPM_UFUNC */ extern ivl_scope_t ivl_lpm_define(ivl_lpm_t net); - /* IVL_LPM_FF */ + /* IVL_LPM_FF IVL_LPM_LATCH*/ extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net); /* IVL_LPM_ADD IVL_LPM_CONCAT IVL_LPM_FF IVL_LPM_PART IVL_LPM_MULT IVL_LPM_MUX IVL_LPM_POW IVL_LPM_SHIFTL IVL_LPM_SHIFTR IVL_LPM_SUB - IVL_LPM_UFUNC IVL_LPM_SUBSTITUTE */ + IVL_LPM_UFUNC IVL_LPM_SUBSTITUTE IVL_LPM_LATCH*/ extern ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx); /* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_POW IVL_LPM_SUB IVL_LPM_CMP_EQ IVL_LPM_CMP_EEQ IVL_LPM_CMP_EQX IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE */ extern ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx); /* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_PART IVL_LPM_POW IVL_LPM_SUB IVL_LPM_UFUNC IVL_LPM_CMP_EEQ IVL_LPM_CMP_EQX - IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE IVL_LPM_SUBSTITUTE */ + IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE IVL_LPM_SUBSTITUTE IVL_LPM_LATCH*/ extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net); extern ivl_drive_t ivl_lpm_drive0(ivl_lpm_t net); extern ivl_drive_t ivl_lpm_drive1(ivl_lpm_t net); diff --git a/t-dll-api.cc b/t-dll-api.cc index 8cad0a4af..b739bd79b 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1148,6 +1148,8 @@ extern "C" ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net) switch (net->type) { case IVL_LPM_FF: return net->u_.ff.we; + case IVL_LPM_LATCH: + return net->u_.latch.we; default: assert(0); return 0; @@ -1220,6 +1222,9 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx) case IVL_LPM_FF: assert(idx == 0); return net->u_.ff.d.pin; + case IVL_LPM_LATCH: + assert(idx == 0); + return net->u_.latch.d.pin; case IVL_LPM_CONCAT: case IVL_LPM_CONCATZ: @@ -1344,6 +1349,8 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net) case IVL_LPM_FF: return net->u_.ff.q.pin; + case IVL_LPM_LATCH: + return net->u_.latch.q.pin; case IVL_LPM_MUX: return net->u_.mux.q; diff --git a/t-dll.cc b/t-dll.cc index 93564e854..52bb17581 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -2051,6 +2051,45 @@ void dll_target::lpm_ff(const NetFF*net) nexus_lpm_add(obj->u_.ff.d.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); } +void dll_target::lpm_latch(const NetLatch*net) +{ + ivl_lpm_t obj = new struct ivl_lpm_s; + obj->type = IVL_LPM_LATCH; + obj->name = net->name(); + obj->scope = find_scope(des_, net->scope()); + assert(obj->scope); + FILE_NAME(obj, net); + + obj->width = net->width(); + + scope_add_lpm(obj->scope, obj); + + const Nexus*nex; + + /* If there is a clock enable, then connect it up to the FF + device. */ + if (net->pin_Enable().is_linked()) { + nex = net->pin_Enable().nexus(); + assert(nex->t_cookie()); + obj->u_.latch.we = nex->t_cookie(); + assert(obj->u_.latch.we); + nexus_lpm_add(obj->u_.latch.we, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + } else { + obj->u_.latch.we = 0; + } + + nex = net->pin_Q().nexus(); + assert(nex->t_cookie()); + obj->u_.latch.q.pin = nex->t_cookie(); + nexus_lpm_add(obj->u_.latch.q.pin, obj, 0, + IVL_DR_STRONG, IVL_DR_STRONG); + + nex = net->pin_Data().nexus(); + assert(nex->t_cookie()); + obj->u_.latch.d.pin = nex->t_cookie(); + nexus_lpm_add(obj->u_.latch.d.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); +} + /* * Make the NetMult object into an IVL_LPM_MULT node. */ diff --git a/t-dll.h b/t-dll.h index a94137383..7baa9263c 100644 --- a/t-dll.h +++ b/t-dll.h @@ -76,6 +76,7 @@ struct dll_target : public target_t, public expr_scan_t { void lpm_compare(const NetCompare*); void lpm_divide(const NetDivide*); void lpm_ff(const NetFF*); + void lpm_latch(const NetLatch*); void lpm_modulo(const NetModulo*); void lpm_mult(const NetMult*); void lpm_mux(const NetMux*); @@ -388,6 +389,18 @@ struct ivl_lpm_s { ivl_expr_t aset_value; ivl_expr_t sset_value; } ff; + struct ivl_lpm_latch_s { + unsigned negedge_flag :1; + ivl_nexus_t we; + union { + ivl_nexus_t*pins; + ivl_nexus_t pin; + } q; + union { + ivl_nexus_t*pins; + ivl_nexus_t pin; + } d; + } latch; struct ivl_lpm_mux_s { unsigned size;