Merge pull request #69 from EnJens/spi-mode

libtrellis: Allow specifying spimode for ecppack
diff --git a/libtrellis/include/Bitstream.hpp b/libtrellis/include/Bitstream.hpp
index 7e00910..08b2d82 100644
--- a/libtrellis/include/Bitstream.hpp
+++ b/libtrellis/include/Bitstream.hpp
@@ -12,6 +12,7 @@
 
 namespace Trellis {
 enum class BitstreamCommand : uint8_t {
+    SPI_MODE = 0b01111001,
     LSC_RESET_CRC = 0b00111011,
     VERIFY_ID = 0b11100010,
     LSC_WRITE_COMP_DIC = 0b00000010,
diff --git a/libtrellis/src/Bitstream.cpp b/libtrellis/src/Bitstream.cpp
index 16d6c8c..d87186a 100644
--- a/libtrellis/src/Bitstream.cpp
+++ b/libtrellis/src/Bitstream.cpp
@@ -23,6 +23,11 @@
      {"38.8", 0x38},
      {"62.0", 0x3b}};
 
+static const vector<pair<std::string, uint8_t>> spi_modes =
+    {{"fast-read", 0x49},
+     {"dual-spi", 0x51},
+     {"qspi", 0x59}};
+
 // The BitstreamReadWriter class stores state (including CRC16) whilst reading
 // the bitstream
 class BitstreamReadWriter {
@@ -356,6 +361,20 @@
                 rd.check_crc16();
             }
                 break;
+            case BitstreamCommand::SPI_MODE: {
+                uint8_t spi_mode;
+                rd.get_bytes(&spi_mode, 1);
+                rd.skip_bytes(2);
+
+                auto spimode = find_if(spi_modes.begin(), spi_modes.end(), [&](const pair<string, uint8_t> &fp){
+                    return fp.second == spi_mode;
+                });
+                if (spimode == spi_modes.end())
+                    throw runtime_error("bad SPI mode" + std::to_string(spi_mode));
+
+                BITSTREAM_NOTE("SPI Mode " <<  spimode->first);
+            }
+                break;
             case BitstreamCommand::DUMMY:
                 break;
             default: BITSTREAM_FATAL("unsupported command 0x" << hex << setw(2) << setfill('0') << int(cmd),
@@ -375,6 +394,19 @@
     wr.write_bytes(preamble.begin(), preamble.size());
     // Padding
     wr.insert_dummy(4);
+
+    if (options.count("spimode")) {
+        auto spimode = find_if(spi_modes.begin(), spi_modes.end(), [&](const pair<string, uint8_t> &fp){
+            return fp.first == options.at("spimode");
+        });
+        if (spimode == spi_modes.end())
+            throw runtime_error("bad spimode option " + options.at("spimode"));
+
+        wr.write_byte(uint8_t(BitstreamCommand::SPI_MODE));
+        wr.write_byte(uint8_t(spimode->second));
+        wr.insert_zeros(2);
+    }
+
     // Reset CRC
     wr.write_byte(uint8_t(BitstreamCommand::LSC_RESET_CRC));
     wr.insert_zeros(3);
diff --git a/libtrellis/tools/ecppack.cpp b/libtrellis/tools/ecppack.cpp
index 5ae362e..31a3f2b 100644
--- a/libtrellis/tools/ecppack.cpp
+++ b/libtrellis/tools/ecppack.cpp
@@ -35,6 +35,7 @@
     options.add_options()("freq", po::value<std::string>(), "config frequency in MHz");
     options.add_options()("svf", po::value<std::string>(), "output SVF file");
     options.add_options()("svf-rowsize", po::value<int>(), "SVF row size in bits (default 8000)");
+    options.add_options()("spimode", po::value<std::string>(), "SPI Mode to use (fast-read, dual-spi, qspi)");
 
     po::positional_options_description pos;
     options.add_options()("input", po::value<std::string>()->required(), "input textual configuration");
@@ -110,6 +111,9 @@
     if (vm.count("freq"))
         bitopts["freq"] = vm["freq"].as<string>();
 
+    if (vm.count("spimode"))
+        bitopts["spimode"] = vm["spimode"].as<string>();
+
     Bitstream b = Bitstream::serialise_chip(c, bitopts);
     if (vm.count("bit")) {
         ofstream bit_file(vm["bit"].as<string>(), ios::binary);