Skip to content

Commit

Permalink
Blend NetPartSelect(PV) objects into NetConcat
Browse files Browse the repository at this point in the history
If a signal s driven by multiple non-overlapping NetPartSelect(PV)
objects, then combine them into a single NetConcat object. This
eliminates the need for resolvers in the target.
  • Loading branch information
steveicarus committed Dec 20, 2012
1 parent a90e264 commit 367d7bf
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 9 deletions.
139 changes: 138 additions & 1 deletion cprop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@

# include "config.h"

# include <algorithm>
# include <vector>
# include <cstdlib>
# include "netlist.h"
# include "netmisc.h"
# include "functor.h"
# include "compiler.h"
# include "ivl_assert.h"
# include <vector>


/*
Expand All @@ -46,6 +47,7 @@ struct cprop_functor : public functor_t {
virtual void lpm_ff(Design*des, NetFF*obj);
virtual void lpm_logic(Design*des, NetLogic*obj);
virtual void lpm_mux(Design*des, NetMux*obj);
virtual void lpm_part_select(Design*des, NetPartSelect*obj);
};

void cprop_functor::signal(Design*, NetNet*)
Expand Down Expand Up @@ -150,6 +152,141 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj)
count += 1;
}

static bool compare_base(NetPartSelect*a, NetPartSelect*b)
{
return a->base() < b->base();
}

/*
* This optimization searches for Nexa that are driven only by
* NetPartSelect(PV) outputs. These might turn from Verilog input that
* looks like this:
* wire [7:0] foo
* assign foo[7:4] = a;
* assign foo[3:0] = b;
* The idea is to convert the part selects of the above to a single
* concatenation that looks like this:
* assign foo = {a, b};
*/
void cprop_functor::lpm_part_select(Design*des, NetPartSelect*obj)
{
if (obj->dir() != NetPartSelect::PV)
return;

NetScope*scope = obj->scope();
Nexus*nex = obj->pin(1).nexus();
vector<NetPartSelect*> obj_set;

for (Link*cur = nex->first_nlink() ; cur ; cur = cur->next_nlink()) {

// If this is an input (or passive) then ignore it.
if (cur->get_dir() != Link::OUTPUT)
continue;

// Check to see if this is the output of a
// NetPartSelect::PV. If not, then give up on the blend.
NetPins*tmp_obj = cur->get_obj();
unsigned tmp_pin = cur->get_pin();

NetPartSelect*cur_obj = dynamic_cast<NetPartSelect*> (tmp_obj);
if (cur_obj == 0)
return;

if (cur_obj->dir() != NetPartSelect::PV)
return;

if (tmp_pin != 1)
return;

obj_set.push_back(cur_obj);
}

if (obj_set.size() < 2)
return;

if (debug_optimizer)
cerr << obj->get_fileline() << ": cprop::lpm_part_select: "
<< "Found " << obj_set.size() << " NetPartSelect(PV) objects."
<< endl;

// Sort by increasing base offset.
sort(obj_set.begin(), obj_set.end(), compare_base);

// Check and make sure there are no overlaps. If there are,
// then give up on this optimization.
for (size_t idx = 1 ; idx < obj_set.size() ; idx += 1) {
unsigned top = obj_set[idx-1]->base() + obj_set[idx-1]->width();
if (top > obj_set[idx]->base()) {
if (debug_optimizer)
cerr << obj->get_fileline() << ": cprop::lpm_part_select: "
<< "Range [" << obj_set[idx-1]->base()
<< " " << top << ") overlaps PV starting at "
<< obj_set[idx]->base() << ". Give up." << endl;
return;
}
}

// Check if the tail runs off the end of the target. If so it
// should be possible to replace it with a bit select to
// shorten the object for the target, but for now just give up.
unsigned sig_width = nex->vector_width();
if (obj_set.back()->base() + obj_set.back()->width() > sig_width) {
if (debug_optimizer)
cerr << obj->get_fileline() << ": cprop::lpm_part_select: "
<< "Range [" << obj_set.back()->base()
<< ":" << (obj_set.back()->base() + obj_set.back()->width() - 1)
<< "] runs off the end of target." << endl;
return;
}

// Figure out how many components we are going to need.
unsigned part_count = 0;
unsigned off = 0;
for (size_t idx = 0 ; idx < obj_set.size() ; idx += 1) {
if (obj_set[idx]->base() > off) {
off = obj_set[idx]->base();
part_count += 1;
}
off += obj_set[idx]->width();
part_count += 1;
}

if (off < sig_width)
part_count += 1;

NetConcat*concat = new NetConcat(scope, scope->local_symbol(),
sig_width, part_count);
des->add_node(concat);
connect(concat->pin(0), obj->pin(1));

off = 0;
size_t concat_pin = 1;
for (size_t idx = 0 ; idx < obj_set.size() ; idx += 1) {
NetPartSelect*cobj = obj_set[idx];
if (cobj->base() > off) {
NetNet*zzz = make_const_z(des, scope, cobj->base()-off);
connect(concat->pin(concat_pin), zzz->pin(0));
concat_pin += 1;
off = cobj->base();
}
connect(concat->pin(concat_pin), cobj->pin(0));
concat_pin += 1;
off += cobj->width();
}
if (off < sig_width) {
NetNet*zzz = make_const_z(des, scope, sig_width-off);
connect(concat->pin(concat_pin), zzz->pin(0));
concat_pin += 1;
}
ivl_assert(*obj, concat_pin == concat->pin_count());

for (size_t idx = 0 ; idx < obj_set.size() ; idx += 1) {
delete obj_set[idx];
}

count += 1;
}

