Merge branch 'bba' into 'master'

bbasm

See merge request SymbioticEDA/nextpnr!18
This commit is contained in:
Clifford Wolf 2018-07-25 11:07:51 +00:00
commit f3dab003e7
7 changed files with 466 additions and 289 deletions

70
bba/README.md Normal file
View File

@ -0,0 +1,70 @@
Binary Blob Assembler (bba)
===========================
This tools read a text file describing binary data, and write that binary data
file. The usual flow is that the input to bbasm is generated by a python
script, and the output is linked or loaded into a C program, using (packed)
structs to interpret the binary data.
All references (pointers) are encoded als 32 bit byte offset relative to the
location of the pointer. This way the resulting binary blob is position
independent.
Valid commands for the input are as follows.
pre <string>
------------
When a C file is generated as output, all the "pre" strings will be included
before the binary blob.
post <string>
-------------
When a C file is generated as output, all the "post" strings will be included
after the binary blob.
push <name>
-----------
All following commands up until the matching "pop" will be writen to stream
<name>. Everything written to the same stream will end up in a continous
region of the output.
pop
---
End of a push..pop block.
label <name> [<comment>]
------------------------
Add a label for the current position.
ref <name> [<comment>]
----------------------
Add a 32-bit reference to the specified label. The reference will be a byte
offset relative to the memory location of the reference itself.
u8 <value> [<comment>]
----------------------
Add a 8-bit value to the binary blob.
u16 <value> [<comment>]
-----------------------
Add a 16-bit value to the binary blob. Note that the input must be structured
in a way that ensures that all u16 are aligned to 2-byte addresses.
u32 <value> [<comment>]
----------------------
Add a 32-bit value to the binary blob. Note that the input must be structured
in a way that ensures that all u32 are aligned to 4-byte addresses.
str <string>
------------
Add a reference to a zero-terminated copy of the specified string.

View File

@ -5,6 +5,7 @@ ENDIF(CMAKE_CROSSCOMPILING)
IF(NOT CMAKE_CROSSCOMPILING) IF(NOT CMAKE_CROSSCOMPILING)
ADD_EXECUTABLE(bbasm bba/main.cc) ADD_EXECUTABLE(bbasm bba/main.cc)
target_link_libraries(bbasm LINK_PUBLIC ${Boost_PROGRAM_OPTIONS_LIBRARY})
ENDIF(NOT CMAKE_CROSSCOMPILING) ENDIF(NOT CMAKE_CROSSCOMPILING)
IF(NOT CMAKE_CROSSCOMPILING) IF(NOT CMAKE_CROSSCOMPILING)

View File

@ -1,15 +1,354 @@
#include <unistd.h> /*
* 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 <assert.h>
int main() #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::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 verbose = false;
bool bigEndian = false;
bool writeC = false;
char buffer[512]; char buffer[512];
int i, j;
while (1) { namespace po = boost::program_options;
i = read(0, buffer, 512); po::positional_options_description pos;
if (i == 0) break; po::options_description options("Allowed options");
assert(i > 0); options.add_options()("v", "verbose output");
j = write(1, buffer, i); options.add_options()("b", "big endian");
assert(i == j); 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("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();
labels.push_back(-1);
}
s.tokenTypes.push_back(cmd == "label" ? TOK_LABEL : TOK_REF);
s.tokenValues.push_back(labelIndex.at(label));
if (verbose)
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 (verbose)
s.tokenComments.push_back(comment);
continue;
}
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) {
labelIndex[label] = labels.size();
labels.push_back(-1);
}
s.tokenTypes.push_back(TOK_REF);
s.tokenValues.push_back(labelIndex.at(label));
if (verbose)
s.tokenComments.push_back(value);
stringStream.tokenTypes.push_back(TOK_LABEL);
stringStream.tokenValues.push_back(labelIndex.at(label));
while (1) {
stringStream.tokenTypes.push_back(TOK_U8);
stringStream.tokenValues.push_back(*value);
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().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; return 0;
} }

View File

