diff options
Diffstat (limited to 'fpga_interchange')
| -rw-r--r-- | fpga_interchange/arch.cc | 18 | ||||
| -rw-r--r-- | fpga_interchange/arch.h | 8 | ||||
| -rw-r--r-- | fpga_interchange/family.cmake | 9 | ||||
| -rw-r--r-- | fpga_interchange/main.cc | 22 | ||||
| -rw-r--r-- | fpga_interchange/xdc.cc | 152 | ||||
| -rw-r--r-- | fpga_interchange/xdc.h | 33 | 
6 files changed, 239 insertions, 3 deletions
diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc index 583813f0..1abf6f30 100644 --- a/fpga_interchange/arch.cc +++ b/fpga_interchange/arch.cc @@ -33,6 +33,7 @@  #include "router2.h"  #include "timing.h"  #include "util.h" +#include "xdc.h"  NEXTPNR_NAMESPACE_BEGIN @@ -558,6 +559,23 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port      return info;  } +// ----------------------------------------------------------------------- + +void Arch::read_logical_netlist(const std::string &filename) {} +void Arch::write_physical_netlist(const std::string &filename) const {} + +void Arch::parse_xdc(const std::string &filename) +{ +    TclInterp interp(getCtx()); +    auto result = Tcl_EvalFile(interp.interp, filename.c_str()); +    if (result != TCL_OK) { +        log_error("Error in %s:%d => %s\n", filename.c_str(), Tcl_GetErrorLine(interp.interp), +                  Tcl_GetStringResult(interp.interp)); +    } +} + +// ----------------------------------------------------------------------- +  #ifdef WITH_HEAP  const std::string Arch::defaultPlacer = "heap";  #else diff --git a/fpga_interchange/arch.h b/fpga_interchange/arch.h index 5964a38f..886978f1 100644 --- a/fpga_interchange/arch.h +++ b/fpga_interchange/arch.h @@ -650,6 +650,7 @@ struct BelBucketRange  struct ArchArgs  {      std::string chipdb; +    std::string package;  };  struct ArchRanges @@ -660,6 +661,7 @@ struct ArchRanges      using TileBelsRangeT = BelRange;      using BelAttrsRangeT = std::vector<std::pair<IdString, std::string>>;      using BelPinsRangeT = IdStringRange; +    using CellBelPinRangeT = std::array<IdString, 1>;      // Wires      using AllWiresRangeT = WireRange;      using DownhillPipRangeT = DownhillPipRange; @@ -865,6 +867,8 @@ struct Arch : ArchAPI<ArchRanges>          return str_range;      } +    std::array<IdString, 1> getBelPinsForCellPin(CellInfo *cell_info, IdString pin) const override { return {pin}; } +      // -------------------------------------------------      WireId getWireByName(IdStringList name) const override; @@ -1301,7 +1305,9 @@ struct Arch : ArchAPI<ArchRanges>      static const std::vector<std::string> availableRouters;      // ------------------------------------------------- -    void write_physical_netlist(const std::string &filename) const {} +    void read_logical_netlist(const std::string &filename); +    void write_physical_netlist(const std::string &filename) const; +    void parse_xdc(const std::string &filename);  };  NEXTPNR_NAMESPACE_END diff --git a/fpga_interchange/family.cmake b/fpga_interchange/family.cmake index e69de29b..c3fefaba 100644 --- a/fpga_interchange/family.cmake +++ b/fpga_interchange/family.cmake @@ -0,0 +1,9 @@ +find_package(TCL) +if(NOT ${TCL_FOUND}) +    message(FATAL_ERROR "Tcl is required for FPGA interchange Arch.") +endif() + +foreach (target ${family_targets}) +    target_link_libraries(${target} LINK_PUBLIC ${TCL_LIBRARY}) +    include_directories (${TCL_INCLUDE_PATH}) +endforeach() diff --git a/fpga_interchange/main.cc b/fpga_interchange/main.cc index 1f98b186..48b07584 100644 --- a/fpga_interchange/main.cc +++ b/fpga_interchange/main.cc @@ -49,8 +49,10 @@ po::options_description FpgaInterchangeCommandHandler::getArchOptions()  {      po::options_description specific("Architecture specific options");      specific.add_options()("chipdb", po::value<std::string>(), "name of chip database binary"); -    specific.add_options()("xdc", po::value<std::vector<std::string>>(), "XDC-style constraints file"); +    specific.add_options()("xdc", po::value<std::vector<std::string>>(), "XDC-style constraints file to read"); +    specific.add_options()("netlist", po::value<std::string>(), "FPGA interchange logical netlist to read");      specific.add_options()("phys", po::value<std::string>(), "FPGA interchange Physical netlist to write"); +    specific.add_options()("package", po::value<std::string>(), "Package to use");      return specific;  } @@ -70,7 +72,23 @@ std::unique_ptr<Context> FpgaInterchangeCommandHandler::createContext(std::unord          log_error("chip database binary must be provided\n");      }      chipArgs.chipdb = vm["chipdb"].as<std::string>(); -    return std::unique_ptr<Context>(new Context(chipArgs)); +    if (vm.count("package")) { +        chipArgs.package = vm["package"].as<std::string>(); +    } + +    auto ctx = std::unique_ptr<Context>(new Context(chipArgs)); + +    if (vm.count("netlist")) { +        ctx->read_logical_netlist(vm["netlist"].as<std::string>()); +    } + +    if (vm.count("xdc")) { +        for (auto &x : vm["xdc"].as<std::vector<std::string>>()) { +            ctx->parse_xdc(x); +        } +    } + +    return ctx;  }  void FpgaInterchangeCommandHandler::customAfterLoad(Context *ctx) {} diff --git a/fpga_interchange/xdc.cc b/fpga_interchange/xdc.cc new file mode 100644 index 00000000..584a1777 --- /dev/null +++ b/fpga_interchange/xdc.cc @@ -0,0 +1,152 @@ +/* + *  nextpnr -- Next Generation Place and Route + * + *  Copyright (C) 2019  David Shah <david@symbioticeda.com> + *  Copyright (C) 2021  Symbiflow Authors + * + *  Permission to use, copy, modify, and/or distribute this software for any + *  purpose with or without fee is hereby granted, provided that the above + *  copyright notice and this permission notice appear in all copies. + * + *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "xdc.h" +#include <string> +#include "log.h" +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +static int port_set_from_any(Tcl_Interp *interp, Tcl_Obj *objPtr) { return TCL_ERROR; } + +static void set_tcl_obj_string(Tcl_Obj *objPtr, const std::string &s) +{ +    NPNR_ASSERT(objPtr->bytes == nullptr); +    // Need to have space for the end null byte. +    objPtr->bytes = Tcl_Alloc(s.size() + 1); + +    // Length is length of string, not including the end null byte. +    objPtr->length = s.size(); + +    std::copy(s.begin(), s.end(), objPtr->bytes); +    objPtr->bytes[objPtr->length] = '\0'; +} + +static void port_update_string(Tcl_Obj *objPtr) +{ +    const Context *ctx = static_cast<const Context *>(objPtr->internalRep.twoPtrValue.ptr1); +    PortInfo *port_info = static_cast<PortInfo *>(objPtr->internalRep.twoPtrValue.ptr2); + +    std::string port_name = port_info->name.str(ctx); +    set_tcl_obj_string(objPtr, port_name); +} + +static void port_dup(Tcl_Obj *srcPtr, Tcl_Obj *dupPtr) +{ +    dupPtr->internalRep.twoPtrValue = srcPtr->internalRep.twoPtrValue; +} + +static void port_free(Tcl_Obj *objPtr) {} + +static void Tcl_SetStringResult(Tcl_Interp *interp, const std::string &s) +{ +    char *copy = Tcl_Alloc(s.size() + 1); +    std::copy(s.begin(), s.end(), copy); +    copy[s.size()] = '\0'; +    Tcl_SetResult(interp, copy, TCL_DYNAMIC); +} + +static Tcl_ObjType port_object = { +        "port", port_free, port_dup, port_update_string, port_set_from_any, +}; + +static int get_ports(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ +    const Context *ctx = static_cast<const Context *>(data); +    if (objc == 1) { +        // Return list of all ports. +        Tcl_SetStringResult(interp, "Unimplemented"); +        return TCL_ERROR; +    } else if (objc == 2) { +        const char *arg0 = Tcl_GetString(objv[1]); +        IdString port_name = ctx->id(arg0); + +        auto iter = ctx->ports.find(port_name); +        if (iter == ctx->ports.end()) { +            Tcl_SetStringResult(interp, "Could not find port " + port_name.str(ctx)); +            return TCL_ERROR; +        } + +        Tcl_Obj *result = Tcl_NewObj(); +        result->typePtr = &port_object; +        result->internalRep.twoPtrValue.ptr1 = (void *)(ctx); +        result->internalRep.twoPtrValue.ptr2 = (void *)(&iter->second); + +        result->bytes = nullptr; +        port_update_string(result); + +        Tcl_SetObjResult(interp, result); +        return TCL_OK; +    } else { +        return TCL_ERROR; +    } +} + +static int set_property(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ +    // set_property <property> <value> <object> +    if (objc != 4) { +        Tcl_SetStringResult(interp, "Only simple 'set_property <property> <value> <object>' is supported"); +        return TCL_ERROR; +    } + +    const char *property = Tcl_GetString(objv[1]); +    const char *value = Tcl_GetString(objv[2]); +    const Tcl_Obj *object = objv[3]; + +    if (object->typePtr != &port_object) { +        Tcl_SetStringResult(interp, "Only port objects are handled right now!"); +        return TCL_ERROR; +    } + +    const Context *ctx = static_cast<const Context *>(object->internalRep.twoPtrValue.ptr1); +    PortInfo *port_info = static_cast<PortInfo *>(object->internalRep.twoPtrValue.ptr2); +    NPNR_ASSERT(port_info->net != nullptr); +    CellInfo *cell = ctx->port_cells.at(port_info->name); + +    cell->attrs[ctx->id(property)] = Property(value); + +    return TCL_OK; +} + +TclInterp::TclInterp(Context *ctx) +{ +    interp = Tcl_CreateInterp(); +    NPNR_ASSERT(Tcl_Init(interp) == TCL_OK); + +    Tcl_RegisterObjType(&port_object); + +    NPNR_ASSERT(Tcl_Eval(interp, "rename unknown _original_unknown") == TCL_OK); +    NPNR_ASSERT(Tcl_Eval(interp, "proc unknown args {\n" +                                 "  set result [scan [lindex $args 0] \"%d\" value]\n" +                                 "  if { $result == 1 && [llength $args] == 1 } {\n" +                                 "    return \\[$value\\]\n" +                                 "  } else {\n" +                                 "    uplevel 1 [list _original_unknown {*}$args]\n" +                                 "  }\n" +                                 "}") == TCL_OK); +    Tcl_CreateObjCommand(interp, "get_ports", get_ports, ctx, nullptr); +    Tcl_CreateObjCommand(interp, "set_property", set_property, ctx, nullptr); +} + +TclInterp::~TclInterp() { Tcl_DeleteInterp(interp); } + +NEXTPNR_NAMESPACE_END diff --git a/fpga_interchange/xdc.h b/fpga_interchange/xdc.h new file mode 100644 index 00000000..c6b80870 --- /dev/null +++ b/fpga_interchange/xdc.h @@ -0,0 +1,33 @@ +/* + *  nextpnr -- Next Generation Place and Route + * + *  Copyright (C) 2021  Symbiflow Authors + * + *  Permission to use, copy, modify, and/or distribute this software for any + *  purpose with or without fee is hereby granted, provided that the above + *  copyright notice and this permission notice appear in all copies. + * + *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include <tcl.h> +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +struct TclInterp +{ +    TclInterp(Context *ctx); +    ~TclInterp(); + +    Tcl_Interp *interp; +}; + +NEXTPNR_NAMESPACE_END  | 