/*
* This functor looks to see if the constant is connected to nothing
* but signals. If that is the case, delete the dangling constant and
Expand Down
11 changes: 11 additions & 0 deletions functor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
# include "functor.h"
# include "netlist.h"

using namespace std;

functor_t::~functor_t()
{
}
Expand Down Expand Up @@ -84,6 +86,10 @@ void functor_t::lpm_mux(Design*, NetMux*)
{
}

void functor_t::lpm_part_select(Design*, NetPartSelect*)
{
}

void functor_t::lpm_pow(Design*, NetPow*)
{
}
Expand Down Expand Up @@ -225,6 +231,11 @@ void NetMux::functor_node(Design*des, functor_t*fun)
fun->lpm_mux(des, this);
}

void NetPartSelect::functor_node(Design*des, functor_t*fun)
{
fun->lpm_part_select(des, this);
}

void NetPow::functor_node(Design*des, functor_t*fun)
{
fun->lpm_pow(des, this);
Expand Down
4 changes: 3 additions & 1 deletion functor.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef __functor_H
#define __functor_H
/*
* Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2008,2012 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
Expand Down Expand Up @@ -81,6 +81,8 @@ struct functor_t {
/* This method is called for each MUX. */
virtual void lpm_mux(class Design*des, class NetMux*);

virtual void lpm_part_select(class Design*des, class NetPartSelect*);

/* This method is called for each power. */
virtual void lpm_pow(class Design*des, class NetPow*);

Expand Down
5 changes: 0 additions & 5 deletions netlist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1031,11 +1031,6 @@ unsigned NetPartSelect::base() const
return off_;
}

NetPartSelect::dir_t NetPartSelect::dir() const
{
return dir_;
}

NetProc::NetProc()
: next_(0)
{
Expand Down
5 changes: 3 additions & 2 deletions netlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -2002,12 +2002,13 @@ class NetPartSelect : public NetNode {

unsigned base() const;
unsigned width() const;
dir_t dir() const;
inline dir_t dir() const { return dir_; }
/* Is the select signal signed? */
bool signed_flag() const { return signed_flag_; }
inline bool signed_flag() const { return signed_flag_; }

virtual void dump_node(ostream&, unsigned ind) const;
bool emit_node(struct target_t*tgt) const;
virtual void functor_node(Design*des, functor_t*fun);

private:
unsigned off_;
Expand Down
14 changes: 14 additions & 0 deletions netmisc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,20 @@ NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid)
return sig;
}

NetNet* make_const_z(Design*des, NetScope*scope, unsigned long wid)
{
verinum xxx (verinum::Vz, wid);
NetConst*res = new NetConst(scope, scope->local_symbol(), xxx);
des->add_node(res);

netvector_t*sig_vec = new netvector_t(IVL_VT_LOGIC, wid-1, 0);
NetNet*sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, sig_vec);
sig->local_flag(true);

connect(sig->pin(0), res->pin(0));
return sig;
}

NetExpr* condition_reduce(NetExpr*expr)
{
if (expr->expr_type() == IVL_VT_REAL) {
Expand Down
1 change: 1 addition & 0 deletions netmisc.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ extern NetEConst*make_const_val(unsigned long val);
* Make A const net
*/
extern NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid);
extern NetNet* make_const_z(Design*des, NetScope*scope, unsigned long wid);

/*
* In some cases the lval is accessible as a pointer to the head of
Expand Down

0 comments on commit 367d7bf

Please sign in to comment.