aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2019-10-19 16:08:11 +0100
committerDavid Shah <dave@ds0.me>2019-10-19 16:08:11 +0100
commitc0484a317d1a25a23541b60dd3bfc800230a0536 (patch)
treeeeca78ad55efcadc1334a934c8a8bad91e22aa93
parenta22f86f86192bbd782cc2fd430b2900ddb6740cc (diff)
downloadnextpnr-c0484a317d1a25a23541b60dd3bfc800230a0536.tar.gz
nextpnr-c0484a317d1a25a23541b60dd3bfc800230a0536.tar.bz2
nextpnr-c0484a317d1a25a23541b60dd3bfc800230a0536.zip
sdf: Framework for writing out SDF files
Signed-off-by: David Shah <dave@ds0.me>
-rw-r--r--common/sdf.cc200
1 files changed, 200 insertions, 0 deletions
diff --git a/common/sdf.cc b/common/sdf.cc
new file mode 100644
index 00000000..570b8aee
--- /dev/null
+++ b/common/sdf.cc
@@ -0,0 +1,200 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2019 David Shah <dave@ds0.me>
+ *
+ * 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 "nextpnr.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+namespace SDF {
+
+struct MinMaxTyp
+{
+ double min, typ, max;
+};
+
+struct RiseFallDelay
+{
+ MinMaxTyp rise, fall;
+};
+
+struct PortAndEdge
+{
+ std::string port;
+ ClockEdge edge;
+};
+
+struct IOPath
+{
+ std::string from, to;
+ RiseFallDelay delay;
+};
+
+struct TimingCheck
+{
+ enum CheckType
+ {
+ SETUPHOLD,
+ PERIOD,
+ WIDTH
+ } type;
+ PortAndEdge from, to;
+ RiseFallDelay delay;
+};
+
+struct Cell
+{
+ std::string celltype, instance;
+ std::vector<IOPath> iopaths;
+ std::vector<TimingCheck> checks;
+};
+
+struct CellPort
+{
+ std::string cell, port;
+};
+
+struct Interconnect
+{
+ CellPort from, to;
+ RiseFallDelay delay;
+};
+
+struct SDFWriter
+{
+ std::vector<Cell> cells;
+ std::vector<Interconnect> conn;
+ std::string sdfversion, design, vendor, program;
+
+ std::string format_name(const std::string &name)
+ {
+ std::string fmt = "\"";
+ for (char c : name) {
+ if (c == '\\' || c == '\"')
+ fmt += "\"";
+ fmt += c;
+ }
+ fmt += "\"";
+ return fmt;
+ }
+
+ std::string timing_check_name(TimingCheck::CheckType type)
+ {
+ switch (type) {
+ case TimingCheck::SETUPHOLD:
+ return "SETUPHOLD";
+ case TimingCheck::PERIOD:
+ return "PERIOD";
+ case TimingCheck::WIDTH:
+ return "WIDTH";
+ default:
+ NPNR_ASSERT_FALSE("unknown timing check type");
+ }
+ }
+
+ void write_delay(std::ostream &out, const RiseFallDelay &delay)
+ {
+ write_delay(out, delay.rise);
+ out << " ";
+ write_delay(out, delay.fall);
+ }
+
+ void write_delay(std::ostream &out, const MinMaxTyp &delay)
+ {
+ out << "(" << delay.min << ":" << delay.typ << ":" << delay.max << ")";
+ }
+
+ void write_port(std::ostream &out, const CellPort &port) { out << format_name(port.cell + "/" + port.port); }
+
+ void write_portedge(std::ostream &out, const PortAndEdge &pe)
+ {
+ out << "(" << (pe.edge == RISING_EDGE ? "posedge" : "negedge") << " " << pe.port << ")";
+ }
+
+ void write(std::ostream &out)
+ {
+ out << "(DELAYFILE" << std::endl;
+ // Headers and metadata
+ out << " (SDFVERSION " << format_name(sdfversion) << ")" << std::endl;
+ out << " (DESIGN " << format_name(design) << ")" << std::endl;
+ out << " (VENDOR " << format_name(vendor) << ")" << std::endl;
+ out << " (PROGRAM " << format_name(program) << ")" << std::endl;
+ out << " (DIVIDER /)" << std::endl;
+ out << " (TIMESCALE 1ps)" << std::endl;
+ // Write cells
+ for (auto &cell : cells) {
+ out << " (CELL" << std::endl;
+ out << " (CELLTYPE " << format_name(cell.celltype) << ")" << std::endl;
+ out << " (INSTANCE " << format_name(cell.instance) << ")" << std::endl;
+ // IOPATHs (combinational delay and clock-to-q)
+ if (!cell.iopaths.empty()) {
+ out << " (DELAY" << std::endl;
+ out << " (ABSOLUTE" << std::endl;
+ for (auto &path : cell.iopaths) {
+ out << " (IOPATH " << path.from << " " << path.to << " ";
+ write_delay(out, path.delay);
+ out << ")" << std::endl;
+ }
+ out << " )" << std::endl;
+ out << " )" << std::endl;
+ }
+ // Timing Checks (setup/hold, period, width)
+ if (!cell.checks.empty()) {
+ out << " (TIMINGCHECK" << std::endl;
+ for (auto &check : cell.checks) {
+ out << " (" << timing_check_name(check.type) << " ";
+ write_portedge(out, check.from);
+ out << " ";
+ if (check.type == TimingCheck::SETUPHOLD) {
+ write_portedge(out, check.to);
+ out << " ";
+ }
+ if (check.type == TimingCheck::SETUPHOLD)
+ write_delay(out, check.delay);
+ else
+ write_delay(out, check.delay.rise);
+ out << ")" << std::endl;
+ }
+ out << " )" << std::endl;
+ }
+ out << " )" << std::endl;
+ }
+ // Write interconnect delays, with the main design begin a "cell"
+ out << " (CELL" << std::endl;
+ out << " (CELLTYPE " << format_name(design) << ")" << std::endl;
+ out << " (DELAY" << std::endl;
+ out << " (ABSOLUTE" << std::endl;
+ for (auto &ic : conn) {
+ out << " (INTERCONNECT ";
+ write_port(out, ic.from);
+ out << " ";
+ write_port(out, ic.to);
+ out << " ";
+ write_delay(out, ic.delay);
+ out << std::endl;
+ }
+ out << " )" << std::endl;
+ out << " )" << std::endl;
+ out << " )" << std::endl;
+ out << ")" << std::endl;
+ }
+};
+
+} // namespace SDF
+
+NEXTPNR_NAMESPACE_END \ No newline at end of file