diff options
Diffstat (limited to 'ecp5')
| -rw-r--r-- | ecp5/arch.cc | 78 | ||||
| -rw-r--r-- | ecp5/arch.h | 12 | ||||
| -rw-r--r-- | ecp5/arch_pybindings.cc | 4 | ||||
| -rw-r--r-- | ecp5/globals.cc | 7 | 
4 files changed, 86 insertions, 15 deletions
| diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 9001ce6c..fe6a9545 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -539,10 +539,10 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort              return true;          }  #if 0 // FIXME -        if (fromPort == id_WCK && (toPort == id_F0 || toPort == id_F1)) { -            delay.delay = 717; -            return true; -        } +            if (fromPort == id_WCK && (toPort == id_F0 || toPort == id_F1)) { +                delay.delay = 717; +                return true; +            }  #endif          if ((fromPort == id_A0 && toPort == id_WADO3) || (fromPort == id_A1 && toPort == id_WDO1) ||              (fromPort == id_B0 && toPort == id_WADO1) || (fromPort == id_B1 && toPort == id_WDO3) || @@ -576,10 +576,10 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort      }  } -TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const +TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const  {      auto disconnected = [cell](IdString p) { return !cell->ports.count(p) || cell->ports.at(p).net == nullptr; }; - +    clockInfoCount = 0;      if (cell->type == id_TRELLIS_SLICE) {          int sd0 = int_or_default(cell->params, id("REG0_SD"), 0), sd1 = int_or_default(cell->params, id("REG1_SD"), 0);          if (port == id_CLK || port == id_WCK) @@ -598,13 +598,13 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id              return TMG_COMB_OUTPUT;          if (port == id_DI0 || port == id_DI1 || port == id_CE || port == id_LSR || (sd0 == 1 && port == id_M0) ||              (sd1 == 1 && port == id_M1)) { -            clockPort = id_CLK; +            clockInfoCount = 1;              return TMG_REGISTER_INPUT;          }          if (port == id_M0 || port == id_M1)              return TMG_COMB_INPUT;          if (port == id_Q0 || port == id_Q1) { -            clockPort = id_CLK; +            clockInfoCount = 1;              return TMG_REGISTER_OUTPUT;          } @@ -614,7 +614,7 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id          if (port == id_WD0 || port == id_WD1 || port == id_WAD0 || port == id_WAD1 || port == id_WAD2 ||              port == id_WAD3 || port == id_WRE) { -            clockPort = id_WCK; +            clockInfoCount = 1;              return TMG_REGISTER_INPUT;          } @@ -638,10 +638,8 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id          for (auto c : boost::adaptors::reverse(port_name)) {              if (std::isdigit(c))                  continue; -            if (c == 'A') -                clockPort = id_CLKA; -            else if (c == 'B') -                clockPort = id_CLKB; +            if (c == 'A' || c == 'B') +                clockInfoCount = 1;              else                  NPNR_ASSERT_FALSE_STR("bad ram port");              return (cell->ports.at(port).type == PORT_OUT) ? TMG_REGISTER_OUTPUT : TMG_REGISTER_INPUT; @@ -658,6 +656,60 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id      }  } +TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const +{ +    TimingClockingInfo info; +    info.setup.delay = 0; +    info.hold.delay = 0; +    info.clockToQ.delay = 0; +    if (cell->type == id_TRELLIS_SLICE) { +        int sd0 = int_or_default(cell->params, id("REG0_SD"), 0), sd1 = int_or_default(cell->params, id("REG1_SD"), 0); + +        if (port == id_WD0 || port == id_WD1 || port == id_WAD0 || port == id_WAD1 || port == id_WAD2 || +            port == id_WAD3 || port == id_WRE) { +            info.edge = RISING_EDGE; +            info.clock_port = id_WCK; +            info.setup.delay = 100; +            info.hold.delay = 0; +        } else if (port == id_DI0 || port == id_DI1 || port == id_CE || port == id_LSR || (sd0 == 1 && port == id_M0) || +                   (sd1 == 1 && port == id_M1)) { +            info.edge = cell->sliceInfo.clkmux == id("INV") ? FALLING_EDGE : RISING_EDGE; +            info.clock_port = id_CLK; +            info.setup.delay = 100; +            info.hold.delay = 0; +        } else { +            info.edge = cell->sliceInfo.clkmux == id("INV") ? FALLING_EDGE : RISING_EDGE; +            info.clock_port = id_CLK; +            info.clockToQ.delay = 395; +        } +    } else if (cell->type == id_DP16KD) { +        std::string port_name = port.str(this); +        for (auto c : boost::adaptors::reverse(port_name)) { +            if (std::isdigit(c)) +                continue; +            if (c == 'A') { +                info.clock_port = id_CLKA; +                break; +            } else if (c == 'B') { +                info.clock_port = id_CLKB; +                break; +            } else +                NPNR_ASSERT_FALSE_STR("bad ram port " + port.str(this)); +        } +        info.edge = (str_or_default(cell->params, info.clock_port == id_CLKB ? id("CLKBMUX") : id("CLKAMUX"), "CLK") == +                     "INV") +                            ? FALLING_EDGE +                            : RISING_EDGE; +        if (cell->ports.at(port).type == PORT_OUT) { +            info.clockToQ.delay = 4280; +        } else { +            info.setup.delay = 100; +            info.hold.delay = 0; +        } +    } +    return info; +} +  std::vector<std::pair<std::string, std::string>> Arch::getTilesAtLocation(int row, int col)  {      std::vector<std::pair<std::string, std::string>> ret; diff --git a/ecp5/arch.h b/ecp5/arch.h index 9daae11d..aa3c5348 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -859,6 +859,12 @@ struct Arch : BaseCtx      delay_t getDelayEpsilon() const { return 20; }      delay_t getRipupDelayPenalty() const { return 200; }      float getDelayNS(delay_t v) const { return v * 0.001; } +    DelayInfo getDelayFromNS(float ns) const +    { +        DelayInfo del; +        del.delay = delay_t(ns * 1000); +        return del; +    }      uint32_t getDelayChecksum(delay_t v) const { return v; }      bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const; @@ -882,8 +888,10 @@ struct Arch : BaseCtx      // 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, DelayInfo &delay) const; -    // Get the port class, also setting clockPort if applicable -    TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const; +    // Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port +    TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const; +    // Get the TimingClockingInfo of a port +    TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const;      // Return true if a port is a net      bool isGlobalNet(const NetInfo *net) const; diff --git a/ecp5/arch_pybindings.cc b/ecp5/arch_pybindings.cc index 9312b4ad..5e73a673 100644 --- a/ecp5/arch_pybindings.cc +++ b/ecp5/arch_pybindings.cc @@ -130,6 +130,10 @@ void arch_wrap_python()                                                                                                               "cells");      readonly_wrapper<Context, decltype(&Context::nets), &Context::nets, wrap_context<NetMap &>>::def_wrap(ctx_cls,                                                                                                            "nets"); + +    fn_wrapper_2a_v<Context, decltype(&Context::addClock), &Context::addClock, conv_from_str<IdString>, +                    pass_through<float>>::def_wrap(ctx_cls, "addClock"); +      WRAP_RANGE(Bel, conv_to_str<BelId>);      WRAP_RANGE(Wire, conv_to_str<WireId>);      WRAP_RANGE(AllPip, conv_to_str<PipId>); diff --git a/ecp5/globals.cc b/ecp5/globals.cc index 06412fef..9b0928a4 100644 --- a/ecp5/globals.cc +++ b/ecp5/globals.cc @@ -350,6 +350,13 @@ class Ecp5GlobalRouter          place_dcc(dcc.get()); +        if (net->clkconstr) { +            glbnet->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint()); +            glbnet->clkconstr->low = net->clkconstr->low; +            glbnet->clkconstr->high = net->clkconstr->high; +            glbnet->clkconstr->period = net->clkconstr->period; +        } +          ctx->cells[dcc->name] = std::move(dcc);          NetInfo *glbptr = glbnet.get();          ctx->nets[glbnet->name] = std::move(glbnet); | 
