aboutsummaryrefslogtreecommitdiffstats
path: root/icemulti
diff options
context:
space:
mode:
authorMarcus Comstedt <marcus@mc.pp.se>2015-08-07 19:40:34 +0200
committerMarcus Comstedt <marcus@mc.pp.se>2015-08-07 19:40:34 +0200
commitd1893e1116fee67db54962dba7417508b3128b9e (patch)
tree51276d3006349cdccbce93e39a82835a5dbc4140 /icemulti
parentc8131e95a40064012f2f7ba4886a9fdfc79abe56 (diff)
downloadicestorm-d1893e1116fee67db54962dba7417508b3128b9e.tar.gz
icestorm-d1893e1116fee67db54962dba7417508b3128b9e.tar.bz2
icestorm-d1893e1116fee67db54962dba7417508b3128b9e.zip
Created a tool for building multiboot images
Diffstat (limited to 'icemulti')
-rw-r--r--icemulti/.gitignore3
-rw-r--r--icemulti/Makefile24
-rw-r--r--icemulti/icemulti.cc263
3 files changed, 290 insertions, 0 deletions
diff --git a/icemulti/.gitignore b/icemulti/.gitignore
new file mode 100644
index 0000000..51ac8f9
--- /dev/null
+++ b/icemulti/.gitignore
@@ -0,0 +1,3 @@
+icemulti
+icemulti.o
+icemulti.d
diff --git a/icemulti/Makefile b/icemulti/Makefile
new file mode 100644
index 0000000..0b4e0aa
--- /dev/null
+++ b/icemulti/Makefile
@@ -0,0 +1,24 @@
+# CXX = clang
+LDLIBS = -lm -lstdc++
+CXXFLAGS = -MD -O0 -ggdb -Wall -std=c++11
+CC = $(CXX)
+DESTDIR = /usr/local
+
+all: icemulti
+
+icemulti: icemulti.o
+
+install: all
+ cp icemulti $(DESTDIR)/bin/icemulti
+
+uninstall:
+ rm -f $(DESTDIR)/bin/icemulti
+
+clean:
+ rm -f icemulti
+ rm -f *.o *.d
+
+-include *.d
+
+.PHONY: all install uninstall clean
+
diff --git a/icemulti/icemulti.cc b/icemulti/icemulti.cc
new file mode 100644
index 0000000..5911550
--- /dev/null
+++ b/icemulti/icemulti.cc
@@ -0,0 +1,263 @@
+//
+// Copyright (C) 2015 Marcus Comstedt <marcus@mc.pp.se>
+//
+// 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 <fstream>
+#include <iostream>
+#include <cstdint>
+#include <memory>
+
+#include <stdio.h>
+
+#define log(...) fprintf(stderr, __VA_ARGS__);
+#define info(...) do { if (log_level > 0) fprintf(stderr, __VA_ARGS__); } while (0)
+#define error(...) do { fprintf(stderr, "Error: " __VA_ARGS__); exit(1); } while (0)
+
+int log_level = 0;
+
+static const int NUM_IMAGES = 4;
+static const int NUM_HEADERS = NUM_IMAGES + 1;
+static const int HEADER_SIZE = 32;
+static const int HEADERS_SIZE = NUM_HEADERS * HEADER_SIZE;
+
+static void write_byte(std::ostream &ofs, uint32_t &file_offset, uint8_t byte)
+{
+ ofs << byte;
+ file_offset++;
+}
+
+static void write_bytes(std::ostream &ofs, uint32_t &file_offset,
+ const uint8_t *buf, size_t n)
+{
+ if (n > 0) {
+ ofs.write(reinterpret_cast<const char*>(buf), n);
+ file_offset += n;
+ }
+}
+
+static void write_file(std::ostream &ofs, uint32_t &file_offset,
+ std::istream &ifs)
+{
+ const size_t bufsize = 8192;
+ uint8_t *buffer = new uint8_t[bufsize];
+
+ while(!ifs.eof()) {
+ ifs.read(reinterpret_cast<char *>(buffer), bufsize);
+ if (ifs.bad())
+ error("Read error on input image");
+ write_bytes(ofs, file_offset, buffer, ifs.gcount());
+ }
+
+ delete[] buffer;
+}
+
+static void pad_to(std::ostream &ofs, uint32_t &file_offset, uint32_t target)
+{
+ if (target < file_offset)
+ error("Trying to pad backwards!\n");
+ while(file_offset < target)
+ write_byte(ofs, file_offset, 0xff);
+}
+
+class Image {
+ std::ifstream ifs;
+ uint32_t offs;
+
+public:
+ Image(const char *filename) : ifs(filename, std::ifstream::binary) {}
+
+ size_t size();
+ void write(std::ostream &ofs, uint32_t &file_offset);
+ void place(uint32_t o) { offs = o; }
+ uint32_t offset() const { return offs; }
+};
+
+size_t Image::size()
+{
+ ifs.seekg (0, ifs.end);
+ size_t length = ifs.tellg();
+ ifs.seekg (0, ifs.beg);
+ return length;
+}
+
+void Image::write(std::ostream &ofs, uint32_t &file_offset)
+{
+ write_file(ofs, file_offset, ifs);
+}
+
+class Header {
+ uint32_t image_offs;
+ bool coldboot_flag;
+ bool empty;
+public:
+ Header() : empty(true) {}
+ Header(const Image &i) :
+ image_offs(i.offset()), coldboot_flag(false), empty(false) {}
+ void set_coldboot_flag() { coldboot_flag = true; }
+ void write(std::ostream &ofs, uint32_t &file_offset);
+};
+
+void Header::write(std::ostream &ofs, uint32_t &file_offset)
+{
+ if (empty)
+ return;
+
+ // Preamble
+ write_byte(ofs, file_offset, 0x7e);
+ write_byte(ofs, file_offset, 0xaa);
+ write_byte(ofs, file_offset, 0x99);
+ write_byte(ofs, file_offset, 0x7e);
+
+ // Boot mode
+ write_byte(ofs, file_offset, 0x92);
+ write_byte(ofs, file_offset, 0x00);
+ write_byte(ofs, file_offset, (coldboot_flag? 0x10: 0x00));
+
+ // Boot address
+ write_byte(ofs, file_offset, 0x44);
+ write_byte(ofs, file_offset, 0x03);
+ write_byte(ofs, file_offset, (image_offs >> 16) & 0xff);
+ write_byte(ofs, file_offset, (image_offs >> 8) & 0xff);
+ write_byte(ofs, file_offset, image_offs & 0xff);
+
+ // Bank offset
+ write_byte(ofs, file_offset, 0x82);
+ write_byte(ofs, file_offset, 0x00);
+ write_byte(ofs, file_offset, 0x00);
+
+ // Reboot
+ write_byte(ofs, file_offset, 0x01);
+ write_byte(ofs, file_offset, 0x08);
+
+ // Zero out any unused bytes
+ while (file_offset & (HEADER_SIZE - 1))
+ write_byte(ofs, file_offset, 0x00);
+}
+
+void usage()
+{
+ log("\n");
+ log("Usage: icemulti [options] input-files\n");
+ log("\n");
+ log(" -c\n");
+ log(" coldboot mode, power on reset image is selected by CBSEL0/CBSEL1\n");
+ log("\n");
+ log(" -p0, -p1, -p2, -p3\n");
+ log(" select power on reset image when not using coldboot mode\n");
+ log("\n");
+ log(" -o filename\n");
+ log(" write output image to file instead of stdout\n");
+ log("\n");
+ log(" -v\n");
+ log(" verbose (repeat to increase verbosity)\n");
+ log("\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ bool coldboot = false;
+ int por_image = 0;
+ int image_count = 0;
+ Header headers[NUM_HEADERS];
+ std::unique_ptr<Image> images[NUM_IMAGES];
+ const char *outfile_name = NULL;
+
+ for (int i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-' && argv[i][1]) {
+ for (int j = 1; argv[i][j]; j++)
+ if (argv[i][j] == 'c') {
+ coldboot = true;
+ } else if (argv[i][j] == 'p' && argv[i][j+1]) {
+ por_image = argv[i][++j] - '0';
+ } else if (argv[i][j] == 'o') {
+ if (argv[i][j+1])
+ outfile_name = &argv[i][j+1];
+ else if(i+1 < argc)
+ outfile_name = argv[++i];
+ else
+ usage();
+ break;
+ } else if (argv[i][j] == 'v') {
+ log_level++;
+ } else
+ usage();
+ continue;
+ }
+
+ if (image_count >= NUM_IMAGES)
+ error("Too many images supplied\n");
+ images[image_count++].reset(new Image(argv[i]));
+ }
+
+ if (!image_count)
+ usage();
+
+ if (coldboot && por_image != 0)
+ error("Can't select power on reset boot image in cold boot mode\n");
+
+ if (por_image >= image_count)
+ error("Specified non-existing image for power on reset\n");
+
+ // Place images
+ uint32_t offs = 0x100;
+ for (int i=0; i<image_count; i++) {
+ images[i]->place(offs);
+ offs += images[i]->size();
+
+ // Align to 4K
+ if (offs & 0xfff) {
+ offs |= 0xfff;
+ offs++;
+ }
+ }
+
+ // Populate headers
+ for (int i=0; i<image_count; i++)
+ headers[i + 1] = Header(*images[i]);
+ headers[0] = headers[por_image + 1];
+ for (int i=image_count; i < NUM_IMAGES; i++)
+ headers[i + 1] = headers[0];
+ if (coldboot)
+ headers[0].set_coldboot_flag();
+
+ std::ofstream ofs;
+ std::ostream *osp;
+
+ if (outfile_name != NULL) {
+ ofs.open(outfile_name, std::ofstream::binary);
+ if (!ofs.is_open())
+ error("Failed to open output file.\n");
+ osp = &ofs;
+ } else {
+ osp = &std::cout;
+ }
+
+ uint32_t file_offset = 0;
+ for (int i=0; i<NUM_HEADERS; i++)
+ {
+ pad_to(*osp, file_offset, i * HEADER_SIZE);
+ headers[i].write(*osp, file_offset);
+ }
+ for (int i=0; i<image_count; i++)
+ {
+ pad_to(*osp, file_offset, images[i]->offset());
+ images[i]->write(*osp, file_offset);
+ }
+
+ info("Done.\n");
+ return 0;
+}