aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--machxo2/bitstream.cc32
-rw-r--r--machxo2/bitstream.h32
-rw-r--r--machxo2/config.cc357
-rw-r--r--machxo2/config.h128
-rw-r--r--machxo2/main.cc12
5 files changed, 559 insertions, 2 deletions
diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc
new file mode 100644
index 00000000..6e1dbb11
--- /dev/null
+++ b/machxo2/bitstream.cc
@@ -0,0 +1,32 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 David Shah <david@symbioticeda.com>
+ * Copyright (C) 2021 William D. Jones <wjones@wdj-consulting.com>
+ *
+ * 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 "bitstream.h"
+#include "config.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+void write_bitstream(Context *ctx, std::string text_config_file)
+{
+ ChipConfig cc;
+
+}
+
+NEXTPNR_NAMESPACE_END
diff --git a/machxo2/bitstream.h b/machxo2/bitstream.h
new file mode 100644
index 00000000..f7965c4f
--- /dev/null
+++ b/machxo2/bitstream.h
@@ -0,0 +1,32 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 David Shah <david@symbioticeda.com>
+ * Copyright (C) 2021 William D. Jones <wjones@wdj-consulting.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef BITSTREAM_H
+#define BITSTREAM_H
+
+#include "nextpnr.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+void write_bitstream(Context *ctx, std::string text_config_file = "");
+
+NEXTPNR_NAMESPACE_END
+
+#endif // BITSTREAM_H
diff --git a/machxo2/config.cc b/machxo2/config.cc
new file mode 100644
index 00000000..2e17ce24
--- /dev/null
+++ b/machxo2/config.cc
@@ -0,0 +1,357 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 David Shah <david@symbioticeda.com>
+ * Copyright (C) 2021 William D. Jones <wjones@wdj-consulting.com>
+ *
+ * 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 "config.h"
+#include <boost/range/adaptor/reversed.hpp>
+#include <iomanip>
+#include "log.h"
+NEXTPNR_NAMESPACE_BEGIN
+
+#define fmt(x) (static_cast<const std::ostringstream &>(std::ostringstream() << x).str())
+
+inline std::string to_string(const std::vector<bool> &bv)
+{
+ std::ostringstream os;
+ for (auto bit : boost::adaptors::reverse(bv))
+ os << (bit ? '1' : '0');
+ return os.str();
+}
+
+inline std::istream &operator>>(std::istream &in, std::vector<bool> &bv)
+{
+ bv.clear();
+ std::string s;
+ in >> s;
+ for (auto c : boost::adaptors::reverse(s)) {
+ assert((c == '0') || (c == '1'));
+ bv.push_back((c == '1'));
+ }
+ return in;
+}
+
+struct ConfigBit
+{
+ int frame;
+ int bit;
+ bool inv;
+};
+
+static ConfigBit cbit_from_str(const std::string &s)
+{
+ size_t idx = 0;
+ ConfigBit b;
+ if (s[idx] == '!') {
+ b.inv = true;
+ ++idx;
+ } else {
+ b.inv = false;
+ }
+ NPNR_ASSERT(s[idx] == 'F');
+ ++idx;
+ size_t b_pos = s.find('B');
+ NPNR_ASSERT(b_pos != std::string::npos);
+ b.frame = stoi(s.substr(idx, b_pos - idx));
+ b.bit = stoi(s.substr(b_pos + 1));
+ return b;
+}
+
+inline std::string to_string(ConfigBit b)
+{
+ std::ostringstream ss;
+ if (b.inv)
+ ss << "!";
+ ss << "F" << b.frame;
+ ss << "B" << b.bit;
+ return ss.str();
+}
+
+// Skip whitespace, optionally including newlines
+inline void skip_blank(std::istream &in, bool nl = false)
+{
+ int c = in.peek();
+ while (in && (((c == ' ') || (c == '\t')) || (nl && ((c == '\n') || (c == '\r'))))) {
+ in.get();
+ c = in.peek();
+ }
+}
+// Return true if end of line (or file)
+inline bool skip_check_eol(std::istream &in)
+{
+ skip_blank(in, false);
+ if (!in)
+ return false;
+ int c = in.peek();
+ // Comments count as end of line
+ if (c == '#') {
+ in.get();
+ c = in.peek();
+ while (in && c != EOF && c != '\n') {
+ in.get();
+ c = in.peek();
+ }
+ return true;
+ }
+ return (c == EOF || c == '\n');
+}
+
+// Skip past blank lines and comments
+inline void skip(std::istream &in)
+{
+ skip_blank(in, true);
+ while (in && (in.peek() == '#')) {
+ // Skip comment line
+ skip_check_eol(in);
+ skip_blank(in, true);
+ }
+}
+
+// Return true if at the end of a record (or file)
+inline bool skip_check_eor(std::istream &in)
+{
+ skip(in);
+ int c = in.peek();
+ return (c == EOF || c == '.');
+}
+
+// Return true if at the end of file
+inline bool skip_check_eof(std::istream &in)
+{
+ skip(in);
+ int c = in.peek();
+ return (c == EOF);
+}
+
+std::ostream &operator<<(std::ostream &out, const ConfigArc &arc)
+{
+ out << "arc: " << arc.sink << " " << arc.source << std::endl;
+ return out;
+}
+
+std::istream &operator>>(std::istream &in, ConfigArc &arc)
+{
+ in >> arc.sink;
+ in >> arc.source;
+ return in;
+}
+
+std::ostream &operator<<(std::ostream &out, const ConfigWord &cw)
+{
+ out << "word: " << cw.name << " " << to_string(cw.value) << std::endl;
+ return out;
+}
+
+std::istream &operator>>(std::istream &in, ConfigWord &cw)
+{
+ in >> cw.name;
+ in >> cw.value;
+ return in;
+}
+
+std::ostream &operator<<(std::ostream &out, const ConfigEnum &cw)
+{
+ out << "enum: " << cw.name << " " << cw.value << std::endl;
+ return out;
+}
+
+std::istream &operator>>(std::istream &in, ConfigEnum &ce)
+{
+ in >> ce.name;
+ in >> ce.value;
+ return in;
+}
+
+std::ostream &operator<<(std::ostream &out, const ConfigUnknown &cu)
+{
+ out << "unknown: " << to_string(ConfigBit{cu.frame, cu.bit, false}) << std::endl;
+ return out;
+}
+
+std::istream &operator>>(std::istream &in, ConfigUnknown &cu)
+{
+ std::string s;
+ in >> s;
+ ConfigBit c = cbit_from_str(s);
+ cu.frame = c.frame;
+ cu.bit = c.bit;
+ assert(!c.inv);
+ return in;
+}
+
+std::ostream &operator<<(std::ostream &out, const TileConfig &tc)
+{
+ for (const auto &arc : tc.carcs)
+ out << arc;
+ for (const auto &cword : tc.cwords)
+ out << cword;
+ for (const auto &cenum : tc.cenums)
+ out << cenum;
+ for (const auto &cunk : tc.cunknowns)
+ out << cunk;
+ return out;
+}
+
+std::istream &operator>>(std::istream &in, TileConfig &tc)
+{
+ tc.carcs.clear();
+ tc.cwords.clear();
+ tc.cenums.clear();
+ while (!skip_check_eor(in)) {
+ std::string type;
+ in >> type;
+ if (type == "arc:") {
+ ConfigArc a;
+ in >> a;
+ tc.carcs.push_back(a);
+ } else if (type == "word:") {
+ ConfigWord w;
+ in >> w;
+ tc.cwords.push_back(w);
+ } else if (type == "enum:") {
+ ConfigEnum e;
+ in >> e;
+ tc.cenums.push_back(e);
+ } else if (type == "unknown:") {
+ ConfigUnknown u;
+ in >> u;
+ tc.cunknowns.push_back(u);
+ } else {
+ NPNR_ASSERT_FALSE_STR("unexpected token " + type + " while reading config text");
+ }
+ }
+ return in;
+}
+
+void TileConfig::add_arc(const std::string &sink, const std::string &source) { carcs.push_back({sink, source}); }
+
+void TileConfig::add_word(const std::string &name, const std::vector<bool> &value) { cwords.push_back({name, value}); }
+
+void TileConfig::add_enum(const std::string &name, const std::string &value) { cenums.push_back({name, value}); }
+
+void TileConfig::add_unknown(int frame, int bit) { cunknowns.push_back({frame, bit}); }
+
+std::string TileConfig::to_string() const
+{
+ std::stringstream ss;
+ ss << *this;
+ return ss.str();
+}
+
+TileConfig TileConfig::from_string(const std::string &str)
+{
+ std::stringstream ss(str);
+ TileConfig tc;
+ ss >> tc;
+ return tc;
+}
+
+bool TileConfig::empty() const { return carcs.empty() && cwords.empty() && cenums.empty() && cunknowns.empty(); }
+
+std::ostream &operator<<(std::ostream &out, const ChipConfig &cc)
+{
+ out << ".device " << cc.chip_name << std::endl << std::endl;
+ for (const auto &meta : cc.metadata)
+ out << ".comment " << meta << std::endl;
+ for (const auto &sc : cc.sysconfig)
+ out << ".sysconfig " << sc.first << " " << sc.second << std::endl;
+ out << std::endl;
+ for (const auto &tile : cc.tiles) {
+ if (!tile.second.empty()) {
+ out << ".tile " << tile.first << std::endl;
+ out << tile.second;
+ out << std::endl;
+ }
+ }
+ for (const auto &bram : cc.bram_data) {
+ out << ".bram_init " << bram.first << std::endl;
+ std::ios_base::fmtflags f(out.flags());
+ for (size_t i = 0; i < bram.second.size(); i++) {
+ out << std::setw(3) << std::setfill('0') << std::hex << bram.second.at(i);
+ if (i % 8 == 7)
+ out << std::endl;
+ else
+ out << " ";
+ }
+ out.flags(f);
+ out << std::endl;
+ }
+ for (const auto &tg : cc.tilegroups) {
+ out << ".tile_group";
+ for (const auto &tile : tg.tiles) {
+ out << " " << tile;
+ }
+ out << std::endl;
+ out << tg.config;
+ out << std::endl;
+ }
+ return out;
+}
+
+std::istream &operator>>(std::istream &in, ChipConfig &cc)
+{
+ while (!skip_check_eof(in)) {
+ std::string verb;
+ in >> verb;
+ if (verb == ".device") {
+ in >> cc.chip_name;
+ } else if (verb == ".comment") {
+ std::string line;
+ getline(in, line);
+ cc.metadata.push_back(line);
+ } else if (verb == ".sysconfig") {
+ std::string key, value;
+ in >> key >> value;
+ cc.sysconfig[key] = value;
+ } else if (verb == ".tile") {
+ std::string tilename;
+ in >> tilename;
+ TileConfig tc;
+ in >> tc;
+ cc.tiles[tilename] = tc;
+ } else if (verb == ".tile_group") {
+ TileGroup tg;
+ std::string line;
+ getline(in, line);
+ std::stringstream ss2(line);
+
+ std::string tile;
+ while (ss2) {
+ ss2 >> tile;
+ tg.tiles.push_back(tile);
+ }
+ in >> tg.config;
+ cc.tilegroups.push_back(tg);
+ } else if (verb == ".bram_init") {
+ uint16_t bram;
+ in >> bram;
+ std::ios_base::fmtflags f(in.flags());
+ while (!skip_check_eor(in)) {
+ uint16_t value;
+ in >> std::hex >> value;
+ cc.bram_data[bram].push_back(value);
+ }
+ in.flags(f);
+ } else {
+ log_error("unrecognised config entry %s\n", verb.c_str());
+ }
+ }
+ return in;
+}
+
+NEXTPNR_NAMESPACE_END
diff --git a/machxo2/config.h b/machxo2/config.h
new file mode 100644
index 00000000..9e09d721
--- /dev/null
+++ b/machxo2/config.h
@@ -0,0 +1,128 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 David Shah <david@symbioticeda.com>
+ * Copyright (C) 2021 William D. Jones <wjones@wdj-consulting.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef MACHXO2_CONFIG_H
+#define MACHXO2_CONFIG_H
+
+#include <map>
+#include "nextpnr.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+// This represents configuration at "FASM" level, in terms of routing arcs and non-routing configuration settings -
+// either words or enums.
+
+// A connection in a tile
+struct ConfigArc
+{
+ std::string sink;
+ std::string source;
+ inline bool operator==(const ConfigArc &other) const { return other.source == source && other.sink == sink; }
+};
+
+std::ostream &operator<<(std::ostream &out, const ConfigArc &arc);
+
+std::istream &operator>>(std::istream &in, ConfigArc &arc);
+
+// A configuration setting in a tile that takes one or more bits (such as LUT init)
+struct ConfigWord
+{
+ std::string name;
+ std::vector<bool> value;
+ inline bool operator==(const ConfigWord &other) const { return other.name == name && other.value == value; }
+};
+
+std::ostream &operator<<(std::ostream &out, const ConfigWord &cw);
+
+std::istream &operator>>(std::istream &in, ConfigWord &cw);
+
+// A configuration setting in a tile that takes an enumeration value (such as IO type)
+struct ConfigEnum
+{
+ std::string name;
+ std::string value;
+ inline bool operator==(const ConfigEnum &other) const { return other.name == name && other.value == value; }
+};
+
+std::ostream &operator<<(std::ostream &out, const ConfigEnum &ce);
+
+std::istream &operator>>(std::istream &in, ConfigEnum &ce);
+
+// An unknown bit, specified by position only
+struct ConfigUnknown
+{
+ int frame, bit;
+ inline bool operator==(const ConfigUnknown &other) const { return other.frame == frame && other.bit == bit; }
+};
+
+std::ostream &operator<<(std::ostream &out, const ConfigUnknown &tc);
+
+std::istream &operator>>(std::istream &in, ConfigUnknown &ce);
+
+struct TileConfig
+{
+ std::vector<ConfigArc> carcs;
+ std::vector<ConfigWord> cwords;
+ std::vector<ConfigEnum> cenums;
+ std::vector<ConfigUnknown> cunknowns;
+ int total_known_bits = 0;
+
+ void add_arc(const std::string &sink, const std::string &source);
+ void add_word(const std::string &name, const std::vector<bool> &value);
+ void add_enum(const std::string &name, const std::string &value);
+ void add_unknown(int frame, int bit);
+
+ std::string to_string() const;
+ static TileConfig from_string(const std::string &str);
+
+ bool empty() const;
+};
+
+std::ostream &operator<<(std::ostream &out, const TileConfig &tc);
+
+std::istream &operator>>(std::istream &in, TileConfig &ce);
+
+// A group of tiles to configure at once for a particular feature that is split across tiles
+// TileGroups are currently for non-routing configuration only
+struct TileGroup
+{
+ std::vector<std::string> tiles;
+ TileConfig config;
+};
+
+// This represents the configuration of a chip at a high level
+class ChipConfig
+{
+ public:
+ std::string chip_name;
+ std::vector<std::string> metadata;
+ std::map<std::string, TileConfig> tiles;
+ std::vector<TileGroup> tilegroups;
+ std::map<std::string, std::string> sysconfig;
+ std::map<uint16_t, std::vector<uint16_t>> bram_data;
+};
+
+std::ostream &operator<<(std::ostream &out, const ChipConfig &cc);
+
+std::istream &operator>>(std::istream &in, ChipConfig &cc);
+
+NEXTPNR_NAMESPACE_END
+
+#endif
diff --git a/machxo2/main.cc b/machxo2/main.cc
index 5a5c7f82..1d393fac 100644
--- a/machxo2/main.cc
+++ b/machxo2/main.cc
@@ -20,6 +20,7 @@
#ifdef MAIN_EXECUTABLE
#include <fstream>
+#include "bitstream.h"
#include "command.h"
#include "design_utils.h"
#include "log.h"
@@ -65,13 +66,20 @@ po::options_description MachXO2CommandHandler::getArchOptions()
"base chip configuration in Trellis text format");
specific.add_options()("textcfg", po::value<std::string>(), "textual configuration in Trellis format to write");
- specific.add_options()("lpf", po::value<std::vector<std::string>>(), "LPF pin constraint file(s)");
+ //specific.add_options()("lpf", po::value<std::vector<std::string>>(), "LPF pin constraint file(s)");
specific.add_options()("no-iobs", "disable automatic IO buffer insertion (unimplemented- always enabled)");
return specific;
}
-void MachXO2CommandHandler::customBitstream(Context *ctx) {}
+void MachXO2CommandHandler::customBitstream(Context *ctx)
+{
+ std::string textcfg;
+ if (vm.count("textcfg"))
+ textcfg = vm["textcfg"].as<std::string>();
+
+ write_bitstream(ctx, textcfg);
+}
std::unique_ptr<Context> MachXO2CommandHandler::createContext(std::unordered_map<std::string, Property> &values)
{