Add prjuray tools
Signed-off-by: Tomasz Michalak <tmichalak@antmicro.com>
diff --git a/tools/.gitignore b/tools/.gitignore
new file mode 100644
index 0000000..ec121a9
--- /dev/null
+++ b/tools/.gitignore
@@ -0,0 +1,4 @@
+CMakeCache.txt
+CMakeFiles
+Makefile
+cmake_install.cmake
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 2ebadf1..612bef1 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -33,3 +33,19 @@
gflags
libprjxray
)
+
+add_library(common common.cpp)
+
+add_executable(dump_bitstream dump_bitstream.cpp)
+target_compile_options(dump_bitstream PRIVATE -Wno-error)
+target_link_libraries(dump_bitstream common)
+
+add_executable(correlate correlate.cpp)
+add_executable(stripdb stripdb.cpp)
+set_target_properties(correlate stripdb PROPERTIES CXX_STANDARD 17)
+
+add_executable(explain explain.cpp)
+target_link_libraries(explain common)
+
+add_executable(assemble assemble.cpp)
+target_link_libraries(assemble common)
diff --git a/tools/assemble.cpp b/tools/assemble.cpp
new file mode 100644
index 0000000..f86e494
--- /dev/null
+++ b/tools/assemble.cpp
@@ -0,0 +1,347 @@
+// Copyright 2020 Project U-Ray Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <unordered_set>
+#include <unordered_map>
+#include <map>
+#include <set>
+#include <cassert>
+#include <stdexcept>
+#include <stdarg.h>
+#include "common.h"
+
+enum BitstreamRegister : uint16_t {
+ #define X(a, b) a = b,
+ #include "registers.inc"
+ #undef X
+};
+
+
+ChipData chip;
+
+std::unordered_set<uint32_t> roi_frames;
+std::map<uint32_t, std::vector<bool>> frames;
+std::map<uint32_t, uint32_t> next_frame;
+std::string db_root;
+
+
+void set_tile_bit(const TileInstance &tile, int bit) {
+ int pos = 0;
+ for (auto &bm : tile.bits) {
+ if (bit >= pos && bit < (pos + bm.size)) {
+ frames.at(bm.frame_offset).at(bm.bit_offset + (bit - pos)) = true;
+ return;
+ }
+ pos += bm.size;
+ }
+ throw std::runtime_error("bad bit " + tile.name + "." + std::to_string(bit));
+}
+
+
+void set_feature(const std::string &tile, const std::string &feature) {
+ auto &db = chip.load_tile_database(tile);
+ if (!db.features.count(feature)) {
+ throw std::runtime_error("unknown feature " + feature + " in tile " + tile);
+ }
+ const auto &fbits = db.features.at(feature);
+ auto &t = chip.tiles[tile];
+ for (auto bit : fbits)
+ set_tile_bit(t, bit);
+}
+
+void read_quasi_fasm(const std::string &filename) {
+ LineReader rd(filename);
+ std::vector<std::string> split;
+ for (auto &line : rd) {
+ split_str(line, split, ".", true, 1);
+ if (split.size() < 2)
+ continue;
+ set_feature(split.at(0), split.at(1));
+ }
+}
+
+// Add ECCs to frames
+void add_frame_ecc() {
+
+ auto get_ecc_value = [](int word, int bit) {
+ int nib = bit / 4;
+ int nibbit = bit % 4;
+ // ECC offset is expanded to 1 bit per nibble,
+ // and then shifted based on the bit index in nibble
+ // e.g. word 3, bit 9
+ // offset: 0b10100110010 - concatenate (3 + (255 - 92)) [frame offset] and 9/4 [nibble offset]
+ // becomes: 0x10100110010
+ // shifted by bit in nibble (9%4): 0x20200220020
+ uint32_t offset = (word + (255 - 92)) << 3 | nib;
+ uint64_t exp_offset = 0;
+ // Odd parity
+ offset ^= (1 << 11);
+ for (int i = 0; i < 11; i++)
+ if (offset & (1 << i)) offset ^= (1 << 11);
+ // Expansion
+ for (int i = 0; i < 12; i++)
+ if (offset & (1 << i)) exp_offset |= (1ULL << (4 * i));
+ return exp_offset << nibbit;
+ };
+
+ for (auto &fr : frames) {
+ auto &bits = fr.second;
+ uint64_t ecc = 0;
+ for (int word = 0; word < 93; word++) {
+ for (int i = 0; i < 32; i++) {
+ if (!bits.at(word * 32 + i))
+ continue;
+ if ((word == 45) || ((word == 46 && (i < 16)))) {
+ bits.at(word * 32 + i) = false;
+ continue;
+ }
+ ecc ^= get_ecc_value(word, i);
+ }
+ }
+ for (int i = 0; i < 48; i++)
+ if (ecc & (1ULL << i))
+ bits.at(45*32 + i) = true;
+ }
+}
+
+
+struct ByteStreamWriter {
+ std::vector<uint8_t> data;
+
+ uint32_t curr_crc = 0;
+ uint32_t curr_addr = 0;
+
+ void write_byte(uint8_t byte) {
+ data.push_back(byte);
+ }
+ void write_bytes(const std::vector<uint8_t> &bytes) {
+ data.insert(data.end(), bytes.begin(), bytes.end());
+ }
+ void write_string(const std::string &str) {
+ int len = int(str.length()) + 1;
+ data.push_back((len >> 8) & 0xFF);
+ data.push_back(len & 0xFF);
+ for (char c : str) data.push_back(uint8_t(c));
+ data.push_back(0x00);
+ }
+ void write_u32(uint32_t word, bool update_crc = false) {
+ data.push_back((word >> 24) & 0xFF);
+ data.push_back((word >> 16) & 0xFF);
+ data.push_back((word >> 8) & 0xFF);
+ data.push_back((word >> 0) & 0xFF);
+ if (update_crc)
+ curr_crc = icap_crc(curr_addr, word, curr_crc);
+ }
+ void write_short_packet(BitstreamOp op, BitstreamRegister reg = BitstreamRegister(0x00), const std::vector<uint32_t> &payload = {}) {
+ curr_addr = uint32_t(reg);
+ write_u32((0b001UL << 29) | ((uint32_t(op) & 0x03) << 27) | ((uint32_t(reg) & 0x3FFF) << 13) | (uint32_t(payload.size()) & 0x3FFF));
+ for (uint32_t x : payload)
+ write_u32(x, true);
+ }
+ void write_long_packet(const std::vector<uint32_t> &payload) {
+ write_u32((0b010UL << 29) | (uint32_t(OP_READ) << 27) | (uint32_t(payload.size()) & 0x3FFFFFF));
+ for (uint32_t x : payload)
+ write_u32(x, true);
+ }
+ void write_crc() {
+ write_short_packet(OP_WRITE, CRC, {curr_crc});
+ curr_crc = 0;
+ }
+};
+
+void write_bitstream(std::ofstream &f) {
+#if 0
+ // FIXME - write an actual binary bitstream
+ for (auto &frame : frames) {
+ for (size_t i = 0; i < frame.second.size(); i++) {
+ if (frame.second.at(i))
+ f << stringf("F%08xW%03dB%02d", frame.first, int(i / 32), int(i % 32)) << std::endl;
+ }
+ }
+#else
+
+ add_frame_ecc();
+
+ ByteStreamWriter bsw;
+ // Header
+ bsw.write_bytes({0x00, 0x09, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x00, 0x00, 0x01, 0x61});
+ bsw.write_string("top;UserID=0XFFFFFFFF;Version=2019.1");
+ bsw.write_byte(0x62);
+ bsw.write_string("xczu7ev-ffvc1156-2-e");
+ bsw.write_byte(0x63);
+ bsw.write_string("2019/09/08");
+ bsw.write_byte(0x64);
+ bsw.write_string("00:00:00");
+ bsw.write_bytes({0x65, 0x01, 0x36, 0x6F, 0xB0});
+ for (int i = 0; i < 64; i++)
+ bsw.write_byte(0xFF);
+ bsw.write_bytes({0x00, 0x00, 0x00, 0xBB, 0x11, 0x22, 0x00, 0x44});
+ for (int i = 0; i < 8; i++)
+ bsw.write_byte(0xFF);
+ // Preamble
+ bsw.write_u32(0xAA995566);
+ // Initial commands
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_WRITE, TIMER, {0x00000000});
+ bsw.write_short_packet(OP_WRITE, WBSTAR, {0x00000000});
+ bsw.write_short_packet(OP_WRITE, CMD, {0x00000000});
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_WRITE, CMD, {0x00000007});
+ bsw.curr_crc = 0;
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_WRITE, FAR, {0x00000000});
+ bsw.write_short_packet(OP_WRITE, BitstreamRegister(0x13), {0x00000000});
+ bsw.write_short_packet(OP_WRITE, COR0, {0x38003fe5});
+ bsw.write_short_packet(OP_WRITE, COR1, {0x00400000});
+ bsw.write_short_packet(OP_WRITE, IDCODE, {0x04a5a093});
+ bsw.write_short_packet(OP_WRITE, CMD, {0x00000009});
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_WRITE, MASK, {0x00000001});
+ bsw.write_short_packet(OP_WRITE, CTL0, {0x00000101});
+ bsw.write_short_packet(OP_WRITE, MASK, {0x00200000});
+ bsw.write_short_packet(OP_WRITE, CTL1, {0x00200000});
+ for (int i = 0; i < 8; i++)
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_WRITE, CMD, {0x00000001});
+ bsw.write_short_packet(OP_NOP);
+ // Frame data
+ std::vector<uint32_t> fdata(93, 0x00000000);
+ bsw.write_short_packet(OP_WRITE, FAR, {frames.begin()->first});
+ for (auto &fr : frames) {
+ for (int i = 0; i < 93; i++) {
+ fdata[i] = 0x00000000;
+ for (int j = 0; j < 32; j++)
+ if (fr.second.at(i * 32 + j))
+ fdata[i] |= (1 << j);
+ }
+ bsw.write_short_packet(OP_WRITE, FDRI, fdata);
+ bsw.write_short_packet(OP_WRITE, FAR, {fr.first});
+ bsw.write_crc();
+ if (!next_frame.count(fr.first) || ((next_frame.at(fr.first) ^ fr.first) & 0xFFFC0000)) {
+ // Duplicate last frame in a row, but empty??
+ for (int i = 0; i < 93; i++)
+ fdata[i] = 0;
+ bsw.write_short_packet(OP_WRITE, FDRI, fdata);
+ bsw.write_short_packet(OP_WRITE, FAR, {fr.first});
+ bsw.write_crc();
+ if (next_frame.count(fr.first)) {
+ // CMD 1 (WCFG)
+ bsw.write_short_packet(OP_WRITE, CMD, {0x00000001});
+ bsw.write_short_packet(OP_NOP);
+ // Next frame address
+ bsw.write_short_packet(OP_WRITE, FAR, {next_frame.at(fr.first)});
+ }
+ }
+
+ //bsw.write_long_packet(fdata);
+ }
+ // End of bitstream
+ bsw.write_short_packet(OP_WRITE, CMD, {0x00000000});
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_WRITE, MASK, {0x00200000});
+ bsw.write_short_packet(OP_WRITE, CTL1, {0x00000000});
+ bsw.write_crc();
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_WRITE, CMD, {0x0000000a});
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_WRITE, CMD, {0x00000003});
+ for (int i = 0; i < 20; i++)
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_WRITE, CMD, {0x00000005});
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_WRITE, FAR, {0x07FC0000});
+ bsw.write_short_packet(OP_WRITE, MASK, {0x00000101});
+ bsw.write_short_packet(OP_WRITE, CTL0, {0x00000101});
+ bsw.write_crc();
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_NOP);
+ bsw.write_short_packet(OP_WRITE, CMD, {0x0000000d});
+ for (int i = 0; i < 400; i++)
+ bsw.write_short_packet(OP_NOP);
+ f.write(reinterpret_cast<const char *>(&(bsw.data[0])), bsw.data.size());
+#endif
+}
+
+void parse_harness(const std::string &filename) {
+ LineReader rd(filename);
+ for (auto &line : rd) {
+ assert(line.at(0) == 'F');
+ const char *curr = line.c_str() + 1;
+ char *next = nullptr;
+ uint32_t frame = std::strtoul(curr, &next, 16);
+ if (roi_frames.count(frame))
+ continue;
+ assert(*next == 'W');
+ curr = next + 1;
+ int word = std::strtol(curr, &next, 10);
+ curr = next + 1;
+ assert(*next == 'B');
+ int bit = std::strtol(curr, &next, 10);
+ frames[frame].at(word * 32 + bit) = true;
+ }
+}
+
+void parse_frames(const std::string &filename, std::unordered_set<uint32_t> &dest_set) {
+ LineReader rd(filename);
+ for (auto &line : rd) {
+ const char *start = line.c_str();
+ char *end = nullptr;
+ uint32_t addr = std::strtol(start, &end, 16);
+ if ((end == nullptr) || (end == start))
+ continue;
+ dest_set.insert(addr);
+ frames[addr].clear();
+ frames[addr].resize(93*32, false);
+ }
+}
+
+void setup_base_frames() {
+ uint32_t last_frame = 0xFFFFFFFF;
+ for (auto addr : chip.all_frames) {
+ if (addr == 0x07FC0000)
+ continue;
+ frames[addr].clear();
+ frames[addr].resize(93*32, false);
+ if (last_frame != 0xFFFFFFFF)
+ next_frame[last_frame] = addr;
+ last_frame = addr;
+ }
+}
+
+int main(int argc, char *argv[]) {
+ if (argc < 6) {
+ std::cerr << "Usage: ./assemble dbdir roi_frames.txt harness.txt input.fasm out.bit" << std::endl;
+ return 2;
+ }
+ db_root = argv[1];
+ chip.open(db_root);
+ setup_base_frames();
+ parse_frames(argv[2], roi_frames);
+ parse_harness(argv[3]);
+ read_quasi_fasm(argv[4]);
+ std::ofstream obf(argv[5], std::ios::binary);
+ if (!obf) {
+ std::cerr << "failed to open " << argv[5] << std::endl;
+ return 1;
+ }
+ write_bitstream(obf);
+}
\ No newline at end of file
diff --git a/tools/bits.py b/tools/bits.py
new file mode 100644
index 0000000..e493cc4
--- /dev/null
+++ b/tools/bits.py
@@ -0,0 +1,81 @@
+# Copyright 2020 Project U-Ray Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+import sys
+import json
+# Usage: frames.txt tiles.txt tilegrid.json
+
+frame_line_re = re.compile(r'0x([0-9A-Fa-f]+).*')
+
+frame_rc_height = {}
+
+with open(sys.argv[1], 'r') as f:
+ for line in f:
+ m = frame_line_re.match(line)
+ if not m:
+ continue
+ frame = int(m.group(1), 16)
+ bus = (frame >> 24) & 0x7
+ half = (frame >> 23) & 0x1
+ row = (frame >> 18) & 0x1F
+ col = (frame >> 8) & 0x3FF
+ minor = frame & 0xFF
+ if bus != 0 or half != 0:
+ continue
+ if (row, col) not in frame_rc_height:
+ frame_rc_height[(row, col, frame & ~0xFF)] = minor + 1
+ else:
+ frame_rc_height[(row, col, frame & ~0xFF)] = max(frame_rc_height[(row, col)], minor + 1)
+
+tiles_to_xy = {}
+with open(sys.argv[2], 'r') as tilef:
+ for line in tilef:
+ sl = line.strip().split(",")
+ if len(sl) < 4:
+ continue
+ x = int(sl[0])
+ y = int(sl[1])
+ name = sl[2]
+ tiles_to_xy[name] = (x, y)
+
+with open(sys.argv[3]) as tb_f:
+ tbj = json.load(tb_f)
+
+frames_to_tiles = {}
+for tilename, tiledata in tbj.items():
+ tile_offset = 0
+ for chunk in tiledata:
+ frame, start, size = chunk
+ if frame not in frames_to_tiles:
+ frames_to_tiles[frame] = []
+ name = tilename.split(":")[0]
+ frames_to_tiles[frame].append((start, tiles_to_xy[name][1], tiles_to_xy[name][0], name))
+ tile_offset += size
+
+for frame, tiles in frames_to_tiles.items():
+ tiles.sort()
+
+for rc, height in sorted(frame_rc_height.items()):
+ row, col, frame = rc
+ line = "%08x %6d %6d %6d" % (frame, row, col, height)
+ print(line)
+ frame = (row << 18) | (col << 8)
+ last_start = 0;
+ if frame in frames_to_tiles and len(frames_to_tiles[frame]) > 0:
+ for tile in frames_to_tiles[frame]:
+ start, ty, tx, tname = tile
+ print(" %6d (%4d) %6d %6d %s" % (start, start - last_start, tx, ty, tname))
+ last_start = start
+
diff --git a/tools/bits_to_tiles.py b/tools/bits_to_tiles.py
new file mode 100644
index 0000000..42a5928
--- /dev/null
+++ b/tools/bits_to_tiles.py
@@ -0,0 +1,61 @@
+# Copyright 2020 Project U-Ray Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+import sys
+import json
+
+line_re = re.compile(r'F(0x[0-9A-Fa-f]+)W(\d+)B(\d+)')
+frames_to_tiles = {} # (start, size, tile, tile offset)
+
+with open(sys.argv[1]) as tb_f:
+ tbj = json.load(tb_f)
+
+for tilename, tiledata in tbj.items():
+ tile_offset = 0
+ for chunk in tiledata:
+ frame, start, size = chunk
+ if frame not in frames_to_tiles:
+ frames_to_tiles[frame] = []
+ frames_to_tiles[frame].append((start, size, tilename, tile_offset))
+ tile_offset += size
+
+tile_bits = {}
+
+# Always write these tiles to avoid correlation issues
+# (distinguishing between all/no bits)
+for tilename, tiledata in tbj.items():
+ if "INT_INTF_L_IO" in tilename:
+ tile_bits[tilename] = set()
+
+with open(sys.argv[2]) as df:
+ for line in df:
+ m = line_re.match(line)
+ if not m:
+ continue
+ frame = int(m[1], 16)
+ if frame not in frames_to_tiles:
+ continue
+ framebit = int(m[2]) * 32 + int(m[3])
+ for fb in frames_to_tiles[frame]:
+ start, size, tile, toff = fb
+ if framebit >= start and framebit < (start + size):
+ if tile not in tile_bits:
+ tile_bits[tile] = set()
+ tile_bits[tile].add(toff + (framebit - start))
+
+for tile, bits in sorted(tile_bits.items()):
+ print(".tile %s" % tile)
+ for b in sorted(bits):
+ print(b)
diff --git a/tools/columns.py b/tools/columns.py
new file mode 100644
index 0000000..826cc04
--- /dev/null
+++ b/tools/columns.py
@@ -0,0 +1,80 @@
+# Copyright 2020 Project U-Ray Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+import sys
+import json
+# Usage: frames.txt tiles.txt tilegrid.json
+
+frame_line_re = re.compile(r'0x([0-9A-Fa-f]+).*')
+
+frame_rc_height = {}
+
+with open(sys.argv[1], 'r') as f:
+ for line in f:
+ m = frame_line_re.match(line)
+ if not m:
+ continue
+ frame = int(m.group(1), 16)
+ bus = (frame >> 24) & 0x7
+ half = (frame >> 23) & 0x1
+ row = (frame >> 18) & 0x1F
+ col = (frame >> 8) & 0x3FF
+ minor = frame & 0xFF
+ if bus != 0 or half != 0:
+ continue
+ if (row, col) not in frame_rc_height:
+ frame_rc_height[(row, col)] = minor + 1
+ else:
+ frame_rc_height[(row, col)] = max(frame_rc_height[(row, col)], minor + 1)
+
+tiles_to_xy = {}
+with open(sys.argv[2], 'r') as tilef:
+ for line in tilef:
+ sl = line.strip().split(",")
+ if len(sl) < 4:
+ continue
+ x = int(sl[0])
+ y = int(sl[1])
+ name = sl[2]
+ tiles_to_xy[name] = (x, y)
+
+with open(sys.argv[3]) as tb_f:
+ tbj = json.load(tb_f)
+
+frames_to_tiles = {}
+for tilename, tiledata in tbj.items():
+ tile_offset = 0
+ for chunk in tiledata:
+ frame, start, size = chunk
+ if frame not in frames_to_tiles:
+ frames_to_tiles[frame] = []
+ name = tilename.split(":")[0]
+ frames_to_tiles[frame].append((tiles_to_xy[name][1], tiles_to_xy[name][0], name))
+ tile_offset += size
+
+for frame, tiles in frames_to_tiles.items():
+ tiles.sort()
+
+print("row col height tx ty tname")
+
+for rc, height in sorted(frame_rc_height.items()):
+ row, col = rc
+ line = "%6d %6d %6d" % (row, col, height)
+ frame = (row << 18) | (col << 8)
+ if frame in frames_to_tiles and len(frames_to_tiles[frame]) > 0:
+ ty, tx, tname = frames_to_tiles[frame][0]
+ line += " %6d %6d %s" % (tx, ty, tname)
+ print(line)
+
diff --git a/tools/common.cpp b/tools/common.cpp
new file mode 100644
index 0000000..01d80b0
--- /dev/null
+++ b/tools/common.cpp
@@ -0,0 +1,80 @@
+// Copyright 2020 Project U-Ray Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "common.h"
+
+
+void ChipData::open(const std::string &root) {
+ this->root = root;
+ load_frames();
+ load_tiles();
+}
+
+void ChipData::load_frames() {
+ LineReader rd(root + "/frames.txt");
+ for (const std::string &line : rd) {
+ all_frames.insert(std::strtoul(line.c_str(), nullptr, 16));
+ }
+}
+
+void ChipData::load_tiletype_database(int type) {
+ auto &tt = tiletypes.at(type);
+ if (tt.loaded_db)
+ return;
+ LineReader rd(root + "/" + tt.type + ".bits");
+ std::vector<std::string> split;
+ for (const std::string &line : rd) {
+ split_str(line, split);
+ if (split.size() < 1)
+ continue;
+ auto &feat = tt.features[split.at(0)];
+ for (size_t i = 1; i < split.size(); i++)
+ feat.push_back(std::stoi(split.at(i)));
+ }
+ tt.loaded_db = true;
+}
+
+void ChipData::load_tiles() {
+ LineReader rd(root + "/tiles.txt");
+ std::vector<std::string> split;
+ TileInstance *curr = nullptr;
+
+ for (const std::string &line : rd) {
+ split_str(line, split);
+ if (split.size() < 1)
+ continue;
+ if (split.at(0) == ".tile") {
+ curr = &(tiles[split.at(1)]);
+ curr->name = split.at(1);
+ if (!tiletype_by_name.count(split.at(2))) {
+ tiletype_by_name[split.at(2)] = int(tiletypes.size());
+ curr->type = int(tiletypes.size());
+ tiletypes.emplace_back();
+ tiletypes.back().type = split.at(2);
+ } else {
+ curr->type = tiletype_by_name.at(split.at(2));
+ }
+ curr->x = std::stoi(split.at(3));
+ curr->y = std::stoi(split.at(4));
+ } else if (split.at(0) == "frame") {
+ TileInstance::TileBitMapping tbm;
+ tbm.frame_offset = std::strtoul(split.at(1).c_str(), nullptr, 16);
+ tbm.bit_offset = std::stoi(split.at(3));
+ tbm.size = std::stoi(split.at(5));
+ curr->bits.push_back(tbm);
+ }
+ }
+}
+
+
diff --git a/tools/common.h b/tools/common.h
new file mode 100644
index 0000000..481e842
--- /dev/null
+++ b/tools/common.h
@@ -0,0 +1,211 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <stdexcept>
+#include <map>
+#include <set>
+#include <unordered_map>
+#include <stdarg.h>
+constexpr uint32_t kCrc32CastagnoliPolynomial = 0x82F63B78;
+
+// From prjxray
+// The CRC is calculated from each written data word and the current
+// register address the data is written to.
+
+// Extend the current CRC value with one register address (5bit) and
+// frame data (32bit) pair and return the newly computed CRC value.
+
+inline uint32_t icap_crc(uint32_t addr, uint32_t data, uint32_t prev) {
+ constexpr int kAddressBitWidth = 5;
+ constexpr int kDataBitWidth = 32;
+
+ uint64_t poly = static_cast<uint64_t>(kCrc32CastagnoliPolynomial) << 1;
+ uint64_t val = (static_cast<uint64_t>(addr) << 32) | data;
+ uint64_t crc = prev;
+
+ for (int i = 0; i < kAddressBitWidth + kDataBitWidth; i++) {
+ if ((val & 1) != (crc & 1))
+ crc ^= poly;
+
+ val >>= 1;
+ crc >>= 1;
+ }
+ return crc;
+}
+
+// From Yosys
+inline std::string vstringf(const char *fmt, va_list ap)
+{
+ std::string string;
+ char *str = NULL;
+
+#if defined(_WIN32 )|| defined(__CYGWIN__)
+ int sz = 64, rc;
+ while (1) {
+ va_list apc;
+ va_copy(apc, ap);
+ str = (char*)realloc(str, sz);
+ rc = vsnprintf(str, sz, fmt, apc);
+ va_end(apc);
+ if (rc >= 0 && rc < sz)
+ break;
+ sz *= 2;
+ }
+#else
+ if (vasprintf(&str, fmt, ap) < 0)
+ str = NULL;
+#endif
+
+ if (str != NULL) {
+ string = str;
+ free(str);
+ }
+
+ return string;
+}
+
+inline std::string stringf(const char *fmt, ...)
+{
+ std::string string;
+ va_list ap;
+
+ va_start(ap, fmt);
+ string = vstringf(fmt, ap);
+ va_end(ap);
+
+ return string;
+}
+
+// Bitstream definitions
+
+enum BitstreamOp : uint8_t {
+ OP_NOP = 0,
+ OP_READ = 1,
+ OP_WRITE = 2
+};
+
+// File and database convenience functions
+// Line-by-line reader, skipping over blank lines and comments
+struct LineReader {
+ LineReader(const std::string &filename) {
+ in.open(filename);
+ if (!in) {
+ throw std::runtime_error("failed to open " + filename);
+ }
+ }
+ std::ifstream in;
+ std::string linebuf;
+ bool at_sof = true;
+
+ struct iterator {
+ LineReader *parent = nullptr;
+ bool at_end = false;
+ inline bool operator!=(const iterator &other) const {
+ return at_end != other.at_end;
+ };
+ inline const std::string& operator*() const {
+ return parent->linebuf;
+ }
+ inline iterator &operator++() {
+ parent->next();
+ at_end = parent->linebuf.empty();
+ return *this;
+ }
+ };
+
+ void next() {
+ while (std::getline(in, linebuf)) {
+ auto cpos = linebuf.find('#');
+ if (cpos != std::string::npos)
+ linebuf = linebuf.substr(0, cpos);
+ if (linebuf.empty())
+ continue;
+ linebuf = linebuf.substr(linebuf.find_first_not_of(" \t"));
+ if (linebuf.empty())
+ continue;
+ break;
+ }
+ at_sof = false;
+ }
+
+ iterator begin() {
+ if (at_sof)
+ next();
+ return iterator{this, linebuf.empty()};
+ }
+
+ iterator end() {
+ return iterator{this, true};
+ }
+};
+
+struct TileInstance {
+ std::string name;
+ int type;
+ int x, y;
+ struct TileBitMapping {
+ int frame_offset;
+ int bit_offset;
+ int size;
+ };
+ std::vector<TileBitMapping> bits;
+};
+
+struct TileType {
+ std::string type;
+ bool loaded_db = false;
+ std::unordered_map<std::string, std::vector<int>> features;
+};
+
+struct ChipData {
+
+ std::string root;
+ void open(const std::string &root);
+ void load_frames();
+ void load_tiles();
+ void load_tiletype_database(int type);
+
+ std::unordered_map<std::string, TileInstance> tiles;
+ inline TileInstance &get_tile_by_name(const std::string &name) {
+ return tiles.at(name);
+ }
+
+ std::vector<TileType> tiletypes;
+ std::unordered_map<std::string, int> tiletype_by_name;
+ TileType &get_tiletype_by_name(const std::string &name) {
+ return tiletypes.at(tiletype_by_name.at(name));
+ }
+ TileType &load_tile_database(const std::string &tile) {
+ int type = tiles.at(tile).type;
+ load_tiletype_database(type);
+ return tiletypes.at(type);
+ }
+
+ std::set<uint32_t> all_frames;
+
+};
+
+inline void split_str(const std::string &s, std::vector<std::string> &dest, const std::string &delim = " ", bool skip_empty = true, int lim = -1) {
+ dest.clear();
+ std::string buf;
+
+ for (char c : s) {
+ if (delim.find(c) != std::string::npos && (lim == -1 || int(dest.size()) < lim)) {
+ if (!buf.empty() || !skip_empty)
+ dest.push_back(buf);
+ buf.clear();
+ } else {
+ buf += c;
+ }
+ }
+
+ if (!buf.empty())
+ dest.push_back(buf);
+}
+
+#endif
\ No newline at end of file
diff --git a/tools/correlate.cpp b/tools/correlate.cpp
new file mode 100644
index 0000000..2c4676d
--- /dev/null
+++ b/tools/correlate.cpp
@@ -0,0 +1,254 @@
+// Copyright 2020 Project U-Ray Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <vector>
+#include <iostream>
+#include <map>
+#include <string>
+#include <fstream>
+#include <stdexcept>
+#include <iterator>
+#include <stdarg.h>
+#include <unordered_set>
+#include <unordered_map>
+#include <set>
+#include <sstream>
+#include <algorithm>
+#include <filesystem>
+namespace fs = std::filesystem;
+
+struct FeatureData {
+ std::unordered_set<int> always_set_with_feature;
+ std::unordered_set<int> never_set_with_feature;
+ std::unordered_set<int> always_set_without_feature;
+
+ std::vector<std::pair<int, bool>> featbits;
+ std::set<std::string> deps;
+ int count;
+};
+
+struct TileTypeData {
+ std::unordered_map<std::string, std::unordered_set<std::string>> inst_features;
+ std::unordered_map<std::string, std::unordered_set<int>> inst_bits;
+ std::unordered_set<int> settable_bits;
+ std::set<std::string> extant_features;
+ std::unordered_map<std::string, FeatureData> features;
+};
+
+std::map<std::string, TileTypeData> tiletypes;
+std::set<std::string> include_tts;
+
+std::pair<std::string, std::string> split_tilename(const std::string &name) {
+ size_t idx = name.find(':');
+ return std::make_pair(name.substr(0, idx), name.substr(idx+1));
+}
+
+void parse_bits(const std::string &prefix, std::istream &in) {
+ std::string line;
+ std::unordered_set<int> *bits = nullptr;
+ std::unordered_set<int> *settable_bits = nullptr;
+ bool skip = false;
+
+ while (std::getline(in, line)) {
+ if (line.empty())
+ continue;
+ std::istringstream iss(line);
+ if (line.front() == '.') {
+ std::string t, tn;
+ iss >> t >> tn;
+ auto spn = split_tilename(tn);
+ if (!include_tts.empty() && !include_tts.count(spn.second)) {
+ skip = true;
+ continue;
+ } else {
+ skip = false;
+ }
+ settable_bits = &(tiletypes[spn.second].settable_bits);
+ bits = &(tiletypes[spn.second].inst_bits[prefix + spn.first]);
+ } else {
+ int bit = -1;
+ iss >> bit;
+ if (!skip && bit != -1) {
+ bits->insert(bit);
+ settable_bits->insert(bit);
+ }
+ }
+ }
+}
+
+void parse_features(const std::string &prefix, std::istream &in) {
+ std::string line;
+ std::unordered_set<std::string> *feats = nullptr;
+ std::set<std::string> *ext_feats = nullptr;
+ bool skip = false;
+
+ while (std::getline(in, line)) {
+ if (line.empty())
+ continue;
+ std::istringstream iss(line);
+ if (line.front() == '.') {
+ std::string t, tn;
+ iss >> t >> tn;
+ auto spn = split_tilename(tn);
+ if (!include_tts.empty() && !include_tts.count(spn.second)) {
+ skip = true;
+ continue;
+ } else {
+ skip = false;
+ }
+ ext_feats = &(tiletypes[spn.second].extant_features);
+ feats = &(tiletypes[spn.second].inst_features[prefix + spn.first]);
+ } else {
+ std::string feat;
+ iss >> feat;
+ if (!feat.empty() && !skip) {
+ feats->insert(feat);
+ ext_feats->insert(feat);
+ }
+ }
+ }
+}
+
+template <typename Tc, typename Tv, typename Tf> void set_erase_if(Tc &target, std::vector<Tv> &temp, Tf pred) {
+ temp.clear();
+ for (auto &entry : target)
+ if (pred(entry))
+ temp.push_back(entry);
+ for (auto &toerase : temp)
+ target.erase(toerase);
+}
+
+void find_feature_deps(TileTypeData &tt) {
+ for (auto &f : tt.extant_features) {
+ auto &fd = tt.features[f];
+ fd.deps = tt.extant_features;
+ fd.deps.erase(f);
+ std::vector<std::string> temp;
+ for (auto &inst : tt.inst_features) {
+ if (!inst.second.count(f))
+ continue;
+ set_erase_if(fd.deps, temp, [&](const std::string &ef){ return !inst.second.count(ef); });
+ }
+ }
+}
+
+void process_feature(TileTypeData &tt, const std::string &feature) {
+
+ FeatureData &fd = tt.features[feature];
+
+ fd.always_set_with_feature = tt.settable_bits;
+ //fd.never_set_with_feature = tt.settable_bits;
+ fd.always_set_without_feature = tt.settable_bits;
+
+ std::vector<int> temp;
+ fd.count = 0;
+ bool always_have_feature = true;
+ for (auto &inst : tt.inst_bits) {
+ if (!tt.inst_features.count(inst.first))
+ continue;
+ auto &ib = inst.second;
+ bool has_feature = tt.inst_features.at(inst.first).count(feature);
+ if (!has_feature)
+ always_have_feature = false;
+
+ if (has_feature)
+ ++fd.count;
+
+ if (has_feature)
+ set_erase_if(fd.always_set_with_feature, temp, [&](int bit){ return !ib.count(bit); });
+ //if (has_feature)
+ // set_erase_if(fd.never_set_with_feature, temp, [&](int bit){ return ib.count(bit); });
+ if (!has_feature)
+ set_erase_if(fd.always_set_without_feature, temp, [&](int bit){ return !ib.count(bit); });
+ }
+ for (int as : fd.always_set_with_feature)
+ if (always_have_feature || !fd.always_set_without_feature.count(as))
+ if (std::all_of(fd.deps.begin(), fd.deps.end(), [&](const std::string &dep) {
+ auto &dd = tt.features[dep];
+ return std::find(dd.featbits.begin(), dd.featbits.end(), std::make_pair(as, false)) == dd.featbits.end();
+ }))
+ fd.featbits.emplace_back(as, false);
+ /*for (int nv : fd.never_set_with_feature)
+ if (fd.always_set_without_feature.count(nv))
+ fd.featbits.emplace_back(nv, true);*/
+ // FIXME: inverted feature bits?
+ std::sort(fd.featbits.begin(), fd.featbits.end());
+}
+
+int main(int argc, char *argv[]) {
+ if (argc < 3) {
+ std::cerr << "usage: correlate specfolder tiledata" << std::endl;
+ return 2;
+ }
+
+ if (argc > 3) {
+ for (int i = 3; i < argc; i++)
+ include_tts.insert(argv[i]);
+ }
+
+ for (const auto &entry : fs::directory_iterator(argv[1])) {
+ auto p = entry.path();
+ if (p.extension() != ".features")
+ continue;
+ std::ifstream tilebits(p.parent_path().string() + "/" + p.stem().string() + ".tbits");
+ if (!tilebits) {
+ std::cerr << "Failed to open " << (p.parent_path().string() + "/" + p.stem().string() + ".tbits") << std::endl;
+ return 1;
+ }
+ parse_bits(p.stem().string(), tilebits);
+ std::ifstream features(p.string());
+ if (!features) {
+ std::cerr << "Failed to open " << p.string() << std::endl;
+ return 1;
+ }
+ parse_features(p.stem().string(), features);
+ }
+
+
+
+ for (auto &tiletype : tiletypes) {
+ auto &t = tiletype.second;
+ std::ofstream td(std::string(argv[2]) + "/" + tiletype.first + ".bits");
+ find_feature_deps(tiletype.second);
+ std::vector<std::string> ord_feats(t.extant_features.begin(),
+ t.extant_features.end());
+ std::stable_sort(ord_feats.begin(), ord_feats.end(), [&](const std::string &a, const std::string &b) {
+ return t.features[a].deps.size() < t.features[b].deps.size();
+ });
+
+ for (auto &feat : ord_feats) {
+ std::cerr << "Processing " << tiletype.first << "." << feat << std::endl;
+ FeatureData fd;
+ process_feature(t, feat);
+ }
+
+ for (auto &feat : t.extant_features) {
+ auto &fd = t.features[feat];
+ if (fd.count < 2)
+ continue;
+ td << feat;
+ for (auto &fb : fd.featbits)
+ td << " " << (fb.second ? "!" : "") << fb.first;
+ td << " # count: " << fd.count;
+ if (fd.deps.size() > 0) {
+ td << ", deps: ";
+ for (auto &d : fd.deps)
+ td << " " << d;
+ }
+ td << std::endl;
+ }
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tools/dump_bitstream.cpp b/tools/dump_bitstream.cpp
new file mode 100644
index 0000000..c1b3689
--- /dev/null
+++ b/tools/dump_bitstream.cpp
@@ -0,0 +1,278 @@
+// Copyright 2020 Project U-Ray Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <vector>
+#include <iostream>
+#include <map>
+#include <string>
+#include <fstream>
+#include <stdexcept>
+#include <iterator>
+#include <stdarg.h>
+#include <iomanip>
+#include "common.h"
+
+const uint32_t preamble = 0xAA995566;
+
+#define SKIP_CRC
+#define SKIP_CHECKSUM
+#define SKIP_COMMENT
+
+class dummy_ostream : public std::ostream {
+
+};
+
+dummy_ostream dummy_out;
+
+bool verbose_flag = false;
+
+#define COMMENT(x) (verbose_flag ? std::cout : dummy_out) << x << std::endl
+
+
+struct ByteStreamReader {
+ std::vector<uint8_t> data;
+ std::size_t ptr = 0;
+ void reset() {
+ ptr = 0;
+ }
+ bool done() {
+ return ptr >= (data.size() - 3);
+ }
+ uint32_t curr_crc = 0;
+ uint32_t curr_addr = 0;
+
+ uint32_t next_u32(bool skip_crc = false) {
+ if (done())
+ throw std::runtime_error("at end of bitstream");
+ uint32_t val = data[ptr] << 24UL | data[ptr+1] << 16UL | data[ptr+2] << 8UL | data[ptr+3];
+ ptr += 4;
+ if (!skip_crc)
+ curr_crc = icap_crc(curr_addr, val, curr_crc);
+ return val;
+ }
+
+ uint32_t peek_u32() {
+ if (done())
+ throw std::runtime_error("at end of bitstream");
+ uint32_t val = data[ptr] << 24UL | data[ptr+1] << 16UL | data[ptr+2] << 8UL | data[ptr+3];
+ return val;
+ }
+ void skip_till_preamble() {
+ while (peek_u32() != preamble)
+ ++ptr;
+ COMMENT("# found preamble at offset " << ptr);
+ ptr += 4;
+ }
+};
+
+
+
+enum BitstreamRegister : uint16_t {
+ #define X(a, b) a = b,
+ #include "registers.inc"
+ #undef X
+};
+
+
+
+std::string get_register_name(uint16_t val) {
+ BitstreamRegister r = (BitstreamRegister)val;
+ #define X(a, b) if (val == a) return #a;
+ #include "registers.inc"
+ #undef X
+ return stringf("reg%04x", val);
+}
+
+std::map<uint32_t, uint32_t> next_frame;
+
+void parse_bitstream(ByteStreamReader &rd) {
+ rd.reset();
+ rd.skip_till_preamble();
+ uint32_t frame = 0;
+ uint16_t last_reg = 0;
+ uint64_t checksum = 0, exp_checksum = 0;
+ int word = 0;
+ auto is_checksum = [] (int w, int b) {
+ return ((w == 45 && b <= 31) || (w == 46 && b <= 15));
+ };
+
+ auto get_ecc_value = [](int word, int bit) {
+ int nib = bit / 4;
+ int nibbit = bit % 4;
+ // ECC offset is expanded to 1 bit per nibble,
+ // and then shifted based on the bit index in nibble
+ // e.g. word 3, bit 9
+ // offset: 0b10100110010 - concatenate (3 + (255 - 92)) [frame offset] and 9/4 [nibble offset]
+ // becomes: 0x10100110010
+ // shifted by bit in nibble (9%4): 0x20200220020
+ uint32_t offset = (word + (255 - 92)) << 3 | nib;
+ uint64_t exp_offset = 0;
+ // Odd parity
+ offset ^= (1 << 11);
+ for (int i = 0; i < 11; i++)
+ if (offset & (1 << i)) offset ^= (1 << 11);
+ // Expansion
+ for (int i = 0; i < 12; i++)
+ if (offset & (1 << i)) exp_offset |= (1ULL << (4 * i));
+ return exp_offset << nibbit;
+ };
+
+ auto process_word = [&](uint32_t data) {
+
+
+ for (int i = 0; i < 32; i++)
+ if (data & (1 << i)) {
+ if (is_checksum(word, i)) {
+ checksum |= 1ULL << ((word - 45) * 32 + i);
+#ifdef SKIP_CHECKSUM
+ continue;
+#endif
+ } else {
+ exp_checksum ^= get_ecc_value(word, i);
+ }
+ std::cout << stringf("F0x%08xW%03dB%02d", frame, word, i) << std::endl;
+ }
+ ++word;
+ if (word >= 93 && next_frame.count(frame)) {
+ // 4 parity bits for each bit in nibbles
+#if 0
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 11; j++)
+ if (exp_checksum & (1ULL << (4 * j + i)))
+ exp_checksum ^= (1ULL << (44 + i));
+#endif
+ COMMENT(stringf("# checksum: 0x%012llX calc: 0x%012llX %s", checksum, exp_checksum, (checksum == exp_checksum) ? "" : "~~~~~"));
+ checksum = 0;
+ exp_checksum = 0;
+ frame = next_frame.at(frame);
+ }
+ };
+
+ while (!rd.done()) {
+ uint32_t hdr = rd.next_u32(true);
+ if (hdr == 0xFFFFFFFF) {
+ COMMENT("# desync");
+ rd.skip_till_preamble();
+ continue;
+ }
+ uint8_t type = (hdr >> 29) & 0x07;
+ if (type == 0b001) {
+ // Type 1 (short) packet
+ uint8_t op = (hdr >> 27) & 0x03;
+ switch(op) {
+ case 0x00:
+ COMMENT("# NOP ");
+ // NOP
+ break;
+ case 0x01:
+ // READ
+ break;
+ case 0x02: {
+ // WRITE
+ uint16_t reg = (hdr >> 13) & 0x3FFF;
+ rd.curr_addr = reg;
+ last_reg = reg;
+ int count = hdr & 0x3FF;
+ COMMENT("# write " << get_register_name(reg));
+ if (reg == FAR) {
+ if (count != 1)
+ COMMENT("# bad FAR length " << count);
+ exp_checksum = 0;
+ checksum = 0;
+ frame = rd.next_u32();
+ word = 0;
+ COMMENT(stringf("# frame 0x%08x", frame));
+ } else if (reg == CRC) {
+ uint32_t crc = 0;
+ for(int i = 0; i < count; i++)
+ crc = rd.next_u32(true);
+ COMMENT(stringf("# CRC written=%08x calc=%08x %s", crc, rd.curr_crc, (crc == rd.curr_crc) ? "" : "*****"));
+ rd.curr_crc = 0;
+ } else if (reg == FDRI) {
+ for(int i = 0; i < count; i++)
+ process_word(rd.next_u32());
+ } else if (reg == CMD) {
+ uint32_t cmd = 0;
+ for(int i = 0; i < count; i++)
+ cmd = rd.next_u32();
+ COMMENT(stringf("# CMD %08x", cmd));
+ if (cmd == 0x7)
+ rd.curr_crc = 0;
+ } else {
+ for(int i = 0; i < count; i++)
+ COMMENT(stringf("# data %08x", rd.next_u32()));
+ }
+
+ if (reg == CRC && next_frame.count(frame)) {
+ exp_checksum = 0;
+ checksum = 0;
+ frame = next_frame.at(frame);
+ }
+
+ } break;
+ }
+ } else if (type == 0b010) {
+ // Type 2 (long) packet
+ int count = hdr & 0x3FFFFFF;
+ if (last_reg == FDRI) {
+ for(int i = 0; i < count; i++)
+ process_word(rd.next_u32());
+ } else {
+ for(int i = 0; i < count; i++)
+ COMMENT(stringf("# data %08x", rd.next_u32()));
+ }
+ } else {
+ std::cout << stringf("# unknown packet type %01x (header: %08x)", type, hdr) << std::endl;
+ return;
+ }
+ }
+}
+
+int main(int argc, char *argv[]) {
+ if (argc < 2) {
+ std::cerr << "Usage: dump_bitstream file.bit [frames.txt] [verbose]" << std::endl;
+ return 2;
+ }
+
+ if (argc > 2) {
+ std::ifstream frame_db(argv[2]);
+ bool had_last = false;
+ uint32_t last;
+ uint32_t val;
+ frame_db.unsetf(std::ios::dec);
+ frame_db.unsetf(std::ios::hex);
+ frame_db.unsetf(std::ios::oct);
+ while (frame_db >> val) {
+ if (had_last)
+ next_frame[last] = val;
+ last = val;
+ had_last = true;
+ }
+ }
+
+ if (argc > 3) {
+ if (std::string(argv[3]) == "verbose")
+ verbose_flag = true;
+ }
+
+ ByteStreamReader rd;
+ std::ifstream file(argv[1], std::ios::binary);
+ file.unsetf(std::ios::skipws);
+ if (!file) {
+ std::cerr << "Failed to open input file" << std::endl;
+ return 2;
+ }
+ rd.data.insert(rd.data.begin(), std::istream_iterator<uint8_t>(file), std::istream_iterator<uint8_t>());
+ parse_bitstream(rd);
+}
\ No newline at end of file
diff --git a/tools/explain.cpp b/tools/explain.cpp
new file mode 100644
index 0000000..acc1d07
--- /dev/null
+++ b/tools/explain.cpp
@@ -0,0 +1,146 @@
+// Copyright 2020 Project U-Ray Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <vector>
+#include <iostream>
+#include <map>
+#include <string>
+#include <fstream>
+#include <stdexcept>
+#include <iterator>
+#include <stdarg.h>
+#include <iomanip>
+#include <filesystem>
+#include <map>
+#include <set>
+#include <cassert>
+#include "common.h"
+
+ChipData chip;
+
+struct Tile {
+ std::string name, type;
+ TileInstance *data;
+ std::set<int> set_bits;
+ std::set<int> unknown_bits;
+ std::set<std::string> matched_features;
+};
+
+std::vector<Tile> tiles;
+std::unordered_map<std::string, int> tile_by_name;
+
+struct InverseTileBitMap {
+ int tile;
+ int offset_in_frame;
+ int offset_in_tile;
+ int size;
+};
+
+std::unordered_map<uint32_t, std::vector<InverseTileBitMap>> tiles_by_frame;
+
+void parse_bits(const std::string &filename) {
+ LineReader rd(filename);
+ for (auto &line : rd) {
+ assert(line.at(0) == 'F');
+ const char *curr = line.c_str() + 1;
+ char *next = nullptr;
+ uint32_t frame = std::strtoul(curr, &next, 16);
+ assert(*next == 'W');
+ curr = next + 1;
+ int word = std::strtol(curr, &next, 10);
+ curr = next + 1;
+ assert(*next == 'B');
+ int bit = std::strtol(curr, &next, 10);
+ if (tiles_by_frame.count(frame)) {
+ int fb = word * 32 + bit;
+ for (auto &t : tiles_by_frame.at(frame)) {
+ if (fb >= t.offset_in_frame && fb < (t.offset_in_frame + t.size)) {
+ int tilebit = (fb - t.offset_in_frame) + t.offset_in_tile;
+ tiles[t.tile].set_bits.insert(tilebit);
+ tiles[t.tile].unknown_bits.insert(tilebit);
+ }
+ }
+ }
+ }
+}
+
+// Currently have poor quality DBs for these tiles,
+// skip outputting them
+std::set<std::string> skip_tiles = {
+ "CLEL_L", "CLEM_R", "RCLK_INT_R",
+};
+
+
+void setup_tiles() {
+ for (auto &tile : chip.tiles) {
+ auto &ti = tile.second;
+ if (skip_tiles.count(chip.tiletypes[ti.type].type))
+ continue;
+ Tile t;
+ t.name = ti.name;
+ t.type = chip.tiletypes[ti.type].type;
+ t.data = &ti;
+ tile_by_name[ti.name] = int(tiles.size());
+
+ int off = 0;
+ for (auto &b : ti.bits) {
+ tiles_by_frame[b.frame_offset].push_back(InverseTileBitMap{int(tiles.size()), b.bit_offset, off, b.size});
+ off += b.size;
+ }
+
+ tiles.push_back(t);
+
+ }
+}
+
+
+void process_tile(Tile &t) {
+ if (t.set_bits.empty())
+ return;
+ auto &td = chip.load_tile_database(t.name);
+ for (const auto &feat : td.features) {
+ if (feat.second.empty())
+ continue;
+ bool matched = true;
+ for (auto bit : feat.second)
+ if (!t.set_bits.count(bit)) {
+ matched = false;
+ break;
+ }
+ if (!matched)
+ continue;
+ t.matched_features.insert(feat.first);
+ for (auto bit : feat.second)
+ t.unknown_bits.erase(bit);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ if (argc < 3) {
+ std::cerr << "usage: explain dbdir/ bitstream.dump" << std::endl;
+ return 2;
+ }
+ chip.open(argv[1]);
+ setup_tiles();
+ parse_bits(argv[2]);
+ for (auto &t : tiles) {
+ process_tile(t);
+ for (auto &f : t.matched_features)
+ std::cout << t.name << "." << f << std::endl;
+ for (auto b : t.unknown_bits)
+ std::cout << t.name << ".?" << b << std::endl;
+ if (!t.matched_features.empty() || !t.unknown_bits.empty())
+ std::cout << std::endl;
+ }
+}
\ No newline at end of file
diff --git a/tools/filter.py b/tools/filter.py
new file mode 100644
index 0000000..8776311
--- /dev/null
+++ b/tools/filter.py
@@ -0,0 +1,30 @@
+# Copyright 2020 Project U-Ray Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+import sys
+import json
+
+line_re = re.compile(r'F(0x[0-9A-Fa-f]+)W(\d+)B(\d+)')
+frames_to_tiles = {} # (start, size, tile, tile offset)
+
+active = False
+
+with open(sys.argv[1]) as f:
+ for line in f:
+ sl = line.strip()
+ if sl[0] == '.':
+ active = sys.argv[2] in sl
+ if active:
+ print(sl)
\ No newline at end of file
diff --git a/tools/frames.py b/tools/frames.py
new file mode 100644
index 0000000..8265cb3
--- /dev/null
+++ b/tools/frames.py
@@ -0,0 +1,37 @@
+# Copyright 2020 Project U-Ray Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+import sys
+
+line_re = re.compile(r'F(0x[0-9A-Fa-f]+).*')
+
+outlines = set()
+
+with open(sys.argv[1], 'r') as f:
+ for line in f:
+ m = line_re.match(line)
+ if not m:
+ continue
+ frame = int(m.group(1), 16)
+ bus = (frame >> 24) & 0x7
+ half = (frame >> 23) & 0x1
+ row = (frame >> 18) & 0x1F
+ col = (frame >> 8) & 0x3FF
+ minor = frame & 0xFF
+ outlines.add("F=%08x B=%d H=%d R=%03d C=%04d M=%03d"
+ % (frame, bus, half, row, col, minor))
+
+for o in sorted(outlines):
+ print(o)
diff --git a/tools/frames_2.py b/tools/frames_2.py
new file mode 100644
index 0000000..0fe5890
--- /dev/null
+++ b/tools/frames_2.py
@@ -0,0 +1,37 @@
+# Copyright 2020 Project U-Ray Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+import sys
+
+line_re = re.compile(r'0x([0-9A-Fa-f]+).*')
+
+outlines = set()
+
+with open(sys.argv[1], 'r') as f:
+ for line in f:
+ m = line_re.match(line)
+ if not m:
+ continue
+ frame = int(m.group(1), 16)
+ bus = (frame >> 24) & 0x7
+ half = (frame >> 23) & 0x1
+ row = (frame >> 18) & 0x1F
+ col = (frame >> 8) & 0x3FF
+ minor = frame & 0xFF
+ outlines.add("F=%08x B=%d H=%d R=%03d C=%04d M=%03d"
+ % (frame, bus, half, row, col, minor))
+
+for o in sorted(outlines):
+ print(o)
diff --git a/tools/ll.py b/tools/ll.py
new file mode 100644
index 0000000..f65beb9
--- /dev/null
+++ b/tools/ll.py
@@ -0,0 +1,38 @@
+# Copyright 2020 Project U-Ray Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+import sys
+
+line_re = re.compile(r'Bit\s+\d+\s+(0x[0-9A-Fa-f]+)\s+\d+\s+SLR\d\s+\d+\s+Block=([A-Za-z0-9_]+).*')
+
+outlines = set()
+
+with open(sys.argv[1], 'r') as f:
+ for line in f:
+ m = line_re.match(line)
+ if not m:
+ continue
+ frame = int(m.group(1), 16)
+ site = m.group(2)
+ bus = (frame >> 24) & 0x7
+ half = (frame >> 23) & 0x1
+ row = (frame >> 18) & 0x1F
+ col = (frame >> 8) & 0x3FF
+ minor = frame & 0xFF
+ outlines.add("F=%08x B=%d H=%d R=%03d C=%04d M=%03d %s"
+ % (frame, bus, half, row, col, minor, site))
+
+for o in sorted(outlines):
+ print(o)
diff --git a/tools/oddtiles.py b/tools/oddtiles.py
new file mode 100644
index 0000000..82451cf
--- /dev/null
+++ b/tools/oddtiles.py
@@ -0,0 +1,58 @@
+# Copyright 2020 Project U-Ray Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+import sys
+import json
+
+line_re = re.compile(r'F(0x[0-9A-Fa-f]+)W(\d+)B(\d+)')
+frames_to_tiles = {} # (start, size, tile, tile offset)
+
+with open(sys.argv[1]) as tb_f:
+ tbj = json.load(tb_f)
+
+for tilename, tiledata in tbj.items():
+ tile_offset = 0
+ for chunk in tiledata:
+ frame, start, size = chunk
+ if frame not in frames_to_tiles:
+ frames_to_tiles[frame] = []
+ frames_to_tiles[frame].append((start, size, tilename, tile_offset))
+ tile_offset += size
+
+tile_bits = {}
+
+with open(sys.argv[2]) as df:
+ for line in df:
+ m = line_re.match(line)
+ if not m:
+ continue
+ frame = int(m[1], 16)
+ if frame not in frames_to_tiles:
+ continue
+ framebit = int(m[2]) * 32 + int(m[3])
+ for fb in frames_to_tiles[frame]:
+ start, size, tile, toff = fb
+ if framebit > start and framebit < (start + size):
+ if tile not in tile_bits:
+ tile_bits[tile] = set()
+ tile_bits[tile].add(toff + (framebit - start))
+
+for tile, bits in sorted(tile_bits.items()):
+ if "CLE" in tile:
+ if 152 not in bits:
+ print(tile)
+ if "INT" in tile:
+ if 3640 not in bits:
+ print(tile)
\ No newline at end of file
diff --git a/tools/registers.inc b/tools/registers.inc
new file mode 100644
index 0000000..0f0c8d8
--- /dev/null
+++ b/tools/registers.inc
@@ -0,0 +1,20 @@
+X(CRC , 0b00000)
+X(FAR , 0b00001)
+X(FDRI , 0b00010)
+X(FDRO , 0b00011)
+X(CMD , 0b00100)
+X(CTL0 , 0b00101)
+X(MASK , 0b00110)
+X(STAT , 0b00111)
+X(LOUT , 0b01000)
+X(COR0 , 0b01001)
+X(MFWR , 0b01010)
+X(CBC , 0b01011)
+X(IDCODE , 0b01100)
+X(AXSS , 0b01101)
+X(COR1 , 0b01110)
+X(WBSTAR , 0b10000)
+X(TIMER , 0b10001)
+X(BOOTSTS, 0b10110)
+X(CTL1 , 0b11000)
+X(BSPI , 0b11111)
\ No newline at end of file
diff --git a/tools/roi.py b/tools/roi.py
new file mode 100644
index 0000000..e1b217a
--- /dev/null
+++ b/tools/roi.py
@@ -0,0 +1,78 @@
+# Copyright 2020 Project U-Ray Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+import sys
+import json
+# Usage: tilegrid.json
+with open(sys.argv[1]) as tb_f:
+ tbj = json.load(tb_f)
+tile_to_frames = {}
+frame_to_tiles = {}
+for tilename, tiledata in tbj.items():
+ tn = tilename.split(":")[0]
+ tile_offset = 0
+ tile_to_frames[tn] = []
+ for chunk in tiledata:
+ frame, start, size = chunk
+ tile_to_frames[tn].append(frame)
+ if frame not in frame_to_tiles:
+ frame_to_tiles[frame] = []
+ frame_to_tiles[frame].append(tn)
+basis_tiles = [
+ "CLEM_X41Y120",
+ "INT_X41Y120",
+ "CLEL_R_X41Y120",
+ "BRAM_X42Y120",
+ "INT_INTF_L_X42Y120",
+ "INT_X42Y120",
+ "CLEL_R_X42Y120",
+ "CLEM_X43Y120",
+ "INT_X43Y120",
+ "INT_INTF_R_X43Y120",
+ "DSP_X43Y120",
+ "CLEM_X44Y120",
+ "INT_X44Y120",
+ "CLEL_R_X44Y120",
+ "CLEM_X45Y120",
+ "INT_X45Y120",
+ "INT_INTF_R_X45Y120",
+ "DSP_X45Y120",
+ "CLEM_X46Y120",
+ "INT_X46Y120",
+ "CLEL_R_X46Y120",
+ "INT_X47Y120",
+ "CLEL_R_X47Y120"
+]
+
+roi_frames = set()
+
+for tile in basis_tiles:
+ if tile not in tile_to_frames:
+ continue
+ for frame in tile_to_frames[tile]:
+ roi_frames.add(frame)
+
+roi_tiles = set()
+for frame in roi_frames:
+ for tile in frame_to_tiles[frame]:
+ roi_tiles.add(tile)
+
+with open(sys.argv[2], "w") as frames_f:
+ for frame in sorted(roi_frames):
+ print("0x%08x" % frame, file=frames_f)
+
+with open(sys.argv[3], "w") as tiles_f:
+ for tile in sorted(roi_tiles):
+ print("tile %s" % tile, file=tiles_f)
\ No newline at end of file
diff --git a/tools/stripdb.cpp b/tools/stripdb.cpp
new file mode 100644
index 0000000..01ff1ab
--- /dev/null
+++ b/tools/stripdb.cpp
@@ -0,0 +1,104 @@
+// Copyright 2020 Project U-Ray Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <vector>
+#include <iostream>
+#include <map>
+#include <string>
+#include <fstream>
+#include <stdexcept>
+#include <iterator>
+#include <stdarg.h>
+#include <iomanip>
+#include <filesystem>
+#include <map>
+#include <set>
+
+namespace fs = std::filesystem;
+
+
+struct TileType {
+ std::map<std::string, std::vector<int>> features;
+};
+
+std::map<std::string, TileType> tiletypes;
+
+
+void parse_database(const std::string &name, std::istream &in) {
+ std::string line;
+ while (std::getline(in, line)) {
+ auto cpos = line.find('#');
+ if (cpos != std::string::npos)
+ line = line.substr(0, cpos);
+ if (line.empty())
+ continue;
+ std::istringstream iss(line);
+ std::string featname;
+ iss >> featname;
+ if (featname.empty())
+ continue;
+ tiletypes[name].features[featname];
+ int bit = -1;
+ iss >> bit;
+ while (bit != -1) {
+ tiletypes[name].features[featname].push_back(bit);
+ bit = -1;
+ iss >> bit;
+ }
+ }
+}
+
+
+int main(int argc, char *argv[]) {
+ if (argc < 3) {
+ std::cerr << "usage: stripdb in/ out/" << std::endl;
+ return 2;
+ }
+
+ // Currently have poor quality DBs for these tiles,
+ // skip outputting them
+ std::set<std::string> skip_tiles = {
+ "CLEL_L", "CLEM_R", "RCLK_INT_R",
+ };
+
+ for (const auto &entry : fs::directory_iterator(argv[1])) {
+ auto p = entry.path();
+ if (p.extension() != ".bits")
+ continue;
+ std::ifstream tiledata(p.string());
+ if (skip_tiles.count(p.stem()))
+ continue;
+ parse_database(p.stem(), tiledata);
+ }
+
+ // Misc cleanups
+ for (auto &f : tiletypes["INT"].features)
+ if (f.first.find(".VCC_WIRE") != std::string::npos)
+ f.second.clear();
+
+ for (const auto &tt : tiletypes) {
+ if(tt.second.features.empty())
+ continue;
+ std::string dbname = std::string(argv[2]) + "/" + tt.first + ".bits";
+ std::ofstream out(dbname);
+ if (!out)
+ std::cerr << "failed to open " << dbname << " for writing." << std::endl;
+ for (auto &f : tt.second.features) {
+ out << f.first;
+ for (int bit : f.second)
+ out << " " << bit;
+ out << std::endl;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/tilebits.py b/tools/tilebits.py
new file mode 100644
index 0000000..57fbe2b
--- /dev/null
+++ b/tools/tilebits.py
@@ -0,0 +1,151 @@
+# Copyright 2020 Project U-Ray Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+import sys
+import json
+
+tiles = {}
+site_to_tile = {}
+tile_to_bits = {} # (frame, bit start, bit size)
+
+with open(sys.argv[1], 'r') as tilef:
+ for line in tilef:
+ sl = line.strip().split(",")
+ if len(sl) < 4:
+ continue
+ x = int(sl[0])
+ y = int(sl[1])
+ name = sl[2]
+ ttype = sl[3]
+ tiles[(x, y)] = (name + ":" + ttype, ttype, [])
+ for site in sl[4:]:
+ sitename, sitetype = site.split(":")
+ tiles[(x, y)][2].append((sitename, sitetype))
+ site_to_tile[sitename] = (x, y)
+
+ll_line_re = re.compile(r'Bit\s+\d+\s+(0x[0-9A-Fa-f]+)\s+(\d+)\s+SLR\d\s+\d+\s+Block=([A-Za-z0-9_]+).*')
+site_re = re.compile(r'SLICE_X(\d+)Y(\d+)')
+with open(sys.argv[2], 'r') as llf:
+ for line in llf:
+ m = ll_line_re.match(line)
+ if not m:
+ continue
+ frame = int(m.group(1), 16)
+ bit = int(m.group(2))
+ start_bit = bit - 2
+ site = m.group(3)
+ bus = (frame >> 24) & 0x7
+ half = (frame >> 23) & 0x1
+ row = (frame >> 18) & 0x1F
+ col = (frame >> 8) & 0x3FF
+ m = frame & 0xFF
+
+
+ sm = site_re.match(site)
+ site_x = int(sm.group(1))
+ site_y = int(sm.group(2))
+ frame_upper = frame & ~0xFF
+
+
+ if site not in site_to_tile:
+ continue
+ tx, ty = site_to_tile[site]
+ tiledata = tiles[tx, ty]
+ tile_to_bits[tiledata[0]] = []
+ for m in range(16):
+ tile_to_bits[tiledata[0]].append((frame_upper | m, start_bit, 48))
+
+ def process_nonlogic(x, y, icol):
+ if (x, y) not in tiles:
+ return
+ itiledata = tiles[x, y]
+ if itiledata[1] == "INT":
+ if (x + 1, y) not in tiles:
+ return
+
+ int_frame_base = (frame_upper & ~0x3FFFF) | (icol << 8)
+ tile_to_bits[itiledata[0]] = []
+ for m in range(76):
+ tile_to_bits[itiledata[0]].append((int_frame_base | m, start_bit, 48))
+ process_clock(x, y-1, int_frame_base, start_bit + 48, 76)
+ process_cmt(x-2, y, icol-2)
+ process_int_intf(x-1, y, icol-1)
+ elif itiledata[1] == "BRAM":
+ bram_frame_base = (frame_upper & ~0x3FFFF) | (icol << 8)
+ tile_to_bits[itiledata[0]] = []
+ for m in range(6):
+ tile_to_bits[itiledata[0]].append((bram_frame_base | m, start_bit, 5 * 48))
+ process_clock(x, y-5, bram_frame_base, start_bit + 5*48, 6)
+ elif itiledata[1] == "DSP":
+ dsp_frame_base = (frame_upper & ~0x3FFFF) | (icol << 8)
+ tile_to_bits[itiledata[0]] = []
+ for m in range(8):
+ tile_to_bits[itiledata[0]].append((dsp_frame_base | m, start_bit, 5 * 48))
+ process_clock(x, y-5, dsp_frame_base, start_bit + 5*48, 8)
+
+ if (x - 1, y) in tiles and "INT_INTF" in tiles[x - 1, y][1]:
+ process_clock(x-1, y-5, dsp_frame_base, start_bit + 5*48, 8)
+
+ def process_clock(cx, cy, frame_base, end_bit, height):
+ if (cx, cy) not in tiles:
+ return
+ if end_bit != (1392 + 48):
+ return
+ ctiledata = tiles[cx, cy]
+ if not ctiledata[1].startswith("RCLK"):
+ return
+ tile_to_bits[ctiledata[0]] = []
+ for m in range(height):
+ tile_to_bits[ctiledata[0]].append((frame_base | m, end_bit + 48, 48))
+
+ def process_cmt(x, y, icol):
+ if (x, y) not in tiles:
+ return
+ ctiledata = tiles[x, y]
+ if not ctiledata[1] in ("CMT_L", "CMT_RIGHT"):
+ return
+ cmt_frame_base = (frame_upper & ~0x3FFFF) | (icol << 8)
+ tile_to_bits[ctiledata[0]] = []
+ for m in range(12):
+ tile_to_bits[ctiledata[0]].append((cmt_frame_base | m, start_bit, 60 * 48))
+
+ def process_int_intf(x, y, icol):
+ if (x, y) not in tiles:
+ return
+ itiledata = tiles[x, y]
+ if not itiledata[1] in ("INT_INTF_L_IO", "INT_INTF_R_IO"):
+ return
+ int_frame_base = (frame_upper & ~0x3FFFF) | (icol << 8)
+ tile_to_bits[itiledata[0]] = []
+ for m in range(4):
+ tile_to_bits[itiledata[0]].append((int_frame_base | m, start_bit, 48))
+
+
+ process_nonlogic(tx-1, ty, col-1)
+ process_nonlogic(tx+1, ty, col+1)
+ process_clock(tx, ty-1, frame_upper, start_bit + 48, 16)
+# Original JSON
+with open(sys.argv[3], 'w') as tj:
+ tj.write(json.dumps(tile_to_bits, sort_keys=True, indent=4, separators=(',', ': ')))
+ tj.write("\n")
+# New simplified text format
+with open(sys.argv[4], 'w') as tf:
+ for loc, tiledata in sorted(tiles.items()):
+ print(".tile %s %s %d %d" % (tiledata[0].split(":")[0], tiledata[1], loc[0], loc[1]), file=tf)
+ for site in tiledata[2]:
+ print("site %s %s" % site, file=tf)
+ if tiledata[0] in tile_to_bits:
+ for frame, offset, size in tile_to_bits[tiledata[0]]:
+ print("frame 0x%08x bits %d +: %d" % (frame, offset, size), file=tf)
\ No newline at end of file