diff --git a/Makefile.in b/Makefile.in index e71560311..76d154871 100644 --- a/Makefile.in +++ b/Makefile.in @@ -114,7 +114,7 @@ O = main.o async.o design_dump.o dup_expr.o elaborate.o elab_expr.o \ elab_lval.o elab_net.o elab_anet.o elab_pexpr.o elab_scope.o \ elab_sig.o emit.o eval.o eval_attrib.o \ eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \ -load_module.o netlist.o NetLatch.o netmisc.o net_assign.o \ +load_module.o netlist.o netmisc.o net_assign.o \ net_design.o net_event.o net_expr.o net_force.o net_func.o \ net_link.o net_modulo.o net_nex_input.o net_nex_output.o \ net_proc.o net_scope.o net_udp.o net_variable.o pad_to_width.o \ diff --git a/NetLatch.cc b/NetLatch.cc deleted file mode 100644 index e8b808a84..000000000 --- a/NetLatch.cc +++ /dev/null @@ -1,48 +0,0 @@ -// NetLatch.cc -// Author: Alan M. Feldstein -// Class NetLatch member-function definitions - -#include "NetLatch.h" // NetLatch class definition -#include "target.h" // target_t structure definition - -// constructor -NetLatch::NetLatch( NetScope *scope, perm_string name, unsigned width ) - // explicitly call base-class constructor - : NetNode( scope, name, 2U * width + 1U ) -{ -} // end NetLatch constructor - -unsigned NetLatch::width() const -{ - return ( pin_count() - 1U ) / 2U; -} // end function width - -Link &NetLatch::pin_Data( unsigned w ) -{ - unsigned pn = 1 + 2 * w; - assert( pn < pin_count() ); - return pin( pn ); -} // end function pin_Data - -Link &NetLatch::pin_Q( unsigned w ) -{ - unsigned pn = 2 + 2 * w; - assert( pn < pin_count() ); - return pin( pn ); -} // end function pin_Q - -Link &NetLatch::pin_Gate() -{ - return pin( 0 ); -} // end function pin_Gate - -const Link &NetLatch::pin_Gate() const -{ - return pin( 0 ); -} // end function pin_Gate - -bool NetLatch::emit_node( target_t *driverPtr ) const -{ - driverPtr->lpm_latch( this ); - return true; -} // end function emit_node diff --git a/NetLatch.h b/NetLatch.h deleted file mode 100644 index e78f5be5b..000000000 --- a/NetLatch.h +++ /dev/null @@ -1,34 +0,0 @@ -// NetLatch.h -// Author: Alan M. Feldstein -// This class represents an LPM_LATCH device. In Verilog, storage components of this type can be inferred. -// The pinout is assigned like so: -// 0 -- Gate -// -// 1 -- Data[0] -// 2 -- Q[0] -// ... -#ifndef NETLATCH_H -#define NETLATCH_H - -#include "netlist.h" // NetNode, NetScope, Link class definitions -#include "StringHeap.h" // perm_string class definition - -class NetLatch : public NetNode -{ - public: - NetLatch( NetScope *, perm_string, unsigned ); - - unsigned width() const; - - Link &pin_Data( unsigned ); - Link &pin_Q( unsigned ); - Link &pin_Gate(); - - const Link &pin_Data( unsigned ) const; - const Link &pin_Q( unsigned ) const; - const Link &pin_Gate() const; - - virtual bool emit_node( target_t * ) const; -}; // end class NetLatch - -#endif diff --git a/cprop.cc b/cprop.cc index 64921523f..cd6fc5ac4 100644 --- a/cprop.cc +++ b/cprop.cc @@ -307,10 +307,8 @@ void cprop_functor::lpm_ff(Design*des, NetFF*obj) obj->width()-unlinked_count); connect(tmp->pin_Clock(), obj->pin_Clock()); connect(tmp->pin_Enable(), obj->pin_Enable()); - connect(tmp->pin_Aload(), obj->pin_Aload()); connect(tmp->pin_Aset(), obj->pin_Aset()); connect(tmp->pin_Aclr(), obj->pin_Aclr()); - connect(tmp->pin_Sload(), obj->pin_Sload()); connect(tmp->pin_Sset(), obj->pin_Sset()); connect(tmp->pin_Sclr(), obj->pin_Sclr()); diff --git a/design_dump.cc b/design_dump.cc index 0b230b69a..f9523a463 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -301,6 +301,16 @@ void NetFF::dump_node(ostream&o, unsigned ind) const dump_obj_attr(o, ind+4); } +void NetLatch::dump_node(ostream&o, unsigned ind) const +{ + o << setw(ind) << "" << "LPM_LATCH: " << name() + << " scope=" << (scope()? scope()->name() : "") + << " aset_value=" << aset_value_ << endl; + + dump_node_pins(o, ind+4); + dump_obj_attr(o, ind+4); +} + void NetLogic::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "logic: "; diff --git a/emit.cc b/emit.cc index fcf1199b0..6b96174b8 100644 --- a/emit.cc +++ b/emit.cc @@ -112,6 +112,12 @@ bool NetForce::emit_node(struct target_t*tgt) const return true; } +bool NetLatch::emit_node(struct target_t*tgt) const +{ + tgt->lpm_latch(this); + return true; +} + bool NetModulo::emit_node(struct target_t*tgt) const { tgt->lpm_modulo(this); diff --git a/functor.cc b/functor.cc index cabe02785..537c99934 100644 --- a/functor.cc +++ b/functor.cc @@ -64,6 +64,10 @@ void functor_t::lpm_ff(class Design*, class NetFF*) { } +void functor_t::lpm_latch(class Design*, class NetLatch*) +{ +} + void functor_t::lpm_logic(class Design*, class NetLogic*) { } @@ -186,6 +190,11 @@ void NetFF::functor_node(Design*des, functor_t*fun) fun->lpm_ff(des, this); } +void NetLatch::functor_node(Design*des, functor_t*fun) +{ + fun->lpm_latch(des, this); +} + void NetLogic::functor_node(Design*des, functor_t*fun) { fun->lpm_logic(des, this); diff --git a/functor.h b/functor.h index 7e6552483..e7c43272c 100644 --- a/functor.h +++ b/functor.h @@ -66,6 +66,9 @@ struct functor_t { /* This method is called for each FF in the design. */ virtual void lpm_ff(class Design*des, class NetFF*); + /* This method is called for each latch in the design. */ + virtual void lpm_latch(class Design*des, class NetLatch*); + /* Handle LPM combinational logic devices. */ virtual void lpm_logic(class Design*des, class NetLogic*); diff --git a/ivl_target.h b/ivl_target.h index e62076edb..79f3ea9a2 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -738,17 +738,16 @@ extern unsigned ivl_lpm_width(ivl_lpm_t net); extern unsigned ivl_lpm_attr_cnt(ivl_lpm_t net); extern ivl_attribute_t ivl_lpm_attr_val(ivl_lpm_t net, unsigned idx); - /* IVL_LPM_FF */ + /* IVL_LPM_FF IVL_LPM_LATCH*/ extern ivl_nexus_t ivl_lpm_async_clr(ivl_lpm_t net); extern ivl_nexus_t ivl_lpm_async_set(ivl_lpm_t net); extern ivl_expr_t ivl_lpm_aset_value(ivl_lpm_t net); + /* IVL_LPM_FF */ extern ivl_nexus_t ivl_lpm_sync_clr(ivl_lpm_t net); extern ivl_nexus_t ivl_lpm_sync_set(ivl_lpm_t net); extern ivl_expr_t ivl_lpm_sset_value(ivl_lpm_t net); - /* IVL_LPM_FF IVL_LPM_RAM */ + /* IVL_LPM_FF IVL_LPM_LATCH IVL_LPM_RAM */ extern ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net); -/* IVL_LPM_LATCH */ -extern ivl_nexus_t ivl_lpm_gate( ivl_lpm_t netPtr ); /* IVL_LPM_FF */ extern ivl_lpm_t ivl_lpm_decode(ivl_lpm_t net); /* IVL_LPM_UFUNC */ diff --git a/netlist.cc b/netlist.cc index 2fc48538f..08c19439d 100644 --- a/netlist.cc +++ b/netlist.cc @@ -540,20 +540,18 @@ const NetScope* NetProcTop::scope() const * like so: * 0 -- Clock * 1 -- Enable - * 2 -- Aload - * 3 -- Aset - * 4 -- Aclr - * 5 -- Sload - * 6 -- Sset - * 7 -- Sclr + * 2 -- Aset + * 3 -- Aclr + * 4 -- Sset + * 5 -- Sclr * - * 8 -- Data[0] - * 9 -- Q[0] + * 6 -- Data[0] + * 7 -- Q[0] * ... */ NetFF::NetFF(NetScope*s, perm_string n, unsigned wid) -: NetNode(s, n, 8 + 2*wid) +: NetNode(s, n, 6 + 2*wid) { demux_ = 0; @@ -561,14 +559,10 @@ NetFF::NetFF(NetScope*s, perm_string n, unsigned wid) pin_Clock().set_name(perm_string::literal("Clock"), 0); pin_Enable().set_dir(Link::INPUT); pin_Enable().set_name(perm_string::literal("Enable"), 0); - pin_Aload().set_dir(Link::INPUT); - pin_Aload().set_name(perm_string::literal("Aload"), 0); pin_Aset().set_dir(Link::INPUT); pin_Aset().set_name(perm_string::literal("Aset"), 0); pin_Aclr().set_dir(Link::INPUT); pin_Aclr().set_name(perm_string::literal("Aclr"), 0); - pin_Sload().set_dir(Link::INPUT); - pin_Sload().set_name(perm_string::literal("Sload"), 0); pin_Sset().set_dir(Link::INPUT); pin_Sset().set_name(perm_string::literal("Sset"), 0); pin_Sclr().set_dir(Link::INPUT); @@ -587,7 +581,7 @@ NetFF::~NetFF() unsigned NetFF::width() const { - return (pin_count() - 8) / 2; + return (pin_count() - 6) / 2; } Link& NetFF::pin_Clock() @@ -610,80 +604,70 @@ const Link& NetFF::pin_Enable() const return pin(1); } -Link& NetFF::pin_Aload() +Link& NetFF::pin_Aset() { return pin(2); } -Link& NetFF::pin_Aset() -{ - return pin(3); -} - const Link& NetFF::pin_Aset() const { - return pin(3); + return pin(2); } Link& NetFF::pin_Aclr() { - return pin(4); + return pin(3); } const Link& NetFF::pin_Aclr() const { - return pin(4); -} - -Link& NetFF::pin_Sload() -{ - return pin(5); + return pin(3); } Link& NetFF::pin_Sset() { - return pin(6); + return pin(4); } const Link& NetFF::pin_Sset() const { - return pin(6); + return pin(4); } Link& NetFF::pin_Sclr() { - return pin(7); + return pin(5); } const Link& NetFF::pin_Sclr() const { - return pin(7); + return pin(5); } Link& NetFF::pin_Data(unsigned w) { - unsigned pn = 8 + 2*w; + unsigned pn = 6 + 2*w; assert(pn < pin_count()); return pin(pn); } const Link& NetFF::pin_Data(unsigned w) const { - unsigned pn = 8 + 2*w; + unsigned pn = 6 + 2*w; assert(pn < pin_count()); return pin(pn); } Link& NetFF::pin_Q(unsigned w) { - unsigned pn = 9 + w*2; + unsigned pn = 7 + w*2; assert(pn < pin_count()); return pin(pn); } const Link& NetFF::pin_Q(unsigned w) const { - unsigned pn = 9 + w*2; + unsigned pn = 7 + w*2; assert(pn < pin_count()); return pin(pn); } @@ -718,6 +702,111 @@ unsigned NetDecode::awidth() const return pin_count(); } +/* + * The NetLatch class represents an LPM_LATCH device. The pinout is assigned + * like so: + * 0 -- Clock (Gate) + * 1 -- Aset + * 2 -- Aclr + * + * 3 -- Data[0] + * 4 -- Q[0] + * ... + */ +NetLatch::NetLatch(NetScope*s, perm_string n, unsigned wid) +: NetNode(s, n, 3 + 2*wid) +{ + pin_Clock().set_dir(Link::INPUT); + pin_Clock().set_name(perm_string::literal("Clock"), 0); + pin_Aset().set_dir(Link::INPUT); + pin_Aset().set_name(perm_string::literal("Aset"), 0); + pin_Aclr().set_dir(Link::INPUT); + pin_Aclr().set_name(perm_string::literal("Aclr"), 0); + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + pin_Data(idx).set_dir(Link::INPUT); + pin_Data(idx).set_name(perm_string::literal("Data"), idx); + pin_Q(idx).set_dir(Link::OUTPUT); + pin_Q(idx).set_name(perm_string::literal("Q"), idx); + } +} + +NetLatch::~NetLatch() +{ +} + +unsigned NetLatch::width() const +{ + return (pin_count() - 3) / 2; +} + +Link& NetLatch::pin_Clock() +{ + return pin(0); +} + +const Link& NetLatch::pin_Clock() const +{ + return pin(0); +} + +Link& NetLatch::pin_Aset() +{ + return pin(1); +} + +const Link& NetLatch::pin_Aset() const +{ + return pin(1); +} + +Link& NetLatch::pin_Aclr() +{ + return pin(2); +} + +const Link& NetLatch::pin_Aclr() const +{ + return pin(2); +} + +Link& NetLatch::pin_Data(unsigned w) +{ + unsigned pn = 3 + 2*w; + assert(pn < pin_count()); + return pin(pn); +} + +const Link& NetLatch::pin_Data(unsigned w) const +{ + unsigned pn = 3 + 2*w; + assert(pn < pin_count()); + return pin(pn); +} + +Link& NetLatch::pin_Q(unsigned w) +{ + unsigned pn = 4 + w*2; + assert(pn < pin_count()); + return pin(pn); +} + +const Link& NetLatch::pin_Q(unsigned w) const +{ + unsigned pn = 4 + w*2; + assert(pn < pin_count()); + return pin(pn); +} + +void NetLatch::aset_value(const verinum&val) +{ + aset_value_ = val; +} + +const verinum& NetLatch::aset_value() const +{ + return aset_value_; +} + NetDemux::NetDemux(NetScope*s, perm_string name, unsigned bus_width, unsigned address_width, unsigned size) : NetNode(s, name, bus_width*2+address_width+bus_width/size) diff --git a/netlist.h b/netlist.h index d27020779..305529394 100644 --- a/netlist.h +++ b/netlist.h @@ -777,13 +777,10 @@ class NetFF : public NetNode { Link& pin_Clock(); Link& pin_Enable(); - Link& pin_Aload(); Link& pin_Aset(); Link& pin_Aclr(); - Link& pin_Sload(); Link& pin_Sset(); Link& pin_Sclr(); - Link& pin_Data(unsigned); Link& pin_Q(unsigned); @@ -820,6 +817,41 @@ class NetFF : public NetNode { verinum sset_value_; }; +/* + * This class represents an LPM_LATCH device. There is no literal gate + * type in Verilog that maps, but gates of this type can be inferred. + */ +class NetLatch : public NetNode { + + public: + NetLatch(NetScope*s, perm_string n, unsigned width); + ~NetLatch(); + + unsigned width() const; + + Link& pin_Clock(); + Link& pin_Aset(); + Link& pin_Aclr(); + Link& pin_Data(unsigned); + Link& pin_Q(unsigned); + + const Link& pin_Aset() const; + const Link& pin_Aclr() const; + const Link& pin_Clock() const; + const Link& pin_Data(unsigned) const; + const Link& pin_Q(unsigned) const; + + void aset_value(const verinum&val); + const verinum& aset_value() const; + + virtual void dump_node(ostream&, unsigned ind) const; + virtual bool emit_node(struct target_t*) const; + virtual void functor_node(Design*des, functor_t*fun); + + private: + verinum aset_value_; +}; + /* * This class represents the declared memory object. The parser diff --git a/synth2.cc b/synth2.cc index db447562c..2920f045b 100644 --- a/synth2.cc +++ b/synth2.cc @@ -23,7 +23,6 @@ # include "netlist.h" # include "compiler.h" #include -#include "NetLatch.h" #include #include @@ -225,7 +224,7 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag, unsigned ptr = static_cast< unsigned >( tmp ); connect( latchPtr->pin_Data( idx ), rsig->pin( roff + idx ) ); connect( nex_out->pin( ptr ), latchPtr->pin_Q( idx ) ); - connect( latchPtr->pin_Gate(), gsig->pin( 0 ) ); + connect( latchPtr->pin_Clock(), gsig->pin( 0 ) ); } des->add_node( latchPtr ); diff --git a/t-dll-api.cc b/t-dll-api.cc index a36bb733a..c600303fc 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -644,6 +644,7 @@ extern "C" ivl_nexus_t ivl_lpm_async_clr(ivl_lpm_t net) assert(net); switch(net->type) { case IVL_LPM_FF: + case IVL_LPM_LATCH: return net->u_.ff.aclr; default: assert(0); @@ -668,6 +669,7 @@ extern "C" ivl_nexus_t ivl_lpm_async_set(ivl_lpm_t net) assert(net); switch(net->type) { case IVL_LPM_FF: + case IVL_LPM_LATCH: return net->u_.ff.aset; default: assert(0); @@ -692,6 +694,7 @@ extern "C" ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net) assert(net); switch (net->type) { case IVL_LPM_FF: + case IVL_LPM_LATCH: case IVL_LPM_RAM: return net->u_.ff.clk; default: @@ -700,26 +703,12 @@ extern "C" ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net) } } -extern "C" ivl_nexus_t ivl_lpm_gate( ivl_lpm_t netPtr ) -{ - assert( netPtr ); - - switch ( netPtr->type ) - { - case IVL_LPM_LATCH: - return netPtr->u_.latch.gatePtr; - default: - assert( false ); - return 0; - } - -} - extern "C" ivl_expr_t ivl_lpm_aset_value(ivl_lpm_t net) { assert(net); switch (net->type) { case IVL_LPM_FF: + case IVL_LPM_LATCH: case IVL_LPM_RAM: return net->u_.ff.aset_value; default: @@ -792,26 +781,13 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx) case IVL_LPM_FF: case IVL_LPM_RAM: + case IVL_LPM_LATCH: assert(idx < net->u_.ff.width); if (net->u_.ff.width == 1) return net->u_.ff.d.pin; else return net->u_.ff.d.pins[idx]; - case IVL_LPM_LATCH: - - if( idx >= net->u_.latch.width ) - { - throw invalid_argument( "idx too high" ); - } - - if ( net->u_.latch.width != 1U ) - { - throw invalid_argument( "Only 1-wide latches are currently supported." ); - } - - return net->u_.latch.dataPtr; - default: assert(0); return 0; @@ -963,6 +939,7 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx) return net->u_.arith.q[0]; case IVL_LPM_FF: + case IVL_LPM_LATCH: case IVL_LPM_RAM: assert(idx < net->u_.ff.width); if (net->u_.ff.width == 1) @@ -970,20 +947,6 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx) else return net->u_.ff.q.pins[idx]; - case IVL_LPM_LATCH: - - if ( idx >= net->u_.latch.width ) - { - throw invalid_argument( "idx too high" ); - } - - if ( net->u_.latch.width != 1U ) - { - throw invalid_argument( "Only 1-wide latches are currently supported." ); - } - - return net->u_.latch.qPtr; - case IVL_LPM_MUX: assert(idx < net->u_.mux.width); if (net->u_.mux.width == 1) @@ -1073,6 +1036,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net) assert(net); switch (net->type) { case IVL_LPM_FF: + case IVL_LPM_LATCH: case IVL_LPM_RAM: case IVL_LPM_MUX: case IVL_LPM_DEMUX: @@ -1126,10 +1090,9 @@ extern "C" unsigned ivl_lpm_width(ivl_lpm_t net) assert(net); switch (net->type) { case IVL_LPM_FF: + case IVL_LPM_LATCH: case IVL_LPM_RAM: return net->u_.ff.width; - case IVL_LPM_LATCH: - return net->u_.latch.width; case IVL_LPM_DECODE: case IVL_LPM_MUX: return net->u_.mux.width; diff --git a/t-dll.cc b/t-dll.cc index b4a94ef61..28bbfbaa9 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1618,8 +1618,6 @@ void dll_target::lpm_ff(const NetFF*net) ivl_lpm_t obj = new struct ivl_lpm_s; obj->type = IVL_LPM_FF; obj->name = net->name(); - obj->attr = 0; - obj->nattr = 0; obj->scope = find_scope(des_, net->scope()); obj->u_.ff.a.decode = lpm_decode_ff_(net->get_demux()); assert(obj->scope); @@ -1735,36 +1733,95 @@ void dll_target::lpm_ff(const NetFF*net) } } -void dll_target::lpm_latch( const NetLatch *latchPtr ) +void dll_target::lpm_latch( const NetLatch*net) { - try - { - ivl_lpm_s *objPtr = new ivl_lpm_s; - objPtr->type = IVL_LPM_LATCH; - objPtr->name = latchPtr->name(); - objPtr->scope = find_scope( des_, latchPtr->scope() ); - assert( objPtr->scope ); // C++ programmers prefer using exceptions rather than assertions. + 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()); + obj->u_.ff.a.decode = 0; + assert(obj->scope); - objPtr->u_.latch.width = latchPtr->width(); + obj->u_.ff.width = net->width(); - objPtr->nattr = latchPtr->attr_cnt(); - objPtr->attr = fill_in_attributes( latchPtr ); + obj->nattr = net->attr_cnt(); + obj->attr = fill_in_attributes(net); - scope_add_lpm( objPtr->scope, objPtr ); + scope_add_lpm(obj->scope, obj); - // Set the gate signal to point to the nexus, and the nexus to point back to this device. - const Nexus *const nexPtr = latchPtr->pin_Gate().nexus(); - assert( nexPtr->t_cookie() ); // C++ programmers prefer using exceptions rather than assertions. - objPtr->u_.latch.gatePtr = static_cast< ivl_nexus_s * >( nexPtr->t_cookie() ); - assert( objPtr->u_.latch.gatePtr ); // C++ programmers prefer using exceptions rather than assertions. - nexus_lpm_add( objPtr->u_.latch.gatePtr, objPtr, 0u, IVL_DR_HiZ, IVL_DR_HiZ ); - } - catch ( bad_alloc &memoryAllocationException ) - { - cerr << "Exception occurred: " << memoryAllocationException.what() << endl; - } + const Nexus*nex; -} // end function lpm_latch + /* Set the clk signal to point to the nexus, and the nexus to + point back to this device. */ + nex = net->pin_Clock().nexus(); + assert(nex->t_cookie()); + obj->u_.ff.clk = (ivl_nexus_t) nex->t_cookie(); + assert(obj->u_.ff.clk); + nexus_lpm_add(obj->u_.ff.clk, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + + obj->u_.ff.we = 0; + + if (net->pin_Aclr().is_linked()) { + nex = net->pin_Aclr().nexus(); + assert(nex->t_cookie()); + obj->u_.ff.aclr = (ivl_nexus_t) nex->t_cookie(); + assert(obj->u_.ff.aclr); + nexus_lpm_add(obj->u_.ff.aclr, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + } else { + obj->u_.ff.aclr = 0; + } + + if (net->pin_Aset().is_linked()) { + nex = net->pin_Aset().nexus(); + assert(nex->t_cookie()); + obj->u_.ff.aset = (ivl_nexus_t) nex->t_cookie(); + assert(obj->u_.ff.aset); + nexus_lpm_add(obj->u_.ff.aset, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + + verinum tmp = net->aset_value(); + obj->u_.ff.aset_value = expr_from_value_(tmp); + + } else { + obj->u_.ff.aset = 0; + obj->u_.ff.aset_value = 0; + } + + obj->u_.ff.sset = 0; + + obj->u_.ff.sset_value = 0; + obj->u_.ff.sclr = 0; + + if (obj->u_.ff.width == 1) { + nex = net->pin_Q(0).nexus(); + assert(nex->t_cookie()); + obj->u_.ff.q.pin = (ivl_nexus_t) nex->t_cookie(); + nexus_lpm_add(obj->u_.ff.q.pin, obj, 0, + IVL_DR_STRONG, IVL_DR_STRONG); + + nex = net->pin_Data(0).nexus(); + assert(nex->t_cookie()); + obj->u_.ff.d.pin = (ivl_nexus_t) nex->t_cookie(); + nexus_lpm_add(obj->u_.ff.d.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + + } else { + obj->u_.ff.q.pins = new ivl_nexus_t [obj->u_.ff.width * 2]; + obj->u_.ff.d.pins = obj->u_.ff.q.pins + obj->u_.ff.width; + + for (unsigned idx = 0 ; idx < obj->u_.ff.width ; idx += 1) { + nex = net->pin_Q(idx).nexus(); + assert(nex->t_cookie()); + obj->u_.ff.q.pins[idx] = (ivl_nexus_t) nex->t_cookie(); + nexus_lpm_add(obj->u_.ff.q.pins[idx], obj, 0, + IVL_DR_STRONG, IVL_DR_STRONG); + + nex = net->pin_Data(idx).nexus(); + assert(nex->t_cookie()); + obj->u_.ff.d.pins[idx] = (ivl_nexus_t) nex->t_cookie(); + nexus_lpm_add(obj->u_.ff.d.pins[idx], obj, 0, + IVL_DR_HiZ, IVL_DR_HiZ); + } + } +} void dll_target::lpm_ram_dq(const NetRamDq*net) { diff --git a/t-dll.h b/t-dll.h index 687507e5e..f7da267c5 100644 --- a/t-dll.h +++ b/t-dll.h @@ -326,14 +326,6 @@ struct ivl_lpm_s { ivl_expr_t sset_value; } ff; - struct ivl_lpm_latch_s - { - unsigned width; - ivl_nexus_s *gatePtr; - ivl_nexus_s *qPtr; - ivl_nexus_s *dataPtr; - } latch; - struct ivl_lpm_mux_s { unsigned width; unsigned size; diff --git a/target.h b/target.h index 10e7f2739..a5e4181d7 100644 --- a/target.h +++ b/target.h @@ -20,7 +20,6 @@ */ # include "netlist.h" -#include "NetLatch.h" /* * This header file describes the types and constants used to describe diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 9be4c9122..b54aa8d9c 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -391,11 +391,6 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) lpm = ivl_nexus_ptr_lpm(nptr); if (lpm) switch (ivl_lpm_type(lpm)) { - case IVL_LPM_LATCH: - fprintf(stderr, "tgt-vvp sorry: simulating a latch primitive is " - "not currently supported.\n"); - exit(1); - break; case IVL_LPM_DECODE: /* The decoder has no outputs. @@ -403,6 +398,7 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) break; case IVL_LPM_FF: + case IVL_LPM_LATCH: case IVL_LPM_MUX: case IVL_LPM_DEMUX: for (idx = 0 ; idx < ivl_lpm_width(lpm) ; idx += 1) @@ -1379,7 +1375,7 @@ static void draw_lpm_eq(ivl_lpm_t net) } /* - * primitive FD (q, clk, ce, d); + * primitive IVL_DFF (q, clk, ce, d); * output q; * reg q; * input clk, ce, d; @@ -1410,7 +1406,7 @@ static void draw_lpm_ff(ivl_lpm_t net) if (clock_pol) { /* Q C CE D RS --> Q+ */ - fprintf(vvp_out, "L_%s.%s/def .udp/sequ \"DFF\", 5, 2," + fprintf(vvp_out, "L_%s.%s/def .udp/sequ \"IVL_DFF\", 5, 2," " \"?" "f" "1" "0" "00" "0\"," " \"?" "f" "1" "1" "00" "1\"," " \"?" "f" "1" "x" "00" "x\"," @@ -1427,7 +1423,7 @@ static void draw_lpm_ff(ivl_lpm_t net) vvp_mangle_id(ivl_lpm_basename(net))); } else { /* Q C CE D RS --> Q+ */ - fprintf(vvp_out, "L_%s.%s/def .udp/sequ \"DFF\", 5, 2," + fprintf(vvp_out, "L_%s.%s/def .udp/sequ \"IVL_DFF\", 5, 2," " \"?" "r" "1" "0" "00" "0\"," " \"?" "r" "1" "1" "00" "1\"," " \"?" "r" "1" "x" "00" "x\"," @@ -1443,6 +1439,7 @@ static void draw_lpm_ff(ivl_lpm_t net) vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(net))), vvp_mangle_id(ivl_lpm_basename(net))); } + aset_expr = ivl_lpm_aset_value(net); if (aset_expr) { assert(ivl_expr_width(aset_expr) == width); @@ -1593,9 +1590,8 @@ static void draw_lpm_ff(ivl_lpm_t net) vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(net))), vvp_mangle_id(ivl_lpm_basename(net)), idx); } else { - tmp = ivl_lpm_data(net, idx); - assert(tmp); fprintf(vvp_out, ", "); + tmp = ivl_lpm_data(net, idx); draw_input_from_net(tmp); } @@ -1632,6 +1628,141 @@ static void draw_lpm_ff(ivl_lpm_t net) } } +/* + * primitive IVL_DLAT(q, clk, d, clr, set); + * output q; + * reg q; + * input clk, d, clr, set; + * + * table + * // clk d clr set : q : q+ + * 1 0 0 0 : ? : 0; + * 1 1 0 0 : ? : 1; + * x 0 0 0 : 0 : 0; + * x 1 0 0 : 1 : 1; + * 0 ? 0 0 : ? : -; + * ? ? 0 1 : ? : 1; + * ? ? 0 x : 1 : 1; + * ? ? 1 ? : ? : 0; + * ? ? x 0 : 0 : 0; + * endtable + * endprimitive + */ +static void draw_lpm_latch(ivl_lpm_t net) +{ + ivl_expr_t aset_expr = 0; + const char*aset_bits = 0; + unsigned width, idx; + + ivl_attribute_t clock_pol = find_lpm_attr(net, "ivl:clock_polarity"); + + width = ivl_lpm_width(net); + + if (clock_pol) { + /* Q CLK D RS --> Q+ */ + fprintf(vvp_out, "L_%s.%s/def .udp/sequ \"IVL_DLAT\", 4, 2," + " \"?" "0" "0" "00" "0\"," + " \"?" "0" "1" "00" "1\"," + " \"0" "x" "0" "00" "0\"," + " \"1" "x" "1" "00" "1\"," + " \"?" "1" "?" "00" "-\"," + " \"?" "?" "?" "01" "1\"," + " \"1" "?" "?" "0x" "1\"," + " \"?" "?" "?" "1?" "0\"," + " \"0" "?" "?" "x0" "0\"" + ";\n", + vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(net))), + vvp_mangle_id(ivl_lpm_basename(net))); + } else { + /* Q CLK D RS --> Q+ */ + fprintf(vvp_out, "L_%s.%s/def .udp/sequ \"IVL_DLAT\", 4, 2," + " \"?" "1" "0" "00" "0\"," + " \"?" "1" "1" "00" "1\"," + " \"0" "x" "0" "00" "0\"," + " \"1" "x" "1" "00" "1\"," + " \"?" "0" "?" "00" "-\"," + " \"?" "?" "?" "01" "1\"," + " \"1" "?" "?" "0x" "1\"," + " \"?" "?" "?" "1?" "0\"," + " \"0" "?" "?" "x0" "0\"" + ";\n", + vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(net))), + vvp_mangle_id(ivl_lpm_basename(net))); + } + + aset_expr = ivl_lpm_aset_value(net); + if (aset_expr) { + assert(ivl_expr_width(aset_expr) == width); + aset_bits = ivl_expr_bits(aset_expr); + } + + for (idx = 0 ; idx < width ; idx += 1) { + if (ivl_lpm_async_clr(net) && + aset_bits && (aset_bits[idx] == '0')) { + fprintf(vvp_out, "L_%s.%s/clr_or .functor OR, ", + vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(net))), + vvp_mangle_id(ivl_lpm_basename(net))); + draw_input_from_net(ivl_lpm_async_clr(net)); + fprintf(vvp_out, ", "); + draw_input_from_net(ivl_lpm_async_set(net)); + fprintf(vvp_out, ", C<0>, C<0>;\n"); + break; + } + } + + for (idx = 0 ; idx < width ; idx += 1) { + ivl_nexus_t tmp; + + fprintf(vvp_out, "L_%s.%s/%u .udp ", + vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(net))), + vvp_mangle_id(ivl_lpm_basename(net)), idx); + + fprintf(vvp_out, "L_%s.%s/def, ", + vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(net))), + vvp_mangle_id(ivl_lpm_basename(net))); + + /* Draw the clock (gate) input. */ + tmp = ivl_lpm_clk(net); + draw_input_from_net(tmp); + + /* Draw the data input. */ + fprintf(vvp_out, ", "); + tmp = ivl_lpm_data(net, idx); + draw_input_from_net(tmp); + + /* Connect reset input. This may be the Aclr input, or + an Aset to zero. */ + fprintf(vvp_out, ", "); + tmp = ivl_lpm_async_clr(net); + if (tmp) { + if (aset_bits && (aset_bits[idx] == '0')) + fprintf(vvp_out, "L_%s.%s/clr_or", + vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(net))), + vvp_mangle_id(ivl_lpm_basename(net))); + else + draw_input_from_net(tmp); + } else { + if (aset_bits && (aset_bits[idx] == '0')) + draw_input_from_net(ivl_lpm_async_set(net)); + else + fprintf(vvp_out, "C<0>"); + } + + /* Connect set input */ + fprintf(vvp_out, ", "); + tmp = ivl_lpm_async_set(net); + if (aset_bits && (aset_bits[idx] != '1')) + tmp = 0; + + if (tmp) + draw_input_from_net(tmp); + else + fprintf(vvp_out, "C<0>"); + + fprintf(vvp_out, ";\n"); + } +} + static void draw_lpm_shiftl(ivl_lpm_t net) { unsigned idx, width, selects; @@ -1757,6 +1888,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net) draw_lpm_ff(net); return; + case IVL_LPM_LATCH: + draw_lpm_latch(net);; + return; + case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: draw_lpm_cmp(net);