From 367d7bf94bb0a098812317e95d88f9979c9ff9b5 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 19 Dec 2012 19:01:22 -0800 Subject: [PATCH] Blend NetPartSelect(PV) objects into NetConcat 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. --- cprop.cc | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++- functor.cc | 11 +++++ functor.h | 4 +- netlist.cc | 5 -- netlist.h | 5 +- netmisc.cc | 14 ++++++ netmisc.h | 1 + 7 files changed, 170 insertions(+), 9 deletions(-) diff --git a/cprop.cc b/cprop.cc index 2efe165f1..c98041874 100644 --- a/cprop.cc +++ b/cprop.cc @@ -19,13 +19,14 @@ # include "config.h" +# include +# include # include # include "netlist.h" # include "netmisc.h" # include "functor.h" # include "compiler.h" # include "ivl_assert.h" -# include /* @@ -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*) @@ -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 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 (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 diff --git a/functor.cc b/functor.cc index 52b88adae..174aa3627 100644 --- a/functor.cc +++ b/functor.cc @@ -24,6 +24,8 @@ # include "functor.h" # include "netlist.h" +using namespace std; + functor_t::~functor_t() { } @@ -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*) { } @@ -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); diff --git a/functor.h b/functor.h index 52123918b..9bd12c843 100644 --- a/functor.h +++ b/functor.h @@ -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 @@ -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*); diff --git a/netlist.cc b/netlist.cc index 36bcdd5ce..e0715c2f3 100644 --- a/netlist.cc +++ b/netlist.cc @@ -1031,11 +1031,6 @@ unsigned NetPartSelect::base() const return off_; } -NetPartSelect::dir_t NetPartSelect::dir() const -{ - return dir_; -} - NetProc::NetProc() : next_(0) { diff --git a/netlist.h b/netlist.h index edb2b9448..a22ec4b34 100644 --- a/netlist.h +++ b/netlist.h @@ -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_; diff --git a/netmisc.cc b/netmisc.cc index beb559bc1..978d0825a 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -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) { diff --git a/netmisc.h b/netmisc.h index d075ae40f..f095e1b05 100644 --- a/netmisc.h +++ b/netmisc.h @@ -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