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.
This commit is contained in:
Cary R 2010-12-21 18:33:20 -08:00 committed by Stephen Williams
parent 678dd7bdaa
commit 34661e9af5
17 changed files with 429 additions and 220 deletions

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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());

View File

@ -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: ";

View File

@ -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);

View File

@ -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);

View File

@ -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*);

View File

@ -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 */

View File

@ -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)

View File

@ -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

View File

@ -23,7 +23,6 @@
# include "netlist.h"
# include "compiler.h"
#include <cassert>
#include "NetLatch.h"
#include <climits>
#include <cstdlib>
@ -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 );

View File

@ -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;

109
t-dll.cc
View File

@ -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)
{

View File

@ -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;

View File

@ -20,7 +20,6 @@
*/
# include "netlist.h"
#include "NetLatch.h"
/*
* This header file describes the types and constants used to describe

View File

@ -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);