Support negedge flip-flops in synthesis and in vvp.
Also extend the support for FF asynchronous set values to vvp and fix the dff functor in vvp to correctly model asynchronous set/clr behaviour.
This commit is contained in:
parent
d39c284055
commit
b242663cae
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -677,8 +677,12 @@ void NetConst::dump_node(ostream&o, unsigned ind) const
|
|||
void NetFF::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "LPM_FF: " << name()
|
||||
<< " scope=" << scope_path(scope())
|
||||
<< " aset_value=" << aset_value_ << endl;
|
||||
<< " scope=" << scope_path(scope());
|
||||
if (negedge_)
|
||||
o << " negedge";
|
||||
else
|
||||
o << " posedge";
|
||||
o << " aset_value=" << aset_value_ << endl;
|
||||
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
|
|
|
|||
1
ivl.def
1
ivl.def
|
|
@ -125,6 +125,7 @@ ivl_lpm_enable
|
|||
ivl_lpm_file
|
||||
ivl_lpm_lineno
|
||||
ivl_lpm_name
|
||||
ivl_lpm_negedge
|
||||
ivl_lpm_q
|
||||
ivl_lpm_scope
|
||||
ivl_lpm_select
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_ivl_target_H
|
||||
#define IVL_ivl_target_H
|
||||
/*
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -1418,6 +1418,7 @@ extern ivl_signal_t ivl_lpm_array(ivl_lpm_t net);
|
|||
/* IVL_LPM_PART IVL_LPM_SUBSTITUTE */
|
||||
extern unsigned ivl_lpm_base(ivl_lpm_t net);
|
||||
/* IVL_LPM_FF */
|
||||
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);
|
||||
|
|
|
|||
11
netlist.cc
11
netlist.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -1153,8 +1153,8 @@ unsigned NetReplicate::repeat() const
|
|||
* ...
|
||||
*/
|
||||
|
||||
NetFF::NetFF(NetScope*s, perm_string n, unsigned width__)
|
||||
: NetNode(s, n, 8), width_(width__)
|
||||
NetFF::NetFF(NetScope*s, perm_string n, bool negedge__, unsigned width__)
|
||||
: NetNode(s, n, 8), negedge_(negedge__), width_(width__)
|
||||
{
|
||||
pin_Clock().set_dir(Link::INPUT);
|
||||
pin_Enable().set_dir(Link::INPUT);
|
||||
|
|
@ -1170,6 +1170,11 @@ NetFF::~NetFF()
|
|||
{
|
||||
}
|
||||
|
||||
bool NetFF::is_negedge() const
|
||||
{
|
||||
return negedge_;
|
||||
}
|
||||
|
||||
unsigned NetFF::width() const
|
||||
{
|
||||
return width_;
|
||||
|
|
|
|||
18
netlist.h
18
netlist.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_netlist_H
|
||||
#define IVL_netlist_H
|
||||
/*
|
||||
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -1622,9 +1622,10 @@ class NetModulo : public NetNode {
|
|||
class NetFF : public NetNode {
|
||||
|
||||
public:
|
||||
NetFF(NetScope*s, perm_string n, unsigned vector_width);
|
||||
NetFF(NetScope*s, perm_string n, bool negedge, unsigned vector_width);
|
||||
~NetFF();
|
||||
|
||||
bool is_negedge() const;
|
||||
unsigned width() const;
|
||||
|
||||
Link& pin_Clock();
|
||||
|
|
@ -1656,6 +1657,7 @@ class NetFF : public NetNode {
|
|||
virtual void functor_node(Design*des, functor_t*fun);
|
||||
|
||||
private:
|
||||
bool negedge_;
|
||||
unsigned width_;
|
||||
verinum aset_value_;
|
||||
verinum sset_value_;
|
||||
|
|
@ -2618,9 +2620,10 @@ class NetProc : public virtual LineInfo {
|
|||
// picked off by e.g. condit statements as set/reset inputs to
|
||||
// the flipflop being generated.
|
||||
virtual bool synth_sync(Design*des, NetScope*scope,
|
||||
bool&ff_negedge,
|
||||
NetNet*ff_clock, NetBus&ff_ce,
|
||||
NetBus&ff_aclr, NetBus&ff_aset,
|
||||
vector<verinum>&aset_value,
|
||||
vector<verinum>&ff_aset_value,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const std::vector<NetEvProbe*>&events);
|
||||
|
||||
|
|
@ -2900,9 +2903,10 @@ class NetBlock : public NetProc {
|
|||
NetBus&accumulated_nex_out);
|
||||
|
||||
bool synth_sync(Design*des, NetScope*scope,
|
||||
bool&ff_negedge,
|
||||
NetNet*ff_clk, NetBus&ff_ce,
|
||||
NetBus&ff_aclr,NetBus&ff_aset,
|
||||
vector<verinum>&aset_value,
|
||||
vector<verinum>&ff_aset_value,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const std::vector<NetEvProbe*>&events);
|
||||
|
||||
|
|
@ -3042,9 +3046,10 @@ class NetCondit : public NetProc {
|
|||
NetBus&accumulated_nex_out);
|
||||
|
||||
bool synth_sync(Design*des, NetScope*scope,
|
||||
bool&ff_negedge,
|
||||
NetNet*ff_clk, NetBus&ff_ce,
|
||||
NetBus&ff_aclr,NetBus&ff_aset,
|
||||
vector<verinum>&aset_value,
|
||||
vector<verinum>&ff_aset_value,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const std::vector<NetEvProbe*>&events);
|
||||
|
||||
|
|
@ -3320,9 +3325,10 @@ class NetEvWait : public NetProc {
|
|||
NetBus&accumulated_nex_out);
|
||||
|
||||
virtual bool synth_sync(Design*des, NetScope*scope,
|
||||
bool&ff_negedge,
|
||||
NetNet*ff_clk, NetBus&ff_ce,
|
||||
NetBus&ff_aclr,NetBus&ff_aset,
|
||||
vector<verinum>&aset_value,
|
||||
vector<verinum>&ff_aset_value,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const std::vector<NetEvProbe*>&events);
|
||||
|
||||
|
|
|
|||
10
syn-rules.y
10
syn-rules.y
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -121,11 +121,6 @@ static void hookup_DFF_CE(NetFF*ff, NetESignal*d, NetEvProbe*pclk,
|
|||
connect(ff->pin_Clock(), pclk->pin(0));
|
||||
if (ce) connect(ff->pin_Enable(), ce->pin(0));
|
||||
|
||||
ff->attribute(perm_string::literal("LPM_FFType"), verinum("DFF"));
|
||||
if (pclk->edge() == NetEvProbe::NEGEDGE)
|
||||
ff->attribute(perm_string::literal("Clock:LPM_Polarity"), verinum("INVERT"));
|
||||
|
||||
|
||||
/* This lval_ represents a reg that is a WIRE in the
|
||||
synthesized results. This function signals the destructor
|
||||
to change the REG that this l-value refers to into a
|
||||
|
|
@ -165,7 +160,8 @@ static void make_DFF_CE(Design*des, NetProcTop*top,
|
|||
|
||||
if (a->sig()) {
|
||||
// cerr << "new NetFF named " << a->name() << endl;
|
||||
NetFF*ff = new NetFF(top->scope(), a->name(),
|
||||
bool negedge = pclk->edge() == NetEvProbe::NEGEDGE;
|
||||
NetFF*ff = new NetFF(top->scope(), a->name(), negedge,
|
||||
a->sig()->vector_width());
|
||||
hookup_DFF_CE(ff, d, pclk, ce, a, rval_pinoffset);
|
||||
des->add_node(ff);
|
||||
|
|
|
|||
64
synth2.cc
64
synth2.cc
|
|
@ -34,9 +34,10 @@ bool NetProc::synth_async(Design*, NetScope*, NexusSet&, NetBus&, NetBus&)
|
|||
}
|
||||
|
||||
bool NetProc::synth_sync(Design*des, NetScope*scope,
|
||||
bool& /* ff_negedge */,
|
||||
NetNet* /* ff_clk */, NetBus& /* ff_ce */,
|
||||
NetBus& /* ff_aclr*/, NetBus& /* ff_aset*/,
|
||||
vector<verinum>& /*aset_value*/,
|
||||
vector<verinum>& /*ff_aset_value*/,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const vector<NetEvProbe*>&events)
|
||||
{
|
||||
|
|
@ -1383,9 +1384,10 @@ bool NetProcTop::synth_async(Design*des)
|
|||
* the statements may each infer different reset and enable signals.
|
||||
*/
|
||||
bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
||||
bool&ff_negedge,
|
||||
NetNet*ff_clk, NetBus&ff_ce,
|
||||
NetBus&ff_aclr,NetBus&ff_aset,
|
||||
vector<verinum>&aset_value,
|
||||
vector<verinum>&ff_aset_value,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const vector<NetEvProbe*>&events_in)
|
||||
{
|
||||
|
|
@ -1428,8 +1430,9 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|||
subset of the statement. The tmp_map is the output
|
||||
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, tmp_ce,
|
||||
ff_aclr, ff_aset, aset_value,
|
||||
bool ok_flag = cur->synth_sync(des, scope,
|
||||
ff_negedge, ff_clk, tmp_ce,
|
||||
ff_aclr, ff_aset, ff_aset_value,
|
||||
tmp_set, tmp_out, events_in);
|
||||
flag = flag && ok_flag;
|
||||
|
||||
|
|
@ -1465,9 +1468,10 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|||
* expression is connected to an event, or not.
|
||||
*/
|
||||
bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
||||
bool&ff_negedge,
|
||||
NetNet*ff_clk, NetBus&ff_ce,
|
||||
NetBus&ff_aclr,NetBus&ff_aset,
|
||||
vector<verinum>&aset_value,
|
||||
vector<verinum>&ff_aset_value,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const vector<NetEvProbe*>&events_in)
|
||||
{
|
||||
|
|
@ -1514,25 +1518,13 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
|||
for (unsigned pin = 0 ; pin < tmp_out.pin_count() ; pin += 1) {
|
||||
Nexus*rst_nex = tmp_out.pin(pin).nexus();
|
||||
|
||||
vector<bool> rst_mask = rst_nex->driven_mask();
|
||||
if (debug_synth2) {
|
||||
cerr << get_fileline() << ": NetCondit::synth_sync: "
|
||||
<< "nex_out pin=" << pin
|
||||
<< ", rst_mask.size()==" << rst_mask.size()
|
||||
<< ", rst_nex->vector_width()=" << rst_nex->vector_width()
|
||||
<< endl;
|
||||
}
|
||||
|
||||
for (size_t bit = 0 ; bit < rst_mask.size() ; bit += 1) {
|
||||
if (rst_mask[bit]==false) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Asynchronous LOAD not implemented." << endl;
|
||||
return false;
|
||||
}
|
||||
if (! rst_nex->drivers_constant()) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Asynchronous LOAD not implemented." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
verinum rst_drv = rst_nex->driven_vector();
|
||||
ivl_assert(*this, rst_drv.len()==rst_mask.size());
|
||||
|
||||
verinum zero (verinum::V0, rst_drv.len());
|
||||
verinum ones (verinum::V1, rst_drv.len());
|
||||
|
|
@ -1551,12 +1543,13 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
|||
ivl_assert(*this, rst->pin_count()==1);
|
||||
connect(ff_aset.pin(pin), rst->pin(0));
|
||||
if (rst_drv!=ones)
|
||||
aset_value[pin] = rst_drv;
|
||||
ff_aset_value[pin] = rst_drv;
|
||||
}
|
||||
}
|
||||
|
||||
return else_->synth_sync(des, scope, ff_clk, ff_ce,
|
||||
ff_aclr, ff_aset, aset_value,
|
||||
return else_->synth_sync(des, scope,
|
||||
ff_negedge, ff_clk, ff_ce,
|
||||
ff_aclr, ff_aset, ff_aset_value,
|
||||
nex_map, nex_out, vector<NetEvProbe*>(0));
|
||||
}
|
||||
|
||||
|
|
@ -1711,15 +1704,19 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
|||
}
|
||||
}
|
||||
|
||||
bool flag = if_->synth_sync(des, scope, ff_clk, ff_ce, ff_aclr, ff_aset, aset_value, nex_map, nex_out, events_in);
|
||||
bool flag = if_->synth_sync(des, scope,
|
||||
ff_negedge, ff_clk, ff_ce,
|
||||
ff_aclr, ff_aset, ff_aset_value,
|
||||
nex_map, nex_out, events_in);
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool NetEvWait::synth_sync(Design*des, NetScope*scope,
|
||||
bool&ff_negedge,
|
||||
NetNet*ff_clk, NetBus&ff_ce,
|
||||
NetBus&ff_aclr,NetBus&ff_aset,
|
||||
vector<verinum>&aset_value,
|
||||
vector<verinum>&ff_aset_value,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
const vector<NetEvProbe*>&events_in)
|
||||
{
|
||||
|
|
@ -1789,8 +1786,7 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope,
|
|||
|
||||
connect(ff_clk->pin(0), pclk->pin(0));
|
||||
if (pclk->edge() == NetEvProbe::NEGEDGE) {
|
||||
perm_string polarity = perm_string::literal("Clock:LPM_Polarity");
|
||||
ff_clk->attribute(polarity, verinum("INVERT"));
|
||||
ff_negedge = true;
|
||||
|
||||
if (debug_synth2) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
|
|
@ -1800,8 +1796,9 @@ 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, aset_value,
|
||||
bool flag = statement_->synth_sync(des, scope,
|
||||
ff_negedge, ff_clk, ff_ce,
|
||||
ff_aclr, ff_aset, ff_aset_value,
|
||||
nex_map, nex_out, events);
|
||||
|
||||
return flag;
|
||||
|
|
@ -1857,7 +1854,10 @@ 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, aclr, aset, aset_value,
|
||||
bool negedge = false;
|
||||
bool flag = statement_->synth_sync(des, scope(),
|
||||
negedge, clock, ce,
|
||||
aclr, aset, aset_value,
|
||||
nex_set, nex_d,
|
||||
vector<NetEvProbe*>());
|
||||
if (! flag) {
|
||||
|
|
@ -1876,7 +1876,7 @@ bool NetProcTop::synth_sync(Design*des)
|
|||
}
|
||||
|
||||
NetFF*ff2 = new NetFF(scope(), scope()->local_symbol(),
|
||||
nex_set[idx].wid);
|
||||
negedge, nex_set[idx].wid);
|
||||
des->add_node(ff2);
|
||||
ff2->set_line(*this);
|
||||
ff2->aset_value(aset_value[idx]);
|
||||
|
|
|
|||
14
t-dll-api.cc
14
t-dll-api.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -1090,6 +1090,18 @@ extern "C" unsigned ivl_lpm_base(ivl_lpm_t net)
|
|||
}
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_lpm_negedge(ivl_lpm_t net)
|
||||
{
|
||||
assert(net);
|
||||
switch (net->type) {
|
||||
case IVL_LPM_FF:
|
||||
return net->u_.ff.negedge_flag;
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net)
|
||||
{
|
||||
assert(net);
|
||||
|
|
|
|||
13
t-dll.cc
13
t-dll.cc
|
|
@ -1938,6 +1938,9 @@ void dll_target::lpm_ff(const NetFF*net)
|
|||
|
||||
const Nexus*nex;
|
||||
|
||||
/* Set the clock polarity. */
|
||||
obj->u_.ff.negedge_flag = net->is_negedge();
|
||||
|
||||
/* Set the clk signal to point to the nexus, and the nexus to
|
||||
point back to this device. */
|
||||
nex = net->pin_Clock().nexus();
|
||||
|
|
@ -1976,7 +1979,10 @@ void dll_target::lpm_ff(const NetFF*net)
|
|||
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);
|
||||
if (tmp.len() > 0)
|
||||
obj->u_.ff.aset_value = expr_from_value_(tmp);
|
||||
else
|
||||
obj->u_.ff.aset_value = 0;
|
||||
|
||||
} else {
|
||||
obj->u_.ff.aset = 0;
|
||||
|
|
@ -2001,7 +2007,10 @@ void dll_target::lpm_ff(const NetFF*net)
|
|||
nexus_lpm_add(obj->u_.ff.sset, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
|
||||
verinum tmp = net->sset_value();
|
||||
obj->u_.ff.sset_value = expr_from_value_(tmp);
|
||||
if (tmp.len() > 0)
|
||||
obj->u_.ff.sset_value = expr_from_value_(tmp);
|
||||
else
|
||||
obj->u_.ff.sset_value = 0;
|
||||
|
||||
} else {
|
||||
obj->u_.ff.sset = 0;
|
||||
|
|
|
|||
3
t-dll.h
3
t-dll.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_t_dll_H
|
||||
#define IVL_t_dll_H
|
||||
/*
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -370,6 +370,7 @@ struct ivl_lpm_s {
|
|||
|
||||
union {
|
||||
struct ivl_lpm_ff_s {
|
||||
unsigned negedge_flag :1;
|
||||
ivl_nexus_t clk;
|
||||
ivl_nexus_t we;
|
||||
ivl_nexus_t aclr;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -497,10 +497,11 @@ static void show_lpm_concat(ivl_lpm_t net)
|
|||
static void show_lpm_ff(ivl_lpm_t net)
|
||||
{
|
||||
ivl_nexus_t nex;
|
||||
char*edge = ivl_lpm_negedge(net) ? "negedge" : "posedge";
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
|
||||
fprintf(out, " LPM_FF %s: <width=%u>\n",
|
||||
ivl_lpm_basename(net), width);
|
||||
fprintf(out, " LPM_FF %s: <polarity=%s> <width=%u>\n",
|
||||
ivl_lpm_basename(net), edge, width);
|
||||
|
||||
nex = ivl_lpm_clk(net);
|
||||
fprintf(out, " clk: %p\n", nex);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2014 Cary R. (cygcary@yahoo.com)
|
||||
* Copyright (C) 2011-2015 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -1245,7 +1245,43 @@ static void emit_posedge_dff_prim(void)
|
|||
fprintf(vlog_out, "endprimitive\n");
|
||||
}
|
||||
|
||||
static void emit_negedge_dff_prim(void)
|
||||
{
|
||||
fprintf(vlog_out, "\n");
|
||||
fprintf(vlog_out, "/* Icarus generated UDP to represent a synthesized "
|
||||
"negative edge D-FF. */\n");
|
||||
fprintf(vlog_out, "primitive IVL_negedge_DFF "
|
||||
"(q, clk, en, d, clr, set);\n");
|
||||
fprintf(vlog_out, "%*coutput q;\n", indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*cinput clk, en, d, clr, set;\n", indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*creg q;\n", indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*ctable\n", indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*cf 1 0 0 0 : ? : 0 ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*cf 1 1 0 0 : ? : 1 ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*cn 1 0 0 0 : 0 : - ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*cn 1 1 0 0 : 1 : - ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*cn x 0 0 0 : 0 : - ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*cn x 1 0 0 : 1 : - ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*cp ? ? 0 0 : ? : - ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*c* 0 ? 0 0 : ? : - ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*c? * ? ? ? : ? : - ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*c? ? * ? ? : ? : - ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*c? ? ? * ? : ? : - ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*c? ? ? ? * : ? : - ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*c? ? ? 0 1 : ? : 1 ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*c? ? ? 0 x : 1 : - ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*c? ? ? 0 x : 0 : x ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*c? ? ? 1 ? : ? : 0 ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*c? ? ? x 0 : 0 : - ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*c? ? ? x 0 : 1 : x ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*c? ? ? x x : ? : x ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*c? ? ? x 1 : ? : x ;\n", 2*indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*cendtable\n", indent_incr, ' ');
|
||||
fprintf(vlog_out, "endprimitive\n");
|
||||
}
|
||||
|
||||
static unsigned need_posedge_dff_prim = 0;
|
||||
static unsigned need_negedge_dff_prim = 0;
|
||||
|
||||
/*
|
||||
* Synthesis creates a D-FF LPM object. To allow this to be simulated as
|
||||
|
|
@ -1263,14 +1299,14 @@ void emit_icarus_generated_udps()
|
|||
{
|
||||
/* Emit the copyright information and LGPL note and then emit any
|
||||
* needed primitives. */
|
||||
if (need_posedge_dff_prim) {
|
||||
if (need_posedge_dff_prim || need_negedge_dff_prim) {
|
||||
fprintf(vlog_out,
|
||||
"\n"
|
||||
"/*\n"
|
||||
" * This is the copyright information for the following primitive(s)\n"
|
||||
" * (library elements).\n"
|
||||
" *\n"
|
||||
" * Copyright (C) 2011 Cary R. (cygcary@yahoo.com)\n"
|
||||
" * Copyright (C) 2011-2015 Cary R. (cygcary@yahoo.com)\n"
|
||||
" *\n"
|
||||
" * This library is free software; you can redistribute it and/or\n"
|
||||
" * modify it under the terms of the GNU Lesser General Public\n"
|
||||
|
|
@ -1290,13 +1326,12 @@ void emit_icarus_generated_udps()
|
|||
"NOTE: vlog95: Adding LGPL 2.1 primitive(s) at the end of the output file.\n");
|
||||
}
|
||||
if (need_posedge_dff_prim) emit_posedge_dff_prim();
|
||||
if (need_negedge_dff_prim) emit_negedge_dff_prim();
|
||||
}
|
||||
|
||||
static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm)
|
||||
{
|
||||
// HERE: No support for lpm attributes and hence polarity information.
|
||||
// ivl_attribute_t clock_pol = find_lpm_attr(lpm, "Clock:LPM_Polarity");
|
||||
ivl_attribute_t clock_pol = 0;
|
||||
unsigned negedge = ivl_lpm_negedge(lpm);
|
||||
ivl_expr_t aset_expr = ivl_lpm_aset_value(lpm);
|
||||
ivl_expr_t sset_expr = ivl_lpm_sset_value(lpm);
|
||||
ivl_nexus_t nex;
|
||||
|
|
@ -1305,7 +1340,13 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm)
|
|||
const char *sset_bits = 0;
|
||||
/* For now we only support a width of 1 for these bits. */
|
||||
if (aset_expr) {
|
||||
assert(ivl_expr_width(aset_expr) == 1);
|
||||
if (ivl_expr_width(aset_expr) != 1) {
|
||||
fprintf(stderr, "%s:%u: vlog95 sorry: FF LPMs with "
|
||||
"multi-bit asynchronous set values are not "
|
||||
"currently translated.\n",
|
||||
ivl_lpm_file(lpm), ivl_lpm_lineno(lpm));
|
||||
vlog_errors += 1;
|
||||
}
|
||||
aset_bits = ivl_expr_bits(aset_expr);
|
||||
}
|
||||
if (sset_expr) {
|
||||
|
|
@ -1314,9 +1355,7 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm)
|
|||
}
|
||||
|
||||
fprintf(vlog_out, "%*c", indent, ' ');
|
||||
/* If there is a clock polarity attribute then we have a negative
|
||||
* edge D-FF. */
|
||||
if (clock_pol) {
|
||||
if (negedge) {
|
||||
fprintf(vlog_out, "IVL_negedge_DFF");
|
||||
} else {
|
||||
fprintf(vlog_out, "IVL_posedge_DFF");
|
||||
|
|
@ -1404,7 +1443,10 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm)
|
|||
else fprintf(vlog_out, "1'b0");
|
||||
fprintf(vlog_out, ");\n");
|
||||
/* We need to emit a primitive for this instance. */
|
||||
need_posedge_dff_prim = 1;
|
||||
if (negedge)
|
||||
need_negedge_dff_prim = 1;
|
||||
else
|
||||
need_posedge_dff_prim = 1;
|
||||
}
|
||||
|
||||
static ivl_signal_t get_output_from_nexus(ivl_scope_t scope, ivl_nexus_t nex,
|
||||
|
|
|
|||
|
|
@ -1716,44 +1716,45 @@ static void draw_lpm_concat(ivl_lpm_t net)
|
|||
/*
|
||||
* Emit a DFF primitive. This uses the following syntax:
|
||||
*
|
||||
* .dff <data>, <clock>, <enable>, <async>;
|
||||
*
|
||||
* The async pin currently sets the stored data value and propagates it
|
||||
* to the output (not very useful). This routine always sets the async
|
||||
* value to high-Z which is ignored in the VVP code. This is all OK
|
||||
* since synthesis is not currently functional.
|
||||
* .dff<variant> <width> <data>, <clock>, <enable>[, <async>[, <async-value>]];
|
||||
*/
|
||||
static void draw_lpm_ff(ivl_lpm_t net)
|
||||
{
|
||||
ivl_nexus_t nex;
|
||||
|
||||
/* Sync/Async set/clear control is currently only supported in V0.8
|
||||
* which has working synthesis. If/when this is added see that code
|
||||
* for clues about how this should be implemented. The dff primitive
|
||||
* used here (from vvp) needs to be improved to support both an
|
||||
* async set and clear. See the UDP generated by the tgt-vlog95 code
|
||||
* generator in V0.10 and later for how this might be done. */
|
||||
/* Sync set/clear control is not currently supported. This is not
|
||||
* a problem, as synthesis can incorporate this in the D input
|
||||
* expression. All modern synthesis tools do this as a matter of
|
||||
* course, as most cell libraries don't contain flip-flops with
|
||||
* sync set/clear.
|
||||
*/
|
||||
assert(ivl_lpm_sync_clr(net) == 0);
|
||||
assert(ivl_lpm_sync_set(net) == 0);
|
||||
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
char*edge = ivl_lpm_negedge(net) ? "n" : "p";
|
||||
if (ivl_lpm_async_clr(net)) {
|
||||
/* Synthesis doesn't currently support both set and clear.
|
||||
If it ever does, it might be better to implement the
|
||||
flip-flop as a UDP. See tgt-vlog95 for an example of
|
||||
how to do this. */
|
||||
if (ivl_lpm_async_set(net)) {
|
||||
fprintf(stderr, "%s:%u:vvp.tgt: sorry: No support for a D-ff "
|
||||
fprintf(stderr, "%s:%u:vvp.tgt: sorry: No support for a DFF "
|
||||
"with both an async. set and clear.\n",
|
||||
ivl_lpm_file(net), ivl_lpm_lineno(net));
|
||||
vvp_errors += 1;
|
||||
}
|
||||
fprintf(vvp_out, "L_%p .dff/aclr ", net);
|
||||
fprintf(vvp_out, "L_%p .dff/%s/aclr %u ", net, edge, width);
|
||||
} else if (ivl_lpm_async_set(net)) {
|
||||
fprintf(vvp_out, "L_%p .dff/aset ", net);
|
||||
fprintf(vvp_out, "L_%p .dff/%s/aset %u ", net, edge, width);
|
||||
} else {
|
||||
fprintf(vvp_out, "L_%p .dff ", net);
|
||||
fprintf(vvp_out, "L_%p .dff/%s %u ", net, edge, width);
|
||||
}
|
||||
|
||||
nex = ivl_lpm_data(net,0);
|
||||
assert(nex);
|
||||
fprintf(vvp_out, "%s", draw_net_input(nex));
|
||||
assert(width_of_nexus(nex) == ivl_lpm_width(net));;
|
||||
assert(width_of_nexus(nex) == width);;
|
||||
|
||||
nex = ivl_lpm_clk(net);
|
||||
assert(nex);
|
||||
|
|
@ -1769,11 +1770,24 @@ static void draw_lpm_ff(ivl_lpm_t net)
|
|||
}
|
||||
|
||||
if ( (nex = ivl_lpm_async_clr(net)) ) {
|
||||
assert(width_of_nexus(nex) == 1);;
|
||||
fprintf(vvp_out, ", %s", draw_net_input(nex));
|
||||
}
|
||||
|
||||
if ( (nex = ivl_lpm_async_set(net)) ) {
|
||||
ivl_expr_t val = ivl_lpm_aset_value(net);
|
||||
assert(width_of_nexus(nex) == 1);;
|
||||
fprintf(vvp_out, ", %s", draw_net_input(nex));
|
||||
if (val) {
|
||||
unsigned nbits = ivl_expr_width(val);
|
||||
const char*bits = ivl_expr_bits(val);
|
||||
unsigned bb;
|
||||
assert(nbits == width);
|
||||
fprintf(vvp_out, ", C4<");
|
||||
for (bb = 0 ; bb < nbits; bb += 1)
|
||||
fprintf(vvp_out, "%c", bits[nbits-bb-1]);
|
||||
fprintf(vvp_out, ">");
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -192,18 +192,24 @@ 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>;
|
||||
<label> .dff/aclr <d>, <clk>, <ce>, <async-input>;
|
||||
<label> .dff/aset <d>, <clk>, <ce>, <async-input>;
|
||||
<label> .dff/p <width> <d>, <clk>, <ce>;
|
||||
<label> .dff/n <width> <d>, <clk>, <ce>;
|
||||
<label> .dff/p/aclr <width> <d>, <clk>, <ce>, <async-input>;
|
||||
<label> .dff/n/aclr <width> <d>, <clk>, <ce>, <async-input>;
|
||||
<label> .dff/p/aset <width> <d>, <clk>, <ce>, <async-input>[, <set-value>];
|
||||
<label> .dff/n/aset <width> <d>, <clk>, <ce>, <async-input>[, <set-value>];
|
||||
|
||||
The /p variants simulate positive-edge triggered flip-flops and the
|
||||
/n variants simulate negative-edge triggered flip-flops. The generated
|
||||
functor is generally synchronous on the specified 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 on the
|
||||
rising edge causes the device to clear/set, forces the output to
|
||||
propagate, and disables the clock until the aynchronous input is
|
||||
deasserted. Thus, they implement DFF with asynchronous clr or set.
|
||||
|
||||
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 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:
|
||||
|
||||
|
|
|
|||
|
|
@ -208,21 +208,22 @@ extern void compile_cmp_ne_r(char*label, unsigned argc, struct symb_s*argv);
|
|||
extern void compile_cmp_ge_r(char*label, unsigned argc, struct symb_s*argv);
|
||||
extern void compile_cmp_gt_r(char*label, unsigned argc, struct symb_s*argv);
|
||||
|
||||
extern void compile_dff(char*label,
|
||||
extern void compile_dff(char*label, unsigned width, bool negedge,
|
||||
struct symb_s arg_d,
|
||||
struct symb_s arg_c,
|
||||
struct symb_s arg_e);
|
||||
|
||||
extern void compile_dff_aclr(char*label,
|
||||
extern void compile_dff_aclr(char*label, unsigned width, bool negedge,
|
||||
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,
|
||||
extern void compile_dff_aset(char*label, unsigned width, bool negedge,
|
||||
struct symb_s arg_d,
|
||||
struct symb_s arg_c,
|
||||
struct symb_s arg_e,
|
||||
struct symb_s arg_a);
|
||||
struct symb_s arg_a,
|
||||
char*asc_value);
|
||||
|
||||
extern void compile_enum2_type(char*label, long width, bool signed_flag,
|
||||
std::list<struct enum_name_s>*names);
|
||||
|
|
|
|||
152
vvp/dff.cc
152
vvp/dff.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2005-2015 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -26,17 +26,43 @@
|
|||
# include <cstdlib>
|
||||
# include <iostream>
|
||||
|
||||
vvp_dff::vvp_dff(bool invert_clk, bool invert_ce)
|
||||
: iclk_(invert_clk), ice_(invert_ce)
|
||||
/* We need to ensure an initial output value is propagated. This is
|
||||
achieved by setting asc_ to BIT4_Z to flag that we haven't yet
|
||||
propagated an output value. This will also disable clocked output.
|
||||
For flip-flops without an asynchronous set/clear, we schedule an
|
||||
initial value of BIT4_0 to be sent to port 3. For flip-flops with
|
||||
an asynchronous set/clear, we rely on the network propagating an
|
||||
initial value to port 3. The first value received on port 3 will
|
||||
either propagate the set/clear value (if the received value is
|
||||
BIT4_1) or will propagate an initial value of 'bx. From then on
|
||||
the flip-flop operates normally. */
|
||||
|
||||
vvp_dff::vvp_dff(unsigned width, bool negedge)
|
||||
: clk_(BIT4_X), ena_(BIT4_X), asc_(BIT4_Z), d_(width, BIT4_X)
|
||||
{
|
||||
clk_cur_ = BIT4_X;
|
||||
enable_ = BIT4_X;
|
||||
clk_active_ = negedge ? BIT4_0 : BIT4_1;
|
||||
}
|
||||
|
||||
vvp_dff::~vvp_dff()
|
||||
{
|
||||
}
|
||||
|
||||
vvp_dff_aclr::vvp_dff_aclr(unsigned width, bool negedge)
|
||||
: vvp_dff(width, negedge)
|
||||
{
|
||||
}
|
||||
|
||||
vvp_dff_aset::vvp_dff_aset(unsigned width, bool negedge)
|
||||
: vvp_dff(width, negedge)
|
||||
{
|
||||
}
|
||||
|
||||
vvp_dff_asc::vvp_dff_asc(unsigned width, bool negedge, char*asc_value)
|
||||
: vvp_dff(width, negedge)
|
||||
{
|
||||
asc_value_ = c4string_to_vector4(asc_value);
|
||||
}
|
||||
|
||||
void vvp_dff::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
||||
vvp_context_t)
|
||||
{
|
||||
|
|
@ -48,105 +74,70 @@ void vvp_dff::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
|||
d_ = bit;
|
||||
break;
|
||||
|
||||
/* This is a clock input */
|
||||
case 1: // CLK
|
||||
assert(bit.size() == 1);
|
||||
if (enable_ != BIT4_1)
|
||||
if (asc_ != BIT4_0)
|
||||
break;
|
||||
tmp = clk_cur_;
|
||||
clk_cur_ = bit.value(0);
|
||||
if (clk_cur_ == BIT4_1 && tmp != BIT4_1)
|
||||
if (ena_ != BIT4_1)
|
||||
break;
|
||||
tmp = clk_;
|
||||
clk_ = bit.value(0);
|
||||
if (clk_ == clk_active_ && tmp != clk_active_)
|
||||
port.ptr()->send_vec4(d_, 0);
|
||||
break;
|
||||
|
||||
case 2: // CE
|
||||
assert(bit.size() == 1);
|
||||
enable_ = bit.value(0);
|
||||
ena_ = bit.value(0);
|
||||
break;
|
||||
|
||||
case 3: // Asynch-D
|
||||
assert(0);
|
||||
case 3: // asynch SET/CLR
|
||||
assert(bit.size() == 1);
|
||||
tmp = asc_;
|
||||
asc_ = bit.value(0);
|
||||
if (asc_ == BIT4_1 && tmp != BIT4_1)
|
||||
recv_async(port);
|
||||
else if (tmp == BIT4_Z)
|
||||
port.ptr()->send_vec4(vvp_vector4_t(d_.size(), BIT4_X), 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The recv_clear and recv_set function respond to asynchronous
|
||||
* clear/set input by propagating the desired output.
|
||||
* The recv_async functions respond to the asynchronous
|
||||
* set/clear 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)
|
||||
void vvp_dff::recv_async(vvp_net_ptr_t)
|
||||
{
|
||||
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);
|
||||
// The base dff does not have an asynchronous set/clr input.
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void vvp_dff::recv_set(vvp_net_ptr_t port)
|
||||
void vvp_dff_aclr::recv_async(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);
|
||||
port.ptr()->send_vec4(vvp_vector4_t(d_.size(), BIT4_0), 0);
|
||||
}
|
||||
|
||||
vvp_dff_aclr::vvp_dff_aclr(bool invert_clk, bool invert_ce)
|
||||
: vvp_dff(invert_clk, invert_ce)
|
||||
void vvp_dff_aset::recv_async(vvp_net_ptr_t port)
|
||||
{
|
||||
a_ = BIT4_X;
|
||||
port.ptr()->send_vec4(vvp_vector4_t(d_.size(), BIT4_1), 0);
|
||||
}
|
||||
|
||||
void vvp_dff_aclr::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
||||
vvp_context_t ctx)
|
||||
void vvp_dff_asc::recv_async(vvp_net_ptr_t port)
|
||||
{
|
||||
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);
|
||||
}
|
||||
port.ptr()->send_vec4(asc_value_, 0);
|
||||
}
|
||||
|
||||
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,
|
||||
void compile_dff(char*label, unsigned width, bool negedge,
|
||||
struct symb_s arg_d,
|
||||
struct symb_s arg_c,
|
||||
struct symb_s arg_e)
|
||||
{
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
vvp_dff*fun = new vvp_dff(false, false);
|
||||
vvp_dff*fun = new vvp_dff(width, negedge);
|
||||
|
||||
ptr->fun = fun;
|
||||
define_functor_symbol(label, ptr);
|
||||
|
|
@ -154,15 +145,19 @@ void compile_dff(char*label, struct symb_s arg_d,
|
|||
input_connect(ptr, 0, arg_d.text);
|
||||
input_connect(ptr, 1, arg_c.text);
|
||||
input_connect(ptr, 2, arg_e.text);
|
||||
|
||||
vvp_vector4_t init_val = vvp_vector4_t(1, BIT4_0);
|
||||
schedule_init_vector(vvp_net_ptr_t(ptr,3), init_val);
|
||||
}
|
||||
|
||||
void compile_dff_aclr(char*label, struct symb_s arg_d,
|
||||
void compile_dff_aclr(char*label, unsigned width, bool negedge,
|
||||
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);
|
||||
vvp_dff*fun = new vvp_dff_aclr(width, negedge);
|
||||
|
||||
ptr->fun = fun;
|
||||
define_functor_symbol(label, ptr);
|
||||
|
|
@ -173,13 +168,22 @@ void compile_dff_aclr(char*label, struct symb_s arg_d,
|
|||
input_connect(ptr, 3, arg_a.text);
|
||||
}
|
||||
|
||||
void compile_dff_aset(char*label, struct symb_s arg_d,
|
||||
void compile_dff_aset(char*label, unsigned width, bool negedge,
|
||||
struct symb_s arg_d,
|
||||
struct symb_s arg_c,
|
||||
struct symb_s arg_e,
|
||||
struct symb_s arg_a)
|
||||
struct symb_s arg_a,
|
||||
char*asc_value)
|
||||
{
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
vvp_dff*fun = new vvp_dff_aset(false, false);
|
||||
vvp_dff*fun;
|
||||
if (asc_value) {
|
||||
assert(c4string_test(asc_value));
|
||||
fun = new vvp_dff_asc(width, negedge, asc_value);
|
||||
free(asc_value);
|
||||
} else {
|
||||
fun = new vvp_dff_aset(width, negedge);
|
||||
}
|
||||
|
||||
ptr->fun = fun;
|
||||
define_functor_symbol(label, ptr);
|
||||
|
|
|
|||
72
vvp/dff.h
72
vvp/dff.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_dff_H
|
||||
#define IVL_dff_H
|
||||
/*
|
||||
* Copyright (c) 2005-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2005-2015 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -22,57 +22,77 @@
|
|||
# include "vvp_net.h"
|
||||
|
||||
/*
|
||||
* The vvp_dff implements a D-type FF that is agnostic to the data
|
||||
* type that is holds. The clock and clock-enable inputs are single
|
||||
* bits and may be invertible. An output is propagated on the logical
|
||||
* rising edge of the clock input, or whenever an asynchronous input
|
||||
* is received. Ports are:
|
||||
* The vvp_dff implements an arbitrary width D-type FF. The clock,
|
||||
* clock-enable, and asynchronous set/clear inputs are single bits.
|
||||
* Both positive and negative edge triggered flip-flops are supported.
|
||||
* An output is propagated on the chosen edge of the clock input, or
|
||||
* on the rising edge of the asynchronous set/clear input. Ports are:
|
||||
*
|
||||
* port-0: D input
|
||||
* port-1: Clock input
|
||||
* port-2: Clock Enable input
|
||||
* port-3: Asynchronous D input.
|
||||
* port-3: Asynchronous Set/Clear input.
|
||||
*
|
||||
* The base vvp_dff does not implement an asychronous set/clear.
|
||||
*/
|
||||
class vvp_dff : public vvp_net_fun_t {
|
||||
class vvp_dff : public vvp_net_fun_t {
|
||||
|
||||
public:
|
||||
explicit vvp_dff(bool invert_clk =false, bool invert_ce =false);
|
||||
explicit vvp_dff(unsigned width, bool negedge);
|
||||
~vvp_dff();
|
||||
|
||||
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_;
|
||||
vvp_bit4_t enable_;
|
||||
virtual void recv_async(vvp_net_ptr_t port);
|
||||
|
||||
vvp_bit4_t clk_active_ : 8;
|
||||
vvp_bit4_t clk_ : 8;
|
||||
vvp_bit4_t ena_ : 8;
|
||||
vvp_bit4_t asc_ : 8;
|
||||
|
||||
protected:
|
||||
vvp_vector4_t d_;
|
||||
};
|
||||
|
||||
class vvp_dff_aclr : public vvp_dff {
|
||||
/*
|
||||
* This variant implements an asynchronous clear to all zeros.
|
||||
*/
|
||||
class vvp_dff_aclr : public vvp_dff {
|
||||
|
||||
public:
|
||||
explicit vvp_dff_aclr(bool invert_clk =false, bool invert_ce =false);
|
||||
explicit vvp_dff_aclr(unsigned width, bool negedge);
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
||||
vvp_context_t);
|
||||
private:
|
||||
vvp_bit4_t a_;
|
||||
void recv_async(vvp_net_ptr_t port);
|
||||
};
|
||||
|
||||
class vvp_dff_aset : public vvp_dff {
|
||||
/*
|
||||
* This variant implements an asynchronous set to all ones.
|
||||
*/
|
||||
class vvp_dff_aset : public vvp_dff {
|
||||
|
||||
public:
|
||||
explicit vvp_dff_aset(bool invert_clk =false, bool invert_ce =false);
|
||||
explicit vvp_dff_aset(unsigned width, bool negedge);
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
||||
vvp_context_t);
|
||||
private:
|
||||
vvp_bit4_t a_;
|
||||
void recv_async(vvp_net_ptr_t port);
|
||||
};
|
||||
|
||||
/*
|
||||
* This variant implements an asynchronous set to a specified constant
|
||||
* vector value.
|
||||
*/
|
||||
class vvp_dff_asc : public vvp_dff {
|
||||
|
||||
public:
|
||||
explicit vvp_dff_asc(unsigned width, bool negedge, char*asc_value);
|
||||
|
||||
private:
|
||||
void recv_async(vvp_net_ptr_t port);
|
||||
|
||||
vvp_vector4_t asc_value_;
|
||||
};
|
||||
|
||||
#endif /* IVL_dff_H */
|
||||
|
|
|
|||
|
|
@ -151,9 +151,12 @@ static char* strdupnew(char const *str)
|
|||
".concat" { return K_CONCAT; }
|
||||
".concat8" { return K_CONCAT8; }
|
||||
".delay" { return K_DELAY; }
|
||||
".dff" { return K_DFF; }
|
||||
".dff/aclr" { return K_DFF_ACLR; }
|
||||
".dff/aset" { return K_DFF_ASET; }
|
||||
".dff/n" { return K_DFF_N; }
|
||||
".dff/n/aclr" { return K_DFF_N_ACLR; }
|
||||
".dff/n/aset" { return K_DFF_N_ASET; }
|
||||
".dff/p" { return K_DFF_P; }
|
||||
".dff/p/aclr" { return K_DFF_P_ACLR; }
|
||||
".dff/p/aset" { return K_DFF_P_ASET; }
|
||||
".enum2" { return K_ENUM2; }
|
||||
".enum2/s" { return K_ENUM2_S; }
|
||||
".enum4" { return K_ENUM4; }
|
||||
|
|
|
|||
32
vvp/parse.y
32
vvp/parse.y
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 2001-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -83,7 +83,8 @@ 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 K_DFF_ACLR K_DFF_ASET
|
||||
%token K_CONCAT K_CONCAT8 K_DEBUG K_DELAY K_DFF_N K_DFF_N_ACLR
|
||||
%token K_DFF_N_ASET K_DFF_P K_DFF_P_ACLR K_DFF_P_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
|
||||
|
|
@ -503,14 +504,29 @@ statement
|
|||
|
||||
/* DFF nodes have an output and take up to 4 inputs. */
|
||||
|
||||
| T_LABEL K_DFF symbol ',' symbol ',' symbol ';'
|
||||
{ compile_dff($1, $3, $5, $7); }
|
||||
| T_LABEL K_DFF_N T_NUMBER symbol ',' symbol ',' symbol ';'
|
||||
{ compile_dff($1, $3, true, $4, $6, $8); }
|
||||
|
||||
| T_LABEL K_DFF_ACLR symbol ',' symbol ',' symbol ',' symbol ';'
|
||||
{ compile_dff_aclr($1, $3, $5, $7, $9); }
|
||||
| T_LABEL K_DFF_P T_NUMBER symbol ',' symbol ',' symbol ';'
|
||||
{ compile_dff($1, $3, false, $4, $6, $8); }
|
||||
|
||||
| T_LABEL K_DFF_ASET symbol ',' symbol ',' symbol ',' symbol ';'
|
||||
{ compile_dff_aset($1, $3, $5, $7, $9); }
|
||||
| T_LABEL K_DFF_N_ACLR T_NUMBER symbol ',' symbol ',' symbol ',' symbol ';'
|
||||
{ compile_dff_aclr($1, $3, true, $4, $6, $8, $10); }
|
||||
|
||||
| T_LABEL K_DFF_P_ACLR T_NUMBER symbol ',' symbol ',' symbol ',' symbol ';'
|
||||
{ compile_dff_aclr($1, $3, false, $4, $6, $8, $10); }
|
||||
|
||||
| T_LABEL K_DFF_N_ASET T_NUMBER symbol ',' symbol ',' symbol ',' symbol ';'
|
||||
{ compile_dff_aset($1, $3, true, $4, $6, $8, $10, 0); }
|
||||
|
||||
| T_LABEL K_DFF_P_ASET T_NUMBER symbol ',' symbol ',' symbol ',' symbol ';'
|
||||
{ compile_dff_aset($1, $3, false, $4, $6, $8, $10, 0); }
|
||||
|
||||
| T_LABEL K_DFF_N_ASET T_NUMBER symbol ',' symbol ',' symbol ',' symbol ',' T_SYMBOL ';'
|
||||
{ compile_dff_aset($1, $3, true, $4, $6, $8, $10, $12); }
|
||||
|
||||
| T_LABEL K_DFF_P_ASET T_NUMBER symbol ',' symbol ',' symbol ',' symbol ',' T_SYMBOL ';'
|
||||
{ compile_dff_aset($1, $3, false, $4, $6, $8, $10, $12); }
|
||||
|
||||
/* The various reduction operator nodes take a single input. */
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue