aboutsummaryrefslogtreecommitdiffstats
path: root/bba/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'bba/main.cc')
-rw-r--r--bba/main.cc427
1 files changed, 427 insertions, 0 deletions
diff --git a/bba/main.cc b/bba/main.cc
new file mode 100644
index 00000000..263cf39e
--- /dev/null
+++ b/bba/main.cc
@@ -0,0 +1,427 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
+ * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.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 <assert.h>
+#include <boost/program_options.hpp>
+#include <iostream>
+#include <map>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+#include <vector>
+
+enum TokenType : int8_t
+{
+ TOK_LABEL,
+ TOK_REF,
+ TOK_U8,
+ TOK_U16,
+ TOK_U32
+};
+
+struct Stream
+{
+ std::string name;
+ std::vector<TokenType> tokenTypes;
+ std::vector<uint32_t> tokenValues;
+ std::vector<std::string> tokenComments;
+};
+
+Stream stringStream;
+std::vector<Stream> streams;
+std::map<std::string, int> streamIndex;
+std::vector<int> streamStack;
+
+std::vector<int> labels;
+std::vector<std::string> labelNames;
+std::map<std::string, int> labelIndex;
+
+std::vector<std::string> preText, postText;
+
+const char *skipWhitespace(const char *p)
+{
+ if (p == nullptr)
+ return "";
+ while (*p == ' ' || *p == '\t')
+ p++;
+ return p;
+}
+
+int main(int argc, char **argv)
+{
+ bool debug = false;
+ bool verbose = false;
+ bool bigEndian = false;
+ bool writeC = false;
+ char buffer[512];
+
+ namespace po = boost::program_options;
+ po::positional_options_description pos;
+ po::options_description options("Allowed options");
+ options.add_options()("v", "verbose output");
+ options.add_options()("d", "debug output");
+ options.add_options()("b", "big endian");
+ options.add_options()("c", "write c strings");
+ options.add_options()("files", po::value<std::vector<std::string>>(), "file parameters");
+ pos.add("files", -1);
+
+ po::variables_map vm;
+ try {
+ po::parsed_options parsed = po::command_line_parser(argc, argv).options(options).positional(pos).run();
+
+ po::store(parsed, vm);
+
+ po::notify(vm);
+ } catch (std::exception &e) {
+ std::cout << e.what() << "\n";
+ return 1;
+ }
+ if (vm.count("v"))
+ verbose = true;
+ if (vm.count("d"))
+ debug = true;
+ if (vm.count("b"))
+ bigEndian = true;
+ if (vm.count("c"))
+ writeC = true;
+
+ if (vm.count("files") == 0) {
+ printf("File parameters are mandatory\n");
+ exit(-1);
+ }
+ std::vector<std::string> files = vm["files"].as<std::vector<std::string>>();
+ if (files.size() != 2) {
+ printf("Input and output parameters must be set\n");
+ exit(-1);
+ }
+
+ FILE *fileIn = fopen(files.at(0).c_str(), "rt");
+ assert(fileIn != nullptr);
+
+ FILE *fileOut = fopen(files.at(1).c_str(), writeC ? "wt" : "wb");
+ assert(fileOut != nullptr);
+
+ while (fgets(buffer, 512, fileIn) != nullptr) {
+ std::string cmd = strtok(buffer, " \t\r\n");
+
+ if (cmd == "pre") {
+ const char *p = skipWhitespace(strtok(nullptr, "\r\n"));
+ preText.push_back(p);
+ continue;
+ }
+
+ if (cmd == "post") {
+ const char *p = skipWhitespace(strtok(nullptr, "\r\n"));
+ postText.push_back(p);
+ continue;
+ }
+
+ if (cmd == "push") {
+ const char *p = strtok(nullptr, " \t\r\n");
+ if (streamIndex.count(p) == 0) {
+ streamIndex[p] = streams.size();
+ streams.resize(streams.size() + 1);
+ streams.back().name = p;
+ }
+ streamStack.push_back(streamIndex.at(p));
+ continue;
+ }
+
+ if (cmd == "pop") {
+ streamStack.pop_back();
+ continue;
+ }
+
+ if (cmd == "label" || cmd == "ref") {
+ const char *label = strtok(nullptr, " \t\r\n");
+ const char *comment = skipWhitespace(strtok(nullptr, "\r\n"));
+ Stream &s = streams.at(streamStack.back());
+ if (labelIndex.count(label) == 0) {
+ labelIndex[label] = labels.size();
+ if (debug)
+ labelNames.push_back(label);
+ labels.push_back(-1);
+ }
+ s.tokenTypes.push_back(cmd == "label" ? TOK_LABEL : TOK_REF);
+ s.tokenValues.push_back(labelIndex.at(label));
+ if (debug)
+ s.tokenComments.push_back(comment);
+ continue;
+ }
+
+ if (cmd == "u8" || cmd == "u16" || cmd == "u32") {
+ const char *value = strtok(nullptr, " \t\r\n");
+ const char *comment = skipWhitespace(strtok(nullptr, "\r\n"));
+ Stream &s = streams.at(streamStack.back());
+ s.tokenTypes.push_back(cmd == "u8" ? TOK_U8 : cmd == "u16" ? TOK_U16 : TOK_U32);
+ s.tokenValues.push_back(atoll(value));
+ if (debug)
+ s.tokenComments.push_back(comment);
+ continue;
+ }
+
+ if (cmd == "str") {
+ const char *value = skipWhitespace(strtok(nullptr, "\r\n"));
+ char terminator[2] = {*value, 0};
+ assert(terminator[0] != 0);
+ value = strtok((char *)value + 1, terminator);
+ const char *comment = skipWhitespace(strtok(nullptr, "\r\n"));
+ std::string label = std::string("str:") + value;
+ Stream &s = streams.at(streamStack.back());
+ if (labelIndex.count(label) == 0) {
+ labelIndex[label] = labels.size();
+ if (debug)
+ labelNames.push_back(label);
+ labels.push_back(-1);
+ }
+ s.tokenTypes.push_back(TOK_REF);
+ s.tokenValues.push_back(labelIndex.at(label));
+ if (debug)
+ s.tokenComments.push_back(comment);
+ stringStream.tokenTypes.push_back(TOK_LABEL);
+ stringStream.tokenValues.push_back(labelIndex.at(label));
+ stringStream.tokenComments.push_back("");
+ while (1) {
+ stringStream.tokenTypes.push_back(TOK_U8);
+ stringStream.tokenValues.push_back(*value);
+ if (debug) {
+ char char_comment[4] = {'\'', *value, '\'', 0};
+ if (*value < 32 || *value >= 127)
+ char_comment[0] = 0;
+ stringStream.tokenComments.push_back(char_comment);
+ }
+ if (*value == 0)
+ break;
+ value++;
+ }
+ continue;
+ }
+
+ assert(0);
+ }
+
+ if (verbose) {
+ printf("Constructed %d streams:\n", int(streams.size()));
+ for (auto &s : streams)
+ printf(" stream '%s' with %d tokens\n", s.name.c_str(), int(s.tokenTypes.size()));
+ }
+
+ assert(!streams.empty());
+ assert(streamStack.empty());
+ streams.push_back(Stream());
+ streams.back().name = "strings";
+ streams.back().tokenTypes.swap(stringStream.tokenTypes);
+ streams.back().tokenValues.swap(stringStream.tokenValues);
+ streams.back().tokenComments.swap(stringStream.tokenComments);
+
+ int cursor = 0;
+ for (auto &s : streams) {
+ for (int i = 0; i < int(s.tokenTypes.size()); i++) {
+ switch (s.tokenTypes[i]) {
+ case TOK_LABEL:
+ labels[s.tokenValues[i]] = cursor;
+ break;
+ case TOK_REF:
+ cursor += 4;
+ break;
+ case TOK_U8:
+ cursor += 1;
+ break;
+ case TOK_U16:
+ assert(cursor % 2 == 0);
+ cursor += 2;
+ break;
+ case TOK_U32:
+ assert(cursor % 4 == 0);
+ cursor += 4;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ }
+
+ if (verbose) {
+ printf("resolved positions for %d labels.\n", int(labels.size()));
+ printf("total data (including strings): %.2f MB\n", double(cursor) / (1024 * 1024));
+ }
+
+ std::vector<uint8_t> data(cursor);
+
+ cursor = 0;
+ for (auto &s : streams) {
+ if (debug)
+ printf("-- %s --\n", s.name.c_str());
+
+ for (int i = 0; i < int(s.tokenTypes.size()); i++) {
+ uint32_t value = s.tokenValues[i];
+ int numBytes = 0;
+
+ switch (s.tokenTypes[i]) {
+ case TOK_LABEL:
+ break;
+ case TOK_REF:
+ value = labels[value] - cursor;
+ numBytes = 4;
+ break;
+ case TOK_U8:
+ numBytes = 1;
+ break;
+ case TOK_U16:
+ numBytes = 2;
+ break;
+ case TOK_U32:
+ numBytes = 4;
+ break;
+ default:
+ assert(0);
+ }
+
+ if (bigEndian) {
+ switch (numBytes) {
+ case 4:
+ data[cursor++] = value >> 24;
+ data[cursor++] = value >> 16;
+ /* fall-through */
+ case 2:
+ data[cursor++] = value >> 8;
+ /* fall-through */
+ case 1:
+ data[cursor++] = value;
+ /* fall-through */
+ case 0:
+ break;
+ default:
+ assert(0);
+ }
+ } else {
+ switch (numBytes) {
+ case 4:
+ data[cursor + 3] = value >> 24;
+ data[cursor + 2] = value >> 16;
+ /* fall-through */
+ case 2:
+ data[cursor + 1] = value >> 8;
+ /* fall-through */
+ case 1:
+ data[cursor] = value;
+ /* fall-through */
+ case 0:
+ break;
+ default:
+ assert(0);
+ }
+ cursor += numBytes;
+ }
+
+ if (debug) {
+ printf("%08x ", cursor - numBytes);
+ for (int k = cursor - numBytes; k < cursor; k++)
+ printf("%02x ", data[k]);
+ for (int k = numBytes; k < 4; k++)
+ printf(" ");
+
+ unsigned long long v = s.tokenValues[i];
+
+ switch (s.tokenTypes[i]) {
+ case TOK_LABEL:
+ if (s.tokenComments[i].empty())
+ printf("label %s\n", labelNames[v].c_str());
+ else
+ printf("label %-24s %s\n", labelNames[v].c_str(), s.tokenComments[i].c_str());
+ break;
+ case TOK_REF:
+ if (s.tokenComments[i].empty())
+ printf("ref %s\n", labelNames[v].c_str());
+ else
+ printf("ref %-26s %s\n", labelNames[v].c_str(), s.tokenComments[i].c_str());
+ break;
+ case TOK_U8:
+ if (s.tokenComments[i].empty())
+ printf("u8 %llu\n", v);
+ else
+ printf("u8 %-27llu %s\n", v, s.tokenComments[i].c_str());
+ break;
+ case TOK_U16:
+ if (s.tokenComments[i].empty())
+ printf("u16 %-26llu\n", v);
+ else
+ printf("u16 %-26llu %s\n", v, s.tokenComments[i].c_str());
+ break;
+ case TOK_U32:
+ if (s.tokenComments[i].empty())
+ printf("u32 %-26llu\n", v);
+ else
+ printf("u32 %-26llu %s\n", v, s.tokenComments[i].c_str());
+ break;
+ default:
+ assert(0);
+ }
+ }
+ }
+ }
+
+ assert(cursor == int(data.size()));
+
+ if (writeC) {
+ for (auto &s : preText)
+ fprintf(fileOut, "%s\n", s.c_str());
+
+ fprintf(fileOut, "const char %s[%d] =\n\"", streams[0].name.c_str(), int(data.size()) + 1);
+
+ cursor = 1;
+ for (int i = 0; i < int(data.size()); i++) {
+ auto d = data[i];
+ if (cursor > 70) {
+ fputc('\"', fileOut);
+ fputc('\n', fileOut);
+ cursor = 0;
+ }
+ if (cursor == 0) {
+ fputc('\"', fileOut);
+ cursor = 1;
+ }
+ if (d < 32 || d >= 127) {
+ if (i + 1 < int(data.size()) && (data[i + 1] < '0' || '9' < data[i + 1]))
+ cursor += fprintf(fileOut, "\\%o", int(d));
+ else
+ cursor += fprintf(fileOut, "\\%03o", int(d));
+ } else if (d == '\"' || d == '\'' || d == '\\') {
+ fputc('\\', fileOut);
+ fputc(d, fileOut);
+ cursor += 2;
+ } else {
+ fputc(d, fileOut);
+ cursor++;
+ }
+ }
+
+ fprintf(fileOut, "\";\n");
+
+ for (auto &s : postText)
+ fprintf(fileOut, "%s\n", s.c_str());
+ } else {
+ fwrite(data.data(), int(data.size()), 1, fileOut);
+ }
+
+ return 0;
+}