diff options
Diffstat (limited to 'common/kernel')
| -rw-r--r-- | common/kernel/arch_pybindings_shared.h | 8 | ||||
| -rw-r--r-- | common/kernel/basectx.cc | 24 | ||||
| -rw-r--r-- | common/kernel/basectx.h | 4 | ||||
| -rw-r--r-- | common/kernel/context.cc | 5 | ||||
| -rw-r--r-- | common/kernel/context.h | 18 | ||||
| -rw-r--r-- | common/kernel/nextpnr_types.cc | 10 | ||||
| -rw-r--r-- | common/kernel/nextpnr_types.h | 86 | 
7 files changed, 127 insertions, 28 deletions
diff --git a/common/kernel/arch_pybindings_shared.h b/common/kernel/arch_pybindings_shared.h index bfb58f11..d78d240c 100644 --- a/common/kernel/arch_pybindings_shared.h +++ b/common/kernel/arch_pybindings_shared.h @@ -150,4 +150,10 @@ fn_wrapper_1a<Context, decltype(&Context::getDelayFromNS), &Context::getDelayFro                pass_through<double>>::def_wrap(ctx_cls, "getDelayFromNS");  fn_wrapper_1a<Context, decltype(&Context::getDelayNS), &Context::getDelayNS, pass_through<double>, -              pass_through<delay_t>>::def_wrap(ctx_cls, "getDelayNS");
\ No newline at end of file +              pass_through<delay_t>>::def_wrap(ctx_cls, "getDelayNS"); + +fn_wrapper_3a_v<Context, decltype(&Context::createRegionPlug), &Context::createRegionPlug, conv_from_str<IdString>, +                conv_from_str<IdString>, pass_through<Loc>>::def_wrap(ctx_cls, "createRegionPlug"); +fn_wrapper_4a_v<Context, decltype(&Context::addPlugPin), &Context::addPlugPin, conv_from_str<IdString>, +                conv_from_str<IdString>, pass_through<PortType>, conv_from_str<WireId>>::def_wrap(ctx_cls, +                                                                                                  "addPlugPin"); diff --git a/common/kernel/basectx.cc b/common/kernel/basectx.cc index 83a2deea..82cdd835 100644 --- a/common/kernel/basectx.cc +++ b/common/kernel/basectx.cc @@ -131,6 +131,30 @@ void BaseCtx::constrainCellToRegion(IdString cell, IdString region_name)      if (!matched)          log_warning("No cell matched '%s' when constraining to region '%s'\n", nameOf(cell), nameOf(region_name));  } + +void BaseCtx::createRegionPlug(IdString name, IdString type, Loc approx_loc) +{ +    CellInfo *cell = nullptr; +    if (cells.count(name)) +        cell = cells.at(name).get(); +    else +        cell = createCell(name, type); +    cell->pseudo_cell = std::make_unique<RegionPlug>(approx_loc); +} + +void BaseCtx::addPlugPin(IdString plug, IdString pin, PortType dir, WireId wire) +{ +    if (!cells.count(plug)) +        log_error("no cell named '%s' found\n", plug.c_str(this)); +    CellInfo *ci = cells.at(plug).get(); +    RegionPlug *rplug = dynamic_cast<RegionPlug *>(ci->pseudo_cell.get()); +    if (!rplug) +        log_error("cell '%s' is not a RegionPlug\n", plug.c_str(this)); +    rplug->port_wires[pin] = wire; +    ci->ports[pin].name = pin; +    ci->ports[pin].type = dir; +} +  DecalXY BaseCtx::constructDecalXY(DecalId decal, float x, float y)  {      DecalXY dxy; diff --git a/common/kernel/basectx.h b/common/kernel/basectx.h index 21d6d63a..5775e47f 100644 --- a/common/kernel/basectx.h +++ b/common/kernel/basectx.h @@ -220,6 +220,10 @@ struct BaseCtx      void addBelToRegion(IdString name, BelId bel);      void constrainCellToRegion(IdString cell, IdString region_name); +    // Helper functions for the partial reconfiguration plug API using PseudoCells +    void createRegionPlug(IdString name, IdString type, Loc approx_loc); +    void addPlugPin(IdString plug, IdString pin, PortType dir, WireId wire); +      // Helper functions for Python bindings      NetInfo *createNet(IdString name);      void connectPort(IdString net, IdString cell, IdString port); diff --git a/common/kernel/context.cc b/common/kernel/context.cc index e35d3e49..014394a6 100644 --- a/common/kernel/context.cc +++ b/common/kernel/context.cc @@ -30,6 +30,9 @@ WireId Context::getNetinfoSourceWire(const NetInfo *net_info) const      if (net_info->driver.cell == nullptr)          return WireId(); +    if (net_info->driver.cell->isPseudo()) +        return net_info->driver.cell->pseudo_cell->getPortWire(net_info->driver.port); +      auto src_bel = net_info->driver.cell->bel;      if (src_bel == BelId()) @@ -47,6 +50,8 @@ WireId Context::getNetinfoSourceWire(const NetInfo *net_info) const  SSOArray<WireId, 2> Context::getNetinfoSinkWires(const NetInfo *net_info, const PortRef &user_info) const  { +    if (user_info.cell->isPseudo()) +        return SSOArray<WireId, 2>(1, user_info.cell->pseudo_cell->getPortWire(user_info.port));      auto dst_bel = user_info.cell->bel;      if (dst_bel == BelId())          return SSOArray<WireId, 2>(0, WireId()); diff --git a/common/kernel/context.h b/common/kernel/context.h index cb8fd257..4a5667d0 100644 --- a/common/kernel/context.h +++ b/common/kernel/context.h @@ -65,6 +65,24 @@ struct Context : Arch, DeterministicRNG                               dict<WireId, PipId> *route = nullptr, bool useEstimate = true);      // -------------------------------------------------------------- +    // Dispatch to the Arch API or pseudo-cell API accordingly +    bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override +    { +        return cell->pseudo_cell ? cell->pseudo_cell->getDelay(fromPort, toPort, delay) +                                 : Arch::getCellDelay(cell, fromPort, toPort, delay); +    } +    TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override +    { +        return cell->pseudo_cell ? cell->pseudo_cell->getPortTimingClass(port, clockInfoCount) +                                 : Arch::getPortTimingClass(cell, port, clockInfoCount); +    } +    TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const override +    { +        return cell->pseudo_cell ? cell->pseudo_cell->getPortClockingInfo(port, index) +                                 : Arch::getPortClockingInfo(cell, port, index); +    } + +    // --------------------------------------------------------------      // call after changing hierpath or adding/removing nets and cells      void fixupHierarchy(); diff --git a/common/kernel/nextpnr_types.cc b/common/kernel/nextpnr_types.cc index 82725d6f..8563eb27 100644 --- a/common/kernel/nextpnr_types.cc +++ b/common/kernel/nextpnr_types.cc @@ -177,4 +177,14 @@ void CellInfo::copyPortBusTo(IdString old_name, int old_offset, bool old_bracket      }  } +Loc CellInfo::getLocation() const +{ +    if (pseudo_cell) { +        return pseudo_cell->getLocation(); +    } else { +        NPNR_ASSERT(bel != BelId()); +        return ctx->getBelLocation(bel); +    } +} +  NEXTPNR_NAMESPACE_END diff --git a/common/kernel/nextpnr_types.h b/common/kernel/nextpnr_types.h index c21182cc..e4042aec 100644 --- a/common/kernel/nextpnr_types.h +++ b/common/kernel/nextpnr_types.h @@ -160,6 +160,59 @@ struct PortInfo  struct Context; +enum TimingPortClass +{ +    TMG_CLOCK_INPUT,     // Clock input to a sequential cell +    TMG_GEN_CLOCK,       // Generated clock output (PLL, DCC, etc) +    TMG_REGISTER_INPUT,  // Input to a register, with an associated clock (may also have comb. fanout too) +    TMG_REGISTER_OUTPUT, // Output from a register +    TMG_COMB_INPUT,      // Combinational input, no paths end here +    TMG_COMB_OUTPUT,     // Combinational output, no paths start here +    TMG_STARTPOINT,      // Unclocked primary startpoint, such as an IO cell output +    TMG_ENDPOINT,        // Unclocked primary endpoint, such as an IO cell input +    TMG_IGNORE,          // Asynchronous to all clocks, "don't care", and should be ignored (false path) for analysis +}; + +enum ClockEdge +{ +    RISING_EDGE, +    FALLING_EDGE +}; + +struct TimingClockingInfo +{ +    IdString clock_port; // Port name of clock domain +    ClockEdge edge; +    DelayPair setup, hold; // Input timing checks +    DelayQuad clockToQ;    // Output clock-to-Q time +}; + +struct PseudoCell +{ +    virtual Loc getLocation() const = 0; +    virtual WireId getPortWire(IdString port) const = 0; + +    virtual bool getDelay(IdString fromPort, IdString toPort, DelayQuad &delay) const = 0; +    virtual TimingPortClass getPortTimingClass(IdString port, int &clockInfoCount) const = 0; +    virtual TimingClockingInfo getPortClockingInfo(IdString port, int index) const = 0; +    virtual ~PseudoCell(){}; +}; + +struct RegionPlug : PseudoCell +{ +    RegionPlug(Loc loc) : loc(loc){}; // 'loc' is a notional location for the placer only +    Loc getLocation() const override { return loc; } +    WireId getPortWire(IdString port) const override { return port_wires.at(port); } + +    // TODO: partial reconfiguration region timing +    bool getDelay(IdString fromPort, IdString toPort, DelayQuad &delay) const { return false; } +    TimingPortClass getPortTimingClass(IdString port, int &clockInfoCount) const { return TMG_IGNORE; } +    virtual TimingClockingInfo getPortClockingInfo(IdString port, int index) const { return TimingClockingInfo{}; } + +    dict<IdString, WireId> port_wires; +    Loc loc; +}; +  struct CellInfo : ArchCellInfo  {      CellInfo(Context *ctx, IdString name, IdString type) : ctx(ctx), name(name), type(type){}; @@ -179,6 +232,8 @@ struct CellInfo : ArchCellInfo      Region *region = nullptr; +    std::unique_ptr<PseudoCell> pseudo_cell{}; +      void addInput(IdString name);      void addOutput(IdString name);      void addInout(IdString name); @@ -190,6 +245,10 @@ struct CellInfo : ArchCellInfo      // check whether a bel complies with the cell's region constraint      bool testRegion(BelId bel) const; +    bool isPseudo() const { return bool(pseudo_cell); } + +    Loc getLocation() const; +      NetInfo *getPort(IdString name)      {          auto found = ports.find(name); @@ -212,33 +271,6 @@ struct CellInfo : ArchCellInfo                         int new_offset, bool new_brackets, int width);  }; -enum TimingPortClass -{ -    TMG_CLOCK_INPUT,     // Clock input to a sequential cell -    TMG_GEN_CLOCK,       // Generated clock output (PLL, DCC, etc) -    TMG_REGISTER_INPUT,  // Input to a register, with an associated clock (may also have comb. fanout too) -    TMG_REGISTER_OUTPUT, // Output from a register -    TMG_COMB_INPUT,      // Combinational input, no paths end here -    TMG_COMB_OUTPUT,     // Combinational output, no paths start here -    TMG_STARTPOINT,      // Unclocked primary startpoint, such as an IO cell output -    TMG_ENDPOINT,        // Unclocked primary endpoint, such as an IO cell input -    TMG_IGNORE,          // Asynchronous to all clocks, "don't care", and should be ignored (false path) for analysis -}; - -enum ClockEdge -{ -    RISING_EDGE, -    FALLING_EDGE -}; - -struct TimingClockingInfo -{ -    IdString clock_port; // Port name of clock domain -    ClockEdge edge; -    DelayPair setup, hold; // Input timing checks -    DelayQuad clockToQ;    // Output clock-to-Q time -}; -  struct ClockConstraint  {      DelayPair high;  | 