@ -23,10 +23,10 @@
#include <condition_variable> #include <condition_variable>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <pthread.h>
#include <stdexcept> #include <stdexcept>
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include <thread>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
@ -79,19 +79,19 @@ class assertion_failure : public std::runtime_error
}; };
NPNR_NORETURN NPNR_NORETURN
inline bool assert_fail_impl(const char *message, const char *expr_str, const char *filename, int line) inline void assert_fail_impl(const char *message, const char *expr_str, const char *filename, int line)
{ {
throw assertion_failure(message, expr_str, filename, line); throw assertion_failure(message, expr_str, filename, line);
} }
NPNR_NORETURN NPNR_NORETURN
inline bool assert_fail_impl_str(std::string message, const char *expr_str, const char *filename, int line) inline void assert_fail_impl_str(std::string message, const char *expr_str, const char *filename, int line)
{ {
throw assertion_failure(message, expr_str, filename, line); throw assertion_failure(message, expr_str, filename, line);
} }
#define NPNR_ASSERT(cond) ((void)((cond) || (assert_fail_impl(#cond, #cond, __FILE__, __LINE__)))) #define NPNR_ASSERT(cond) (!(cond) ? assert_fail_impl(#cond, #cond, __FILE__, __LINE__) : (void)true)
#define NPNR_ASSERT_MSG(cond, msg) ((void)((cond) || (assert_fail_impl(msg, #cond, __FILE__, __LINE__)))) #define NPNR_ASSERT_MSG(cond, msg) (!(cond) ? assert_fail_impl(msg, #cond, __FILE__, __LINE__) : (void)true)
#define NPNR_ASSERT_FALSE(msg) (assert_fail_impl(msg, "false", __FILE__, __LINE__)) #define NPNR_ASSERT_FALSE(msg) (assert_fail_impl(msg, "false", __FILE__, __LINE__))
#define NPNR_ASSERT_FALSE_STR(msg) (assert_fail_impl_str(msg, "false", __FILE__, __LINE__)) #define NPNR_ASSERT_FALSE_STR(msg) (assert_fail_impl_str(msg, "false", __FILE__, __LINE__))
@ -354,7 +354,7 @@ struct BaseCtx
{ {
// Lock to perform mutating actions on the Context. // Lock to perform mutating actions on the Context.
std::mutex mutex; std::mutex mutex;
pthread_t mutex_owner; std::thread::id mutex_owner;
// Lock to be taken by UI when wanting to access context - the yield() // Lock to be taken by UI when wanting to access context - the yield()
// method will lock/unlock it when its' released the main mutex to make // method will lock/unlock it when its' released the main mutex to make
@ -387,12 +387,12 @@ struct BaseCtx
void lock(void) void lock(void)
{ {
mutex.lock(); mutex.lock();
mutex_owner = pthread_self(); mutex_owner = std::this_thread::get_id();
} }
void unlock(void) void unlock(void)
{ {
NPNR_ASSERT(pthread_equal(pthread_self(), mutex_owner) != 0); NPNR_ASSERT(std::this_thread::get_id() != mutex_owner);
mutex.unlock(); mutex.unlock();
} }

View File

@ -198,6 +198,8 @@ bool LineShader::compile(void)
void LineShader::draw(const LineShaderData &line, const QColor &color, float thickness, const QMatrix4x4 &projection) void LineShader::draw(const LineShaderData &line, const QColor &color, float thickness, const QMatrix4x4 &projection)
{ {
auto gl = QOpenGLContext::currentContext()->functions(); auto gl = QOpenGLContext::currentContext()->functions();
if (line.vertices.size() == 0)
return;
vao_.bind(); vao_.bind();
program_->bind(); program_->bind();

View File

@ -6,17 +6,11 @@ import textwrap
import argparse import argparse
parser = argparse.ArgumentParser(description="convert ICE40 chip database") 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("filename", type=str, help="chipdb input filename")
parser.add_argument("-p", "--portspins", type=str, help="path to portpins.inc") parser.add_argument("-p", "--portspins", type=str, help="path to portpins.inc")
parser.add_argument("-g", "--gfxh", type=str, help="path to gfx.h") parser.add_argument("-g", "--gfxh", type=str, help="path to gfx.h")
args = parser.parse_args() args = parser.parse_args()
endianness = "le"
nodebug = True
dev_name = None dev_name = None
dev_width = None dev_width = None
dev_height = None dev_height = None
@ -668,266 +662,56 @@ for ec in sorted(extra_cells.keys()):
add_bel_ec(ec) add_bel_ec(ec)
class BinaryBlobAssembler: 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): def l(self, name, ltype = None, export = False):
assert not self.finalized if ltype is None:
assert name not in self.labels print("label %s" % (name,))
assert len(self.data) not in self.labels_byaddr else:
self.labels[name] = len(self.data) print("label %s %s" % (name, ltype))
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))
def r(self, name, comment): def r(self, name, comment):
assert not self.finalized if comment is None:
assert len(self.data) % 4 == 0 print("ref %s" % (name,))
assert len(self.data) not in self.refs else:
if self.nodebug: print("ref %s %s" % (name, comment))
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)"
def s(self, s, comment): def s(self, s, comment):
assert not self.finalized print("str %s" % s)
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)
def u8(self, v, comment): def u8(self, v, comment):
assert not self.finalized if comment is None:
if self.nodebug: print("u8 %d" % (v,))
comment = None else:
self.data.append(v) print("u8 %d %s" % (v, comment))
if comment is not None:
self.comments[len(self.data)] = comment
def u16(self, v, comment): def u16(self, v, comment):
assert not self.finalized if comment is None:
assert len(self.data) % 2 == 0 print("u16 %d" % (v,))
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)
else: else:
assert 0 print("u16 %d %s" % (v, comment))
if comment is not None:
self.comments[len(self.data)] = comment
def u32(self, v, comment): def u32(self, v, comment):
assert not self.finalized if comment is None:
assert len(self.data) % 4 == 0 print("u32 %d" % (v,))
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)
else: else:
assert 0 print("u32 %d %s" % (v, comment))
if comment is not None:
self.comments[len(self.data)] = comment
def finalize(self): def pre(self, s):
assert not self.finalized print("pre %s" % s)
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"): def post(self, s):
assert self.finalized print("post %s" % s)
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"): def push(self, name):
assert self.finalized print("push %s" % name)
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"): def pop(self):
assert self.finalized print("pop")
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"): bba = BinaryBlobAssembler()
assert self.finalized bba.pre('#include "nextpnr.h"')
assert self.data[len(self.data)-1] == 0 bba.pre('NEXTPNR_NAMESPACE_BEGIN')
print("%s %s[%d] =" % (ctype, self.cname, len(self.data)), file=f) bba.post('NEXTPNR_NAMESPACE_END')
print(" \"", end="", file=f) bba.push("chipdb_blob_%s" % dev_name)
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)
bba.r("chip_info_%s" % dev_name, "chip_info") bba.r("chip_info_%s" % dev_name, "chip_info")
index = 0 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("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.r("package_info_%s" % dev_name, "packages_data")
bba.finalize() bba.pop()
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')

View File

@ -24,11 +24,11 @@ if (MSVC)
set(DEV_PORTS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/portpins.inc) set(DEV_PORTS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/portpins.inc)
set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h) set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h)
add_custom_command(OUTPUT ${DEV_CC_BBA_DB} 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} DEPENDS ${DEV_TXT_DB} ${DB_PY}
) )
add_custom_command(OUTPUT ${DEV_CC_DB} 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} DEPENDS bbasm ${DEV_CC_BBA_DB}
) )
target_sources(ice40_chipdb PRIVATE ${DEV_CC_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_PORTS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/portpins.inc)
set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h) set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h)
add_custom_command(OUTPUT ${DEV_CC_BBA_DB} 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} COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB}
DEPENDS ${DEV_TXT_DB} ${DB_PY} DEPENDS ${DEV_TXT_DB} ${DB_PY}
) )
add_custom_command(OUTPUT ${DEV_CC_DB} 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} COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB}
DEPENDS bbasm ${DEV_CC_BBA_DB} DEPENDS bbasm ${DEV_CC_BBA_DB}
) )