diff options
| -rw-r--r-- | common/timing.cc | 64 | ||||
| -rw-r--r-- | dummy/arch.cc | 6 | ||||
| -rw-r--r-- | dummy/arch.h | 4 | ||||
| -rw-r--r-- | ice40/arch.cc | 6 | ||||
| -rw-r--r-- | ice40/arch.h | 7 | 
5 files changed, 70 insertions, 17 deletions
diff --git a/common/timing.cc b/common/timing.cc index 225afb5f..47c82a03 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -25,20 +25,72 @@  NEXTPNR_NAMESPACE_BEGIN +static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, +                          delay_t slack); +  // Follow a path, returning budget to annotate -static delay_t follow_path(Context *ctx, const PortRef &begin, int path_length, -                           delay_t slack) +static delay_t follow_user_port(Context *ctx, PortRef &user, int path_length, +                                delay_t slack)  { -    if (ctx->getPortClock(begin.cell, begin.port) != IdString()) { -        return slack / path_length; +    delay_t value; +    if (ctx->getPortClock(user.cell, user.port) != IdString()) { +        // At the end of a timing path (arguably, should check setup time +        // here too) +        value = slack / path_length;      } else { -        // ... +        // Default to the path ending here, if no further paths found +        value = slack / path_length; +        // Follow outputs of the user +        for (auto port : user.cell->ports) { +            if (port.second.type == PORT_OUT) { +                delay_t comb_delay; +                // Look up delay through this path +                bool is_path = ctx->getCellDelay(user.cell, user.port, +                                                 port.first, comb_delay); +                if (is_path) { +                    NetInfo *net = port.second.net; +                    if (net) { +                        delay_t path_budget = follow_net(ctx, net, path_length, +                                                         slack - comb_delay); +                        value = std::min(value, path_budget); +                    } +                } +            } +        } +    } + +    if (value < user.budget) { +        user.budget = value; +    } +} + +static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, +                          delay_t slack) +{ +    delay_t net_budget = slack / path_length; +    for (auto &usr : net->users) { +        net_budget = std::min( +                net_budget, follow_user_port(ctx, usr, path_length + 1, slack));      } +    return net_budget;  }  void assign_budget(Context *ctx, float default_clock)  { -    // TODO +    for (auto cell : ctx->cells) { +        for (auto port : cell.second->ports) { +            if (port.second.type == PORT_OUT) { +                IdString clock_domain = +                        ctx->getPortClock(cell.second, port.first); +                if (clock_domain != IdString()) { +                    delay_t slack = delay_t( +                            1.0e12 / default_clock); // TODO: clock constraints +                    if (port.second.net) +                        follow_net(ctx, port.second.net, 0, slack); +                } +            } +        } +    }  }  NEXTPNR_NAMESPACE_END diff --git a/dummy/arch.cc b/dummy/arch.cc index 64841374..fa0d8bd3 100644 --- a/dummy/arch.cc +++ b/dummy/arch.cc @@ -178,10 +178,10 @@ std::vector<GraphicElement> Arch::getPipGraphics(PipId pip) const  // --------------------------------------------------------------- -delay_t Arch::getCellDelay(const CellInfo *cell, IdString fromPort, -                           IdString toPort) const +bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, +                        IdString toPort, delay_t &delay) const  { -    return 0; +    return false;  }  IdString Arch::getPortClock(const CellInfo *cell, IdString port) const diff --git a/dummy/arch.h b/dummy/arch.h index 61a09e00..39c48232 100644 --- a/dummy/arch.h +++ b/dummy/arch.h @@ -134,8 +134,8 @@ struct Arch : BaseCtx      std::unordered_set<WireId> wireGraphicsReload;      std::unordered_set<PipId> pipGraphicsReload; -    delay_t getCellDelay(const CellInfo *cell, IdString fromPort, -                         IdString toPort) const; +    bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, +                      delay_t &delay) const;      IdString getPortClock(const CellInfo *cell, IdString port) const;      bool isClockPort(const CellInfo *cell, IdString port) const;  }; diff --git a/ice40/arch.cc b/ice40/arch.cc index 380f3386..7baaef8d 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -418,11 +418,11 @@ std::vector<GraphicElement> Arch::getPipGraphics(PipId pip) const  // ----------------------------------------------------------------------- -delay_t Arch::getCellDelay(const CellInfo *cell, IdString fromPort, -                           IdString toPort) const +bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, +                        IdString toPort, delay_t &delay) const  {      // TODO -    return 0; +    return false;  }  IdString Arch::getPortClock(const CellInfo *cell, IdString port) const diff --git a/ice40/arch.h b/ice40/arch.h index 172541c0..356f88da 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -758,9 +758,10 @@ struct Arch : BaseCtx      // ------------------------------------------------- -    // Get the delay through a cell from one port to another -    delay_t getCellDelay(const CellInfo *cell, IdString fromPort, -                         IdString toPort) const; +    // Get the delay through a cell from one port to another, returning false +    // if no path exists +    bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, +                      delay_t &delay) const;      // Get the associated clock to a port, or empty if the port is combinational      IdString getPortClock(const CellInfo *cell, IdString port) const;      // Return true if a port is a clock  | 
