Merge branch 'bba' into 'master'
bbasm See merge request SymbioticEDA/nextpnr!18
This commit is contained in:
commit
f3dab003e7
70
bba/README.md
Normal file
70
bba/README.md
Normal 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.
|
@ -5,6 +5,7 @@ ENDIF(CMAKE_CROSSCOMPILING)
|
||||
|
||||
IF(NOT CMAKE_CROSSCOMPILING)
|
||||
ADD_EXECUTABLE(bbasm bba/main.cc)
|
||||
target_link_libraries(bbasm LINK_PUBLIC ${Boost_PROGRAM_OPTIONS_LIBRARY})
|
||||
ENDIF(NOT CMAKE_CROSSCOMPILING)
|
||||
|
||||
IF(NOT CMAKE_CROSSCOMPILING)
|
||||
|
357
bba/main.cc
357
bba/main.cc
@ -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>
|
||||
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];
|
||||
int i, j;
|
||||
while (1) {
|
||||
i = read(0, buffer, 512);
|
||||
if (i == 0) break;
|
||||
assert(i > 0);
|
||||
j = write(1, buffer, i);
|
||||
assert(i == j);
|
||||
|
||||
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()("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("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;
|
||||
}
|
||||
|
@ -23,10 +23,10 @@
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <pthread.h>
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
@ -79,19 +79,19 @@ class assertion_failure : public std::runtime_error
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#define NPNR_ASSERT(cond) ((void)((cond) || (assert_fail_impl(#cond, #cond, __FILE__, __LINE__))))
|
||||
#define NPNR_ASSERT_MSG(cond, msg) ((void)((cond) || (assert_fail_impl(msg, #cond, __FILE__, __LINE__))))
|
||||
#define NPNR_ASSERT(cond) (!(cond) ? assert_fail_impl(#cond, #cond, __FILE__, __LINE__) : (void)true)
|
||||
#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_STR(msg) (assert_fail_impl_str(msg, "false", __FILE__, __LINE__))
|
||||
|
||||
@ -354,7 +354,7 @@ struct BaseCtx
|
||||
{
|
||||
// Lock to perform mutating actions on the Context.
|
||||
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()
|
||||
// method will lock/unlock it when its' released the main mutex to make
|
||||
@ -387,12 +387,12 @@ struct BaseCtx
|
||||
void lock(void)
|
||||
{
|
||||
mutex.lock();
|
||||
mutex_owner = pthread_self();
|
||||
mutex_owner = std::this_thread::get_id();
|
||||
}
|
||||
|
||||
void unlock(void)
|
||||
{
|
||||
NPNR_ASSERT(pthread_equal(pthread_self(), mutex_owner) != 0);
|
||||
NPNR_ASSERT(std::this_thread::get_id() != mutex_owner);
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
|
@ -198,6 +198,8 @@ bool LineShader::compile(void)
|
||||
void LineShader::draw(const LineShaderData &line, const QColor &color, float thickness, const QMatrix4x4 &projection)
|
||||
{
|
||||
auto gl = QOpenGLContext::currentContext()->functions();
|
||||
if (line.vertices.size() == 0)
|
||||
return;
|
||||
vao_.bind();
|
||||
program_->bind();
|
||||
|
||||
|
301
ice40/chipdb.py
301
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
|
||||
print("u32 %d %s" % (v, 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 pre(self, s):
|
||||
print("pre %s" % s)
|
||||
|
||||
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 post(self, s):
|
||||
print("post %s" % s)
|
||||
|
||||
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 push(self, name):
|
||||
print("push %s" % name)
|
||||
|
||||
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 pop(self):
|
||||
print("pop")
|
||||
|
||||
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)
|
||||
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()
|
||||
|
@ -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}
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user