diff options
| -rw-r--r-- | bba/main.cc | 206 | ||||
| -rw-r--r-- | ice40/chipdb.py | 311 | ||||
| -rw-r--r-- | ice40/family.cmake | 8 | 
3 files changed, 236 insertions, 289 deletions
| diff --git a/bba/main.cc b/bba/main.cc index 3ef4c1ca..53c70b83 100644 --- a/bba/main.cc +++ b/bba/main.cc @@ -3,8 +3,10 @@  #include <string>  #include <stdio.h>  #include <stdlib.h> +#include <stdint.h>  #include <string.h>  #include <assert.h> +#include <unistd.h>  enum TokenType : int8_t  { @@ -35,18 +37,48 @@ 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 main(int argc, char **argv)  { -    bool verbose = true; -    // bool bigEndian = false; +    bool verbose = false; +    bool bigEndian = false; +    bool writeC = false;      char buffer[512]; -    while (fgets(buffer, 512, stdin) != nullptr) +    int opt; +    while ((opt = getopt(argc, argv, "vbc")) != -1) +    { +        switch (opt) +        { +        case 'v': +            verbose = true; +            break; +        case 'b': +            bigEndian = true; +            break; +        case 'c': +            writeC = true; +            break; +        default: +            assert(0); +        } +    } + +    assert(optind+2 == argc); + +    FILE *fileIn = fopen(argv[optind], "rt"); +    assert(fileIn != nullptr); + +    FILE *fileOut = fopen(argv[optind+1], writeC ? "wt" : "wb"); +    assert(fileOut != nullptr); + +    while (fgets(buffer, 512, fileIn) != nullptr)      {          std::string cmd = strtok(buffer, " \t\r\n"); @@ -63,7 +95,7 @@ int main()          }          if (cmd == "push") { -            const char *p = strtok(buffer, " \t\r\n"); +            const char *p = strtok(nullptr, " \t\r\n");              if (streamIndex.count(p) == 0) {                  streamIndex[p] = streams.size();                  streams.resize(streams.size() + 1); @@ -79,8 +111,8 @@ int main()          }          if (cmd == "label" || cmd == "ref") { -            const char *label = strtok(buffer, " \t\r\n"); -            const char *comment = skipWhitespace(strtok(buffer, "\r\n")); +            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(); @@ -94,8 +126,8 @@ int main()          }          if (cmd == "u8" || cmd == "u16" || cmd == "u32") { -            const char *value = strtok(buffer, " \t\r\n"); -            const char *comment = skipWhitespace(strtok(buffer, "\r\n")); +            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)); @@ -104,8 +136,8 @@ int main()              continue;          } -        if (cmd == "s") { -            const char *value = skipWhitespace(strtok(buffer, "\r\n")); +        if (cmd == "str") { +            const char *value = skipWhitespace(strtok(nullptr, "\r\n"));              std::string label = std::string("str:") + value;              Stream &s = streams.at(streamStack.back());              if (labelIndex.count(label) == 0) { @@ -128,7 +160,13 @@ int main()              continue;          } -        abort(); +        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()); @@ -137,5 +175,149 @@ int main()      streams.back().tokenTypes.swap(stringStream.tokenTypes);      streams.back().tokenValues.swap(stringStream.tokenValues); +    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) { +        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; +            } +        } +    } + +    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 (auto d : data) { +            if (cursor > 70) { +                fputc('\"', fileOut); +                fputc('\n', fileOut); +                cursor = 0; +            } +            if (cursor == 0) { +                fputc('\"', fileOut); +                cursor = 1; +            } +            if (d < 32 || d >= 128) { +                fprintf(fileOut, "\\%03o", int(d)); +                cursor += 4; +            } 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;  } diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 108197c1..b5fee359 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -6,17 +6,11 @@ import textwrap  import argparse  parser = argparse.ArgumentParser(description="convert ICE40 chip database") -group = parser.add_mutually_exclusive_group() -group.add_argument("-b", "--binary", action="store_true") -group.add_argument("-c", "--c_file", action="store_true")  parser.add_argument("filename", type=str, help="chipdb input filename")  parser.add_argument("-p", "--portspins", type=str, help="path to portpins.inc")  parser.add_argument("-g", "--gfxh", type=str, help="path to gfx.h")  args = parser.parse_args() -endianness = "le" -nodebug = True -  dev_name = None  dev_width = None  dev_height = None @@ -668,266 +662,56 @@ for ec in sorted(extra_cells.keys()):          add_bel_ec(ec)  class BinaryBlobAssembler: -    def __init__(self, cname, endianness, nodebug = False): -        assert endianness in ["le", "be"] -        self.cname = cname -        self.endianness = endianness -        self.finalized = False -        self.data = bytearray() -        self.comments = dict() -        self.labels = dict() -        self.exports = set() -        self.labels_byaddr = dict() -        self.ltypes_byaddr = dict() -        self.strings = dict() -        self.refs = dict() -        self.nodebug = nodebug -      def l(self, name, ltype = None, export = False): -        assert not self.finalized -        assert name not in self.labels -        assert len(self.data) not in self.labels_byaddr -        self.labels[name] = len(self.data) -        if ltype is not None: -            self.ltypes_byaddr[len(self.data)] = ltype -        self.labels_byaddr[len(self.data)] = name -        if export: -            assert ltype is not None -            self.exports.add(len(self.data)) +        if ltype is None: +            print("label %s" % (name,)) +        else: +            print("label %s %s" % (name, ltype))      def r(self, name, comment): -        assert not self.finalized -        assert len(self.data) % 4 == 0 -        assert len(self.data) not in self.refs -        if self.nodebug: -            comment = None -        if name is not None: -            self.refs[len(self.data)] = (name, comment) -        self.data.append(0) -        self.data.append(0) -        self.data.append(0) -        self.data.append(0) -        if (name is None) and (comment is not None): -            self.comments[len(self.data)] = comment + " (null reference)" +        if comment is None: +            print("ref %s" % (name,)) +        else: +            print("ref %s %s" % (name, comment))      def s(self, s, comment): -        assert not self.finalized -        if self.nodebug: -            comment = None -        if s not in self.strings: -            index = len(self.strings) -            self.strings[s] = index -        else: -            index = self.strings[s] -        if comment is not None: -            self.r("str%d" % index, '%s: "%s"' % (comment, s)) -        else: -            self.r("str%d" % index, None) +        print("str %s" % s)      def u8(self, v, comment): -        assert not self.finalized -        if self.nodebug: -            comment = None -        self.data.append(v) -        if comment is not None: -            self.comments[len(self.data)] = comment +        if comment is None: +            print("u8 %d" % (v,)) +        else: +            print("u8 %d %s" % (v, comment))      def u16(self, v, comment): -        assert not self.finalized -        assert len(self.data) % 2 == 0 -        if self.nodebug: -            comment = None -        if self.endianness == "le": -            self.data.append(v & 255) -            self.data.append((v >> 8) & 255) -        elif self.endianness == "be": -            self.data.append((v >> 8) & 255) -            self.data.append(v & 255) +        if comment is None: +            print("u16 %d" % (v,))          else: -            assert 0 -        if comment is not None: -            self.comments[len(self.data)] = comment +            print("u16 %d %s" % (v, comment))      def u32(self, v, comment): -        assert not self.finalized -        assert len(self.data) % 4 == 0 -        if self.nodebug: -            comment = None -        if self.endianness == "le": -            self.data.append(v & 255) -            self.data.append((v >> 8) & 255) -            self.data.append((v >> 16) & 255) -            self.data.append((v >> 24) & 255) -        elif self.endianness == "be": -            self.data.append((v >> 24) & 255) -            self.data.append((v >> 16) & 255) -            self.data.append((v >> 8) & 255) -            self.data.append(v & 255) +        if comment is None: +            print("u32 %d" % (v,))          else: -            assert 0 -        if comment is not None: -            self.comments[len(self.data)] = comment - -    def finalize(self): -        assert not self.finalized -        for s, index in sorted(self.strings.items()): -            self.l("str%d" % index, "char") -            for c in s: -                self.data.append(ord(c)) -            self.data.append(0) -        self.finalized = True -        cursor = 0 -        while cursor < len(self.data): -            if cursor in self.refs: -                v = self.labels[self.refs[cursor][0]] - cursor -                if self.endianness == "le": -                    self.data[cursor+0] = (v & 255) -                    self.data[cursor+1] = ((v >> 8) & 255) -                    self.data[cursor+2] = ((v >> 16) & 255) -                    self.data[cursor+3] = ((v >> 24) & 255) -                elif self.endianness == "be": -                    self.data[cursor+0] = ((v >> 24) & 255) -                    self.data[cursor+1] = ((v >> 16) & 255) -                    self.data[cursor+2] = ((v >> 8) & 255) -                    self.data[cursor+3] = (v & 255) -                else: -                    assert 0 -                cursor += 4 -            else: -                cursor += 1 - -    def write_verbose_c(self, f, ctype = "const unsigned char"): -        assert self.finalized -        print("%s %s[%d] = {" % (ctype, self.cname, len(self.data)), file=f) -        cursor = 0 -        bytecnt = 0 -        while cursor < len(self.data): -            if cursor in self.comments: -                if bytecnt == 0: -                    print(" ", end="", file=f) -                print(" // %s" % self.comments[cursor], file=f) -                bytecnt = 0 -            if cursor in self.labels_byaddr: -                if bytecnt != 0: -                    print(file=f) -                if cursor in self.exports: -                    print("#define %s ((%s*)(%s+%d))" % (self.labels_byaddr[cursor], self.ltypes_byaddr[cursor], self.cname, cursor), file=f) -                else: -                    print("  // [%d] %s" % (cursor, self.labels_byaddr[cursor]), file=f) -                bytecnt = 0 -            if cursor in self.refs: -                if bytecnt != 0: -                    print(file=f) -                print(" ", end="", file=f) -                print(" %-4s" % ("%d," % self.data[cursor+0]), end="", file=f) -                print(" %-4s" % ("%d," % self.data[cursor+1]), end="", file=f) -                print(" %-4s" % ("%d," % self.data[cursor+2]), end="", file=f) -                print(" %-4s" % ("%d," % self.data[cursor+3]), end="", file=f) -                print(" // [%d] %s (reference to %s)" % (cursor, self.refs[cursor][1], self.refs[cursor][0]), file=f) -                bytecnt = 0 -                cursor += 4 -            else: -                if bytecnt == 0: -                    print(" ", end="", file=f) -                print(" %-4s" % ("%d," % self.data[cursor]), end=("" if bytecnt < 15 else "\n"), file=f) -                bytecnt = (bytecnt + 1) & 15 -                cursor += 1 -        if bytecnt != 0: -            print(file=f) -        print("};", file=f) - -    def write_compact_c(self, f, ctype = "const unsigned char"): -        assert self.finalized -        print("%s %s[%d] = {" % (ctype, self.cname, len(self.data)), file=f) -        column = 0 -        for v in self.data: -            if column == 0: -                print("  ", end="", file=f) -                column += 2 -            s = "%d," % v -            print(s, end="", file=f) -            column += len(s) -            if column > 75: -                print(file=f) -                column = 0 -        if column != 0: -            print(file=f) -        for cursor in self.exports: -            print("#define %s ((%s*)(%s+%d))" % (self.labels_byaddr[cursor], self.ltypes_byaddr[cursor], self.cname, cursor), file=f) -        print("};", file=f) - -    def write_uint64_c(self, f, ctype = "const uint64_t"): -        assert self.finalized -        print("%s %s[%d] = {" % (ctype, self.cname, (len(self.data)+7) // 8), file=f) -        column = 0 -        for i in range((len(self.data)+7) // 8): -            v0 = self.data[8*i+0] if 8*i+0 < len(self.data) else 0 -            v1 = self.data[8*i+1] if 8*i+1 < len(self.data) else 0 -            v2 = self.data[8*i+2] if 8*i+2 < len(self.data) else 0 -            v3 = self.data[8*i+3] if 8*i+3 < len(self.data) else 0 -            v4 = self.data[8*i+4] if 8*i+4 < len(self.data) else 0 -            v5 = self.data[8*i+5] if 8*i+5 < len(self.data) else 0 -            v6 = self.data[8*i+6] if 8*i+6 < len(self.data) else 0 -            v7 = self.data[8*i+7] if 8*i+7 < len(self.data) else 0 -            if self.endianness == "le": -                v  = v0 <<  0 -                v |= v1 <<  8 -                v |= v2 << 16 -                v |= v3 << 24 -                v |= v4 << 32 -                v |= v5 << 40 -                v |= v6 << 48 -                v |= v7 << 56 -            elif self.endianness == "be": -                v  = v7 <<  0 -                v |= v6 <<  8 -                v |= v5 << 16 -                v |= v4 << 24 -                v |= v3 << 32 -                v |= v2 << 40 -                v |= v1 << 48 -                v |= v0 << 56 -            else: -                assert 0 -            if column == 3: -                print(" 0x%016x," % v, file=f) -                column = 0 -            else: -                if column == 0: -                    print(" ", end="", file=f) -                print(" 0x%016x," % v, end="", file=f) -                column += 1 -        if column != 0: -            print("", file=f) -        print("};", file=f) - -    def write_string_c(self, f, ctype = "const char"): -        assert self.finalized -        assert self.data[len(self.data)-1] == 0 -        print("%s %s[%d] =" % (ctype, self.cname, len(self.data)), file=f) -        print("  \"", end="", file=f) -        column = 0 -        for i in range(len(self.data)-1): -            if (self.data[i] < 32) or (self.data[i] > 126): -                print("\\%03o" % self.data[i], end="", file=f) -                column += 4 -            elif self.data[i] == ord('"') or self.data[i] == ord('\\'): -                print("\\" + chr(self.data[i]), end="", file=f) -                column += 2 -            else: -                print(chr(self.data[i]), end="", file=f) -                column += 1 -            if column > 70 and (i != len(self.data)-2): -                print("\"\n  \"", end="", file=f) -                column = 0 -        print("\";", file=f) - -    def write_binary(self, f): -        assert self.finalized -        assert self.data[len(self.data)-1] == 0 -        f.buffer.write(self.data) - -bba = BinaryBlobAssembler("chipdb_blob_%s" % dev_name, endianness) +            print("u32 %d %s" % (v, comment)) + +    def pre(self, s): +        print("pre %s" % s) + +    def post(self, s): +        print("post %s" % s) + +    def push(self, name): +        print("push %s" % name) + +    def pop(self): +        print("pop") + +bba = BinaryBlobAssembler() +bba.pre('#include "nextpnr.h"') +bba.pre('NEXTPNR_NAMESPACE_BEGIN') +bba.post('NEXTPNR_NAMESPACE_END') +bba.push("chipdb_blob_%s" % dev_name)  bba.r("chip_info_%s" % dev_name, "chip_info")  index = 0 @@ -1243,23 +1027,4 @@ bba.r("bits_info_%s" % dev_name, "bits_info")  bba.r("bel_config_%s" % dev_name if len(extra_cell_config) > 0 else None, "bel_config")  bba.r("package_info_%s" % dev_name, "packages_data") -bba.finalize() - -if args.c_file: -    print('#include "nextpnr.h"') -    print('NEXTPNR_NAMESPACE_BEGIN') - - -if args.binary: -    bba.write_binary(sys.stdout) - -if args.c_file: -    bba.write_string_c(sys.stdout) - -# bba.write_uint64_c(sys.stdout) -# bba.write_compact_c(sys.stdout, "uint8_t") -# bba.write_verbose_c(sys.stdout, "uint8_t") - -if args.c_file: -    print('NEXTPNR_NAMESPACE_END') - +bba.pop() diff --git a/ice40/family.cmake b/ice40/family.cmake index 95cdf331..374c62eb 100644 --- a/ice40/family.cmake +++ b/ice40/family.cmake @@ -24,11 +24,11 @@ if (MSVC)          set(DEV_PORTS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/portpins.inc)          set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h)          add_custom_command(OUTPUT ${DEV_CC_BBA_DB} -                COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -b -p ${DEV_PORTS_INC} -g ${DEV_GFXH} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB} +                COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_PORTS_INC} -g ${DEV_GFXH} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB}                  DEPENDS ${DEV_TXT_DB} ${DB_PY}                  )          add_custom_command(OUTPUT ${DEV_CC_DB} -                COMMAND bbasm < ${DEV_CC_BBA_DB} > ${DEV_CC_DB} +                COMMAND bbasm ${DEV_CC_BBA_DB} ${DEV_CC_DB}                  DEPENDS bbasm ${DEV_CC_BBA_DB}          )          target_sources(ice40_chipdb PRIVATE ${DEV_CC_DB}) @@ -46,12 +46,12 @@ else()          set(DEV_PORTS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/portpins.inc)          set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h)          add_custom_command(OUTPUT ${DEV_CC_BBA_DB} -                COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -c -p ${DEV_PORTS_INC} -g ${DEV_GFXH} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB}.new +                COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_PORTS_INC} -g ${DEV_GFXH} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB}.new                  COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB}                  DEPENDS ${DEV_TXT_DB} ${DB_PY}          )          add_custom_command(OUTPUT ${DEV_CC_DB} -                COMMAND bbasm < ${DEV_CC_BBA_DB} > ${DEV_CC_DB}.new +                COMMAND bbasm -c ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new                  COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB}                  DEPENDS bbasm ${DEV_CC_BBA_DB}          ) | 
