From 34661e9af52f896ee0ffdae58ed1c6a1d9bb185b Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 21 Dec 2010 18:33:20 -0800 Subject: [PATCH] V0.8: Rework the NetLatch and back end code. This patch reworks the NetLatch class to better match the NetFF class (e.g. it adds a place for the async controls and value, adds a dump routine, etc.) and moves it into the normal netlist.{h,cc} files. It removes the unused Aload and Sload routines, etc. from the NetFF class. It switches the latch to use the existing ff object to pass information to the target and uses the existing FF routines as applicable. ivl_lpm_async_clr() ivl_lpm_async_set() ivl_lpm_aset_value() ivl_lpm_clk() for the gate ivl_lpm_data() ivl_lpm_q() It adds support for generating a latch UDP just like is done for the D flip-flop in the tgt-vvp code generator and fixes a bug in the generation of the clear signal when both the Aclr and Aset signals clear the register. --- Makefile.in | 2 +- NetLatch.cc | 48 ------------- NetLatch.h | 34 ---------- cprop.cc | 2 - design_dump.cc | 10 +++ emit.cc | 6 ++ functor.cc | 9 +++ functor.h | 3 + ivl_target.h | 7 +- netlist.cc | 161 ++++++++++++++++++++++++++++++++++---------- netlist.h | 38 ++++++++++- synth2.cc | 3 +- t-dll-api.cc | 53 +++------------ t-dll.cc | 109 +++++++++++++++++++++++------- t-dll.h | 8 --- target.h | 1 - tgt-vvp/vvp_scope.c | 155 +++++++++++++++++++++++++++++++++++++++--- 17 files changed, 429 insertions(+), 220 deletions(-) delete mode 100644 NetLatch.cc delete mode 100644 NetLatch.h 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);