#!/usr/bin/env python3 # # Copyright (C) 2015 Clifford Wolf # # 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. # import iceboxdb import re, sys class iceconfig: def __init__(self): self.clear() def clear(self): self.max_x = 0 self.max_y = 0 self.device = "" self.warmboot = True self.logic_tiles = dict() self.io_tiles = dict() self.ramb_tiles = dict() self.ramt_tiles = dict() self.dsp_tiles = [dict() for i in range(4)] self.ipcon_tiles = dict() self.ram_data = dict() self.extra_bits = set() self.symbols = dict() def setup_empty_384(self): self.clear() self.device = "384" self.max_x = 7 self.max_y = 9 for x in range(1, self.max_x): for y in range(1, self.max_y): self.logic_tiles[(x, y)] = ["0" * 54 for i in range(16)] for x in range(1, self.max_x): self.io_tiles[(x, 0)] = ["0" * 18 for i in range(16)] self.io_tiles[(x, self.max_y)] = ["0" * 18 for i in range(16)] for y in range(1, self.max_y): self.io_tiles[(0, y)] = ["0" * 18 for i in range(16)] self.io_tiles[(self.max_x, y)] = ["0" * 18 for i in range(16)] def setup_empty_1k(self): self.clear() self.device = "1k" self.max_x = 13 self.max_y = 17 for x in range(1, self.max_x): for y in range(1, self.max_y): if x in (3, 10): if y % 2 == 1: self.ramb_tiles[(x, y)] = ["0" * 42 for i in range(16)] else: self.ramt_tiles[(x, y)] = ["0" * 42 for i in range(16)] else: self.logic_tiles[(x, y)] = ["0" * 54 for i in range(16)] for x in range(1, self.max_x): self.io_tiles[(x, 0)] = ["0" * 18 for i in range(16)] self.io_tiles[(x, self.max_y)] = ["0" * 18 for i in range(16)] for y in range(1, self.max_y): self.io_tiles[(0, y)] = ["0" * 18 for i in range(16)] self.io_tiles[(self.max_x, y)] = ["0" * 18 for i in range(16)] def setup_empty_5k(self): self.clear() self.device = "5k" self.max_x = 25 self.max_y = 31 for x in range(1, self.max_x): for y in range(1, self.max_y): if x in (6, 19): if y % 2 == 1: self.ramb_tiles[(x, y)] = ["0" * 42 for i in range(16)] else: self.ramt_tiles[(x, y)] = ["0" * 42 for i in range(16)] else: self.logic_tiles[(x, y)] = ["0" * 54 for i in range(16)] for x in range(1, self.max_x): self.io_tiles[(x, 0)] = ["0" * 18 for i in range(16)] self.io_tiles[(x, self.max_y)] = ["0" * 18 for i in range(16)] for x in [0, self.max_x]: for y in range(1, self.max_y): if y in [5, 10, 15, 23]: self.dsp_tiles[0][(x, y)] = ["0" * 54 for i in range(16)] elif y in [6, 11, 16, 24]: self.dsp_tiles[1][(x, y)] = ["0" * 54 for i in range(16)] elif y in [7, 12, 17, 25]: self.dsp_tiles[2][(x, y)] = ["0" * 54 for i in range(16)] elif y in [8, 13, 18, 26]: self.dsp_tiles[3][(x, y)] = ["0" * 54 for i in range(16)] else: self.ipcon_tiles[(x, y)] = ["0" * 54 for i in range(16)] def setup_empty_8k(self): self.clear() self.device = "8k" self.max_x = 33 self.max_y = 33 for x in range(1, self.max_x): for y in range(1, self.max_y): if x in (8, 25): if y % 2 == 1: self.ramb_tiles[(x, y)] = ["0" * 42 for i in range(16)] else: self.ramt_tiles[(x, y)] = ["0" * 42 for i in range(16)] else: self.logic_tiles[(x, y)] = ["0" * 54 for i in range(16)] for x in range(1, self.max_x): self.io_tiles[(x, 0)] = ["0" * 18 for i in range(16)] self.io_tiles[(x, self.max_y)] = ["0" * 18 for i in range(16)] for y in range(1, self.max_y): self.io_tiles[(0, y)] = ["0" * 18 for i in range(16)] self.io_tiles[(self.max_x, y)] = ["0" * 18 for i in range(16)] def lookup_extra_bit(self, bit): assert self.device in extra_bits_db if bit in extra_bits_db[self.device]: return extra_bits_db[self.device][bit] return ("UNKNOWN_FUNCTION",) def tile(self, x, y): if (x, y) in self.io_tiles: return self.io_tiles[(x, y)] if (x, y) in self.logic_tiles: return self.logic_tiles[(x, y)] if (x, y) in self.ramb_tiles: return self.ramb_tiles[(x, y)] if (x, y) in self.ramt_tiles: return self.ramt_tiles[(x, y)] for i in range(4): if (x, y) in self.dsp_tiles[i]: return self.dsp_tiles[i][(x, y)] if (x, y) in self.ipcon_tiles: return self.ipcon_tiles[(x, y)] return None def pinloc_db(self): if self.device == "384": return pinloc_db["384-qn32"] if self.device == "1k": return pinloc_db["1k-tq144"] if self.device == "5k": return pinloc_db["5k-sg48"] if self.device == "8k": return pinloc_db["8k-ct256"] assert False def gbufin_db(self): return gbufin_db[self.device] def iolatch_db(self): return iolatch_db[self.device] def padin_pio_db(self): return padin_pio_db[self.device] def extra_bits_db(self): return extra_bits_db[self.device] def ieren_db(self): return ieren_db[self.device] def pll_list(self): if self.device == "1k": return ["1k"] if self.device == "5k": return ["5k"] if self.device == "8k": return ["8k_0", "8k_1"] if self.device == "384": return [ ] assert False # Return true if device is Ultra/UltraPlus series, i.e. has # IpConnect/DSP at the sides instead of IO def is_ultra(self): return self.device in ["5k"] def colbuf_db(self): if self.device == "1k": entries = list() for x in range(self.max_x+1): for y in range(self.max_y+1): src_y = None if 0 <= y <= 4: src_y = 4 if 5 <= y <= 8: src_y = 5 if 9 <= y <= 12: src_y = 12 if 13 <= y <= 17: src_y = 13 if x in [3, 10] and src_y == 4: src_y = 3 if x in [3, 10] and src_y == 12: src_y = 11 entries.append((x, src_y, x, y)) return entries if self.device == "8k": entries = list() for x in range(self.max_x+1): for y in range(self.max_y+1): src_y = None if 0 <= y <= 8: src_y = 8 if 9 <= y <= 16: src_y = 9 if 17 <= y <= 24: src_y = 24 if 25 <= y <= 33: src_y = 25 entries.append((x, src_y, x, y)) return entries if self.device == "5k": #Interesting, seems the 5k has more colbufs? entries = list() for x in range(self.max_x+1): for y in range(self.max_y+1): src_y = None if 0 <= y <= 4: src_y = 4 if 5 <= y <= 10: src_y = 5 if 11 <= y <= 14: src_y = 14 if 15 <= y <= 20: src_y = 15 if 21 <= y <= 26: src_y = 26 if 27 <= y <= 31: src_y = 27 entries.append((x, src_y, x, y)) return entries if self.device == "384": entries = list() for x in range(self.max_x+1): for y in range(self.max_y+1): src_y = None #Is ColBufCtrl relevant? if 0 <= y <= 2: src_y = 2 #384? if 3 <= y <= 4: src_y = 3 #384? if 5 <= y <= 6: src_y = 6 #384? if 7 <= y <= 9: src_y = 7 #384? entries.append((x, src_y, x, y)) return entries assert False # Return a map between HDL name and routing net and location for a given DSP cell def get_dsp_nets_db(self, x, y): assert ((x, y) in self.dsp_tiles[0]) # Control signals nets = { "CLK": (x, y+2, "lutff_global/clk"), "CE": (x, y+2, "lutff_global/cen"), "IRSTTOP": (x, y+1, "lutff_global/s_r"), "IRSTBOT": (x, y+0, "lutff_global/s_r"), "ORSTTOP": (x, y+3, "lutff_global/s_r"), "ORSTBOT": (x, y+2, "lutff_global/s_r"), "AHOLD": (x, y+2, "lutff_0/in_0"), "BHOLD": (x, y+1, "lutff_0/in_0"), "CHOLD": (x, y+3, "lutff_0/in_0"), "DHOLD": (x, y+0, "lutff_0/in_0"), "OHOLDTOP": (x, y+3, "lutff_1/in_0"), "OHOLDBOT": (x, y+0, "lutff_1/in_0"), "ADDSUBTOP": (x, y+3, "lutff_3/in_0"), "ADDSUBBOT": (x, y+0, "lutff_3/in_0"), "OLOADTOP": (x, y+3, "lutff_2/in_0"), "OLOADBOT": (x, y+0, "lutff_2/in_0"), "CI": (x, y+0, "lutff_4/in_0"), "CO": (x, y+4, "slf_op_0") } #Data ports for i in range(8): nets["C_%d" % i] = (x, y+3, "lutff_%d/in_3" % i) nets["C_%d" % (i+8)] = (x, y+3, "lutff_%d/in_1" % i) nets["A_%d" % i] = (x, y+2, "lutff_%d/in_3" % i) nets["A_%d" % (i+8)] = (x, y+2, "lutff_%d/in_1" % i) nets["B_%d" % i] = (x, y+1, "lutff_%d/in_3" % i) nets["B_%d" % (i+8)] = (x, y+1, "lutff_%d/in_1" % i) nets["D_%d" % i] = (x, y+0, "lutff_%d/in_3" % i) nets["D_%d" % (i+8)] = (x, y+0, "lutff_%d/in_1" % i) for i in range(32): nets["O_%d" % i] = (x, y+(i//8), "mult/O_%d" % i) return nets # Return the location of configuration bits for a given DSP cell def get_dsp_config_db(self, x, y): assert ((x, y) in self.dsp_tiles[0]) override = { } if (("%s_%d_%d" % (self.device, x, y)) in dsp_config_db): override = dsp_config_db["%s_%d_%d" % (self.device, x, y)] default_db = dsp_config_db["default"] merged = { } for cfgkey in default_db: cx, cy, cbit = default_db[cfgkey] if cfgkey in override: cx, cy, cbit = override[cfgkey] merged[cfgkey] = (x + cx, y + cy, cbit) return merged def tile_db(self, x, y): # Only these devices have IO on the left and right sides. if self.device in ["384", "1k", "8k"]: if x == 0: return iotile_l_db if x == self.max_x: return iotile_r_db # The 5k needs an IO db including the extra bits if self.device == "5k": if y == 0: return iotile_b_5k_db if y == self.max_y: return iotile_t_5k_db else: if y == 0: return iotile_b_db if y == self.max_y: return iotile_t_db if self.device == "1k": if (x, y) in self.logic_tiles: return logictile_db if (x, y) in self.ramb_tiles: return rambtile_db if (x, y) in self.ramt_tiles: return ramttile_db elif self.device == "5k": if (x, y) in self.logic_tiles: return logictile_5k_db if (x, y) in self.ramb_tiles: return rambtile_8k_db if (x, y) in self.ramt_tiles: return ramttile_8k_db if (x, y) in self.ipcon_tiles: return ipcon_5k_db if (x, y) in self.dsp_tiles[0]: return dsp0_5k_db if (x, y) in self.dsp_tiles[1]: return dsp1_5k_db if (x, y) in self.dsp_tiles[2]: return dsp2_5k_db if (x, y) in self.dsp_tiles[3]: return dsp3_5k_db elif self.device == "8k": if (x, y) in self.logic_tiles: return logictile_8k_db if (x, y) in self.ramb_tiles: return rambtile_8k_db if (x, y) in self.ramt_tiles: return ramttile_8k_db elif self.device == "384": if (x, y) in self.logic_tiles: return logictile_384_db print("Tile type unknown at (%d, %d)" % (x, y)) assert False def tile_type(self, x, y): if x == 0 and (not self.is_ultra()): return "IO" if y == 0: return "IO" if x == self.max_x and (not self.is_ultra()): return "IO" if y == self.max_y: return "IO" if (x, y) in self.ramb_tiles: return "RAMB" if (x, y) in self.ramt_tiles: return "RAMT" if (x, y) in self.logic_tiles: return "LOGIC" if (x == 0 or x == self.max_x) and self.is_ultra(): if y in [5, 10, 15, 23]: return "DSP0" elif y in [6, 11, 16, 24]: return "DSP1" elif y in [7, 12, 17, 25]: return "DSP2" elif y in [8, 13, 18, 26]: return "DSP3" else: return "IPCON" assert False def tile_pos(self, x, y): if x == 0 and 0 < y < self.max_y: return "l" if y == 0 and 0 < x < self.max_x: return "b" if x == self.max_x and 0 < y < self.max_y: return "r" if y == self.max_y and 0 < x < self.max_x: return "t" if 0 < x < self.max_x and 0 < y < self.max_y: return "x" return None def tile_has_entry(self, x, y, entry): if entry[1] in ("routing", "buffer"): return self.tile_has_net(x, y, entry[2]) and self.tile_has_net(x, y, entry[3]) return True def tile_has_net(self, x, y, netname): if netname.startswith("logic_op_"): if netname.startswith("logic_op_bot_"): if y == self.max_y and 0 < x < self.max_x: return True if netname.startswith("logic_op_bnl_"): if x == self.max_x and 1 < y < self.max_y and (not self.is_ultra()): return True if y == self.max_y and 1 < x < self.max_x: return True if netname.startswith("logic_op_bnr_"): if x == 0 and 1 < y < self.max_y and (not self.is_ultra()): return True if y == self.max_y and 0 < x < self.max_x-1: return True if netname.startswith("logic_op_top_"): if y == 0 and 0 < x < self.max_x: return True if netname.startswith("logic_op_tnl_"): if x == self.max_x and 0 < y < self.max_y-1 and (not self.is_ultra()): return True if y == 0 and 1 < x < self.max_x: return True if netname.startswith("logic_op_tnr_"): if x == 0 and 0 < y < self.max_y-1 and (not self.is_ultra()): return True if y == 0 and 0 < x < self.max_x-1: return True if netname.startswith("logic_op_lft_"): if x == self.max_x and (not self.is_ultra()): return True if netname.startswith("logic_op_rgt_"): if x == 0 and (not self.is_ultra()): return True return False if not 0 <= x <= self.max_x: return False if not 0 <= y <= self.max_y: return False return pos_has_net(self.tile_pos(x, y), netname) def tile_follow_net(self, x, y, direction, netname): if x == 1 and y not in (0, self.max_y) and direction == 'l': return pos_follow_net("x", "L", netname, self.is_ultra()) if y == 1 and x not in (0, self.max_x) and direction == 'b': return pos_follow_net("x", "B", netname, self.is_ultra()) if x == self.max_x-1 and y not in (0, self.max_y) and direction == 'r': return pos_follow_net("x", "R", netname, self.is_ultra()) if y == self.max_y-1 and x not in (0, self.max_x) and direction == 't': return pos_follow_net("x", "T", netname, self.is_ultra()) if self.is_ultra(): # Pass through corner positions as they must be handled differently if y == 1 and x in (0, self.max_x) and direction == 'b': return pos_follow_net(self.tile_pos(x, y), "B", netname, self.is_ultra()) if y == self.max_y-1 and x in (0, self.max_x) and direction == 't': return pos_follow_net(self.tile_pos(x, y), "T", netname, self.is_ultra()) if x == 1 and y in (0, self.max_y) and direction == 'l': return pos_follow_net(self.tile_pos(x, y), "L", netname, self.is_ultra()) if x == self.max_x-1 and y in (0, self.max_y) and direction == 'r': return pos_follow_net(self.tile_pos(x, y), "R", netname, self.is_ultra()) return pos_follow_net(self.tile_pos(x, y), direction, netname, self.is_ultra()) def follow_funcnet(self, x, y, func): neighbours = set() def do_direction(name, nx, ny): if (0 < nx < self.max_x or self.is_ultra()) and 0 < ny < self.max_y: neighbours.add((nx, ny, "neigh_op_%s_%d" % (name, func))) if nx in (0, self.max_x) and 0 < ny < self.max_y and nx != x and (not self.is_ultra()): neighbours.add((nx, ny, "logic_op_%s_%d" % (name, func))) if ny in (0, self.max_y) and 0 < nx < self.max_x and ny != y: neighbours.add((nx, ny, "logic_op_%s_%d" % (name, func))) do_direction("bot", x, y+1) do_direction("bnl", x+1, y+1) do_direction("bnr", x-1, y+1) do_direction("top", x, y-1) do_direction("tnl", x+1, y-1) do_direction("tnr", x-1, y-1) do_direction("lft", x+1, y ) do_direction("rgt", x-1, y ) return neighbours def lookup_funcnet(self, nx, ny, x, y, func): npos = self.tile_pos(nx, ny) pos = self.tile_pos(x, y) if npos is not None and pos is not None: if npos == "x": if (nx, ny) in self.logic_tiles: return (nx, ny, "lutff_%d/out" % func) for i in range(4): if (nx, ny) in self.dsp_tiles[i]: #TODO: check this return (nx, ny, "mult/O_%d" % (i * 8 + func)) if (nx, ny) in self.ramb_tiles: if self.device == "1k": return (nx, ny, "ram/RDATA_%d" % func) elif self.device == "5k": return (nx, ny, "ram/RDATA_%d" % (15-func)) elif self.device == "8k": return (nx, ny, "ram/RDATA_%d" % (15-func)) else: assert False if (nx, ny) in self.ramt_tiles: if self.device == "1k": return (nx, ny, "ram/RDATA_%d" % (8+func)) elif self.device == "5k": return (nx, ny, "ram/RDATA_%d" % (7-func)) elif self.device == "8k": return (nx, ny, "ram/RDATA_%d" % (7-func)) else: assert False elif pos == "x" and ((npos in ("t", "b")) or ((not self.is_ultra()) and (npos in ("l", "r")))): if func in (0, 4): return (nx, ny, "io_0/D_IN_0") if func in (1, 5): return (nx, ny, "io_0/D_IN_1") if func in (2, 6): return (nx, ny, "io_1/D_IN_0") if func in (3, 7): return (nx, ny, "io_1/D_IN_1") return None def rlookup_funcnet(self, x, y, netname): funcnets = set() if netname == "io_0/D_IN_0": for net in self.follow_funcnet(x, y, 0) | self.follow_funcnet(x, y, 4): if self.tile_pos(net[0], net[1]) == "x": funcnets.add(net) if netname == "io_0/D_IN_1": for net in self.follow_funcnet(x, y, 1) | self.follow_funcnet(x, y, 5): if self.tile_pos(net[0], net[1]) == "x": funcnets.add(net) if netname == "io_1/D_IN_0": for net in self.follow_funcnet(x, y, 2) | self.follow_funcnet(x, y, 6): if self.tile_pos(net[0], net[1]) == "x": funcnets.add(net) if netname == "io_1/D_IN_1": for net in self.follow_funcnet(x, y, 3) | self.follow_funcnet(x, y, 7): if self.tile_pos(net[0], net[1]) == "x": funcnets.add(net) match = re.match(r"lutff_(\d+)/out", netname) if match: funcnets |= self.follow_funcnet(x, y, int(match.group(1))) match = re.match(r"ram/RDATA_(\d+)", netname) if match: if self.device == "1k": funcnets |= self.follow_funcnet(x, y, int(match.group(1)) % 8) elif self.device == "5k": funcnets |= self.follow_funcnet(x, y, 7 - int(match.group(1)) % 8) elif self.device == "8k": funcnets |= self.follow_funcnet(x, y, 7 - int(match.group(1)) % 8) else: assert False return funcnets def ultraplus_follow_corner(self, corner, direction, netname): m = re.match("span4_(horz|vert)_([lrtb])_(\d+)$", netname) if not m: return None cur_edge = m.group(2) cur_index = int(m.group(3)) if direction not in corner: return None if direction != cur_edge: return None h_idx, v_idx = self.ultraplus_trace_corner_idx(corner, cur_index) if h_idx is None and (direction == "b" or direction == "t"): return None if v_idx is None and (direction == "l" or direction == "r"): return None if corner == "bl" and direction == "l": return (0, 1, sp4v_normalize("sp4_v_b_%d" % v_idx)) if corner == "bl" and direction == "b": return (1, 0, ultra_span4_horz_normalize("span4_horz_l_%d" % h_idx)) if corner == "br" and direction == "r": return (self.max_x, 1
/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2019  whitequark <whitequark@whitequark.org>
 *
 *  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.
 *
 */

// The reason the -path mode of connect_rpc uses byte-oriented and not message-oriented sockets, even though
// it is a message-oriented interface, is that the system can place various limits on the message size, which
// are not always transparent or easy to change. Given that generated HDL code get be extremely large, it is
// unwise to rely on those limits being large enough, and using byte-oriented sockets is guaranteed to work.

#ifndef _WIN32
#include <unistd.h>
#include <spawn.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
extern char **environ;
#endif

#include "libs/json11/json11.hpp"
#include "libs/sha1/sha1.h"
#include "kernel/yosys.h"

YOSYS_NAMESPACE_BEGIN

#if defined(_WIN32)
static std::wstring str2wstr(const std::string &in) {
    if(in == "") return L"";
    std::wstring out;
    out.resize(MultiByteToWideChar(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpMultiByteStr=*/&in[0], /*cbMultiByte=*/(int)in.length(), /*lpWideCharStr=*/NULL, /*cchWideChar=*/0));
    int written = MultiByteToWideChar(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpMultiByteStr=*/&in[0], /*cbMultiByte=*/(int)in.length(), /*lpWideCharStr=*/&out[0], /*cchWideChar=*/(int)out.length());
    log_assert(written == (int)out.length());
    return out;
}

static std::string wstr2str(const std::wstring &in) {
	if(in == L"") return "";
	std::string out;
	out.resize(WideCharToMultiByte(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpWideCharStr=*/&in[0], /*cchWideChar=*/(int)in.length(), /*lpMultiByteStr=*/NULL, /*cbMultiByte=*/0, /*lpDefaultChar=*/NULL, /*lpUsedDefaultChar=*/NULL));
	int written = WideCharToMultiByte(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpWideCharStr=*/&in[0], /*cchWideChar=*/(int)in.length(), /*lpMultiByteStr=*/&out[0], /*cbMultiByte=*/(int)out.length(), /*lpDefaultChar=*/NULL, /*lpUsedDefaultChar=*/NULL);
	log_assert(written == (int)out.length());
	return out;
}

static std::string get_last_error_str() {
	DWORD last_error = GetLastError();
	LPWSTR out_w;
	DWORD size_w = FormatMessageW(/*dwFlags=*/FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS, /*lpSource=*/NULL, /*dwMessageId=*/last_error, /*dwLanguageId=*/0, /*lpBuffer=*/(LPWSTR)&out_w, /*nSize=*/0, /*Arguments=*/NULL);
	if (size_w == 0)
		return std::to_string(last_error);
	std::string out = wstr2str(std::wstring(out_w, size_w));
	LocalFree(out_w);
	return out;
}
#endif

using json11::Json;

struct RpcServer {
	std::string name;

	RpcServer(const std::string &name) : name(name) { }
	virtual ~RpcServer() { }

	virtual void write(const std::string &data) = 0;
	virtual std::string read() = 0;

	Json call(const Json &json_request) {
		std::string request;
		json_request.dump(request);
		request += '\n';
		log_debug("RPC frontend request: %s", request.c_str());
		write(request);

		std::string response = read();
		log_debug("RPC frontend response: %s", response.c_str());
		std::string error;
		Json json_response = Json::parse(response, error);
		if (json_response.is_null())
			log_cmd_error("parsing JSON failed: %s\n", error.c_str());
		if (json_response["error"].is_string())
			log_cmd_error("RPC frontend returned an error: %s\n", json_response["error"].string_value().c_str());
		return json_response;
	}

	std::vector<std::string> get_module_names() {
		Json response = call(Json::object {
			{ "method", "modules" },
		});
		bool is_valid = true;
		std::vector<std::string> modules;
		if (response["modules"].is_array()) {
			for (auto &json_module : response["modules"].array_items()) {
				if (json_module.is_string())
					modules.push_back(json_module.string_value());
				else is_valid = false;
			}
		} else is_valid = false;
		if (!is_valid)
			log_cmd_error("RPC frontend returned malformed response: %s\n", response.dump().c_str());
		return modules;
	}

	std::pair<std::string, std::string> derive_module(const std::string &module, const dict<RTLIL::IdString, RTLIL::Const> &parameters) {
		Json::object json_parameters;
		for (auto &param : parameters) {
			std::string type, value;
			if (param.second.flags & RTLIL::CONST_FLAG_REAL) {
				type = "real";
				value = param.second.decode_string();
			} else if (param.second.flags & RTLIL::CONST_FLAG_STRING) {
				type = "string";
				value = param.second.decode_string();
			} else if ((param.second.flags & ~RTLIL::CONST_FLAG_SIGNED) == RTLIL::CONST_FLAG_NONE) {
				type = (param.second.flags & RTLIL::CONST_FLAG_SIGNED) ? "signed" : "unsigned";
				value = param.second.as_string();
			} else
				log_cmd_error("Unserializable constant flags 0x%x\n", param.second.flags);
			json_parameters[param.first.str()] = Json::object {
				{ "type", type },
				{ "value", value },
			};
		}
		Json response = call(Json::object {
			{ "method", "derive" },
			{ "module", module },
			{ "parameters", json_parameters },
		});
		bool is_valid = true;
		std::string frontend, source;
		if (response["frontend"].is_string())
			frontend = response["frontend"].string_value();
		else is_valid = false;
		if (response["source"].is_string())
			source = response["source"].string_value();
		else is_valid = false;
		if (!is_valid)
			log_cmd_error("RPC frontend returned malformed response: %s\n", response.dump().c_str());
		return std::make_pair(frontend, source);
	}
};

struct RpcModule : RTLIL::Module {
	std::shared_ptr<RpcServer> server;

	RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool /*mayfail*/) YS_OVERRIDE {
		std::string stripped_name = name.str();
		if (stripped_name.compare(0, 9, "$abstract") == 0)
			stripped_name = stripped_name.substr(9);
		log_assert(stripped_name[0] == '\\');

		log_header(design, "Executing RPC frontend `%s' for module `%s'.\n", server->name.c_str(), stripped_name.c_str());

		std::string parameter_info;
		for (auto &param : parameters) {
			log("Parameter %s = %s\n", param.first.c_str(), log_signal(RTLIL::SigSpec(param.second)));
			parameter_info += stringf("%s=%s", param.first.c_str(), log_signal(RTLIL::SigSpec(param.second)));
		}

		std::string derived_name;
		if (parameters.empty())
			derived_name = stripped_name;
		else if (parameter_info.size() > 60)
			derived_name = "$paramod$" + sha1(parameter_info) + stripped_name;
		else
			derived_name = "$paramod" + stripped_name + parameter_info;

		if (design->has(derived_name)) {
			log("Found cached RTLIL representation for module `%s'.\n", derived_name.c_str());
		} else {
			std::string command, input;
			std::tie(command, input) = server->derive_module(stripped_name.substr(1), parameters);

			std::istringstream input_stream(input);
			RTLIL::Design *derived_design = new RTLIL::Design;
			Frontend::frontend_call(derived_design, &input_stream, "<rpc>" + derived_name.substr(8), command);
			derived_design->check();

			dict<std::string, std::string> name_mangling;
			bool found_derived_top = false;
			for (auto module : derived_design->modules()) {
				std::string original_name = module->name.str();
				if (original_name == stripped_name) {
					found_derived_top = true;
					name_mangling[original_name] = derived_name;
				} else {
					name_mangling[original_name] = derived_name + module->name.str();
				}
			}
			if (!found_derived_top)
				log_cmd_error("RPC frontend did not return requested module `%s`!\n", stripped_name.c_str());

			for (auto module : derived_design->modules())
				for (auto cell : module->cells())
					if (name_mangling.count(cell->type.str()))
						cell->type = name_mangling[cell->type.str()];

			for (auto module : derived_design->modules_) {
				std::string mangled_name = name_mangling[module.first.str()];

				log("Importing `%s' as `%s'.\n", log_id(module.first), log_id(mangled_name));

				module.second->name = mangled_name;
				module.second->design = design;
				module.second->attributes.erase("\\top");
				design->modules_[mangled_name] = module.second;
				derived_design->modules_.erase(module.first);
			}

			delete derived_design;
		}

		return derived_name;
	}

	RTLIL::Module *clone() const YS_OVERRIDE {
		RpcModule *new_mod = new RpcModule;
		new_mod->server = server;
		cloneInto(new_mod);
		return new_mod;
	}
};

#if defined(_WIN32)

#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif

struct HandleRpcServer : RpcServer {
	HANDLE hsend, hrecv;

	HandleRpcServer(const std::string &name, HANDLE hsend, HANDLE hrecv)
		: RpcServer(name), hsend(hsend), hrecv(hrecv) { }

	void write(const std::string &data) YS_OVERRIDE {
		log_assert(data.length() >= 1 && data.find('\n') == data.length() - 1);
		ssize_t offset = 0;
		do {
			DWORD data_written;
			if (!WriteFile(hsend, &data[offset], data.length() - offset, &data_written, /*lpOverlapped=*/NULL))
				log_cmd_error("WriteFile failed: %s\n", get_last_error_str().c_str());
			offset += data_written;
		} while(offset < (ssize_t)data.length());
	}

	std::string read() YS_OVERRIDE {
		std::string data;
		ssize_t offset = 0;
		while (data.length() == 0 || data[data.length() - 1] != '\n') {
			data.resize(data.length() + 1024);
			DWORD data_read;
			if (!ReadFile(hrecv, &data[offset], data.length() - offset, &data_read, /*lpOverlapped=*/NULL))
				log_cmd_error("ReadFile failed: %s\n", get_last_error_str().c_str());
			offset += data_read;
			data.resize(offset);
			size_t term_pos = data.find('\n', offset);
			if (term_pos != data.length() - 1 && term_pos != std::string::npos)
				log_cmd_error("read failed: more than one response\n");
		}
		return data;
	}

	~HandleRpcServer() {
		CloseHandle(hsend);
		if (hrecv != hsend)
			CloseHandle(hrecv);
	}
};

#else

struct FdRpcServer : RpcServer {
	int fdsend, fdrecv;
	pid_t pid;

	FdRpcServer(const std::string &name, int fdsend, int fdrecv, pid_t pid = -1)
		: RpcServer(name), fdsend(fdsend), fdrecv(fdrecv), pid(pid) { }

	void check_pid() {
		if (pid == -1) return;
		// If we're communicating with a process, check that it's still running, or we may get killed with SIGPIPE.
		pid_t wait_result = ::waitpid(pid, NULL, WNOHANG);
		if (wait_result == -1)
			log_cmd_error("waitpid failed: %s\n", strerror(errno));
		if (wait_result == pid)
			log_cmd_error("RPC frontend terminated unexpectedly\n");
	}

	void write(const std::string &data) YS_OVERRIDE {
		log_assert(data.length() >= 1 && data.find('\n') == data.length() - 1);
		ssize_t offset = 0;
		do {
			check_pid();
			ssize_t result = ::write(fdsend, &data[offset], data.length() - offset);
			if (result == -1)
				log_cmd_error("write failed: %s\n", strerror(errno));
			offset += result;
		} while(offset < (ssize_t)data.length());
	}

	std::string read() YS_OVERRIDE {
		std::string data;
		ssize_t offset = 0;
		while (data.length() == 0 || data[data.length() - 1] != '\n') {
			data.resize(data.length() + 1024);
			check_pid();
			ssize_t result = ::read(fdrecv, &data[offset], data.length() - offset);
			if (result == -1)
				log_cmd_error("read failed: %s\n", strerror(errno));
			offset += result;
			data.resize(offset);
			size_t term_pos = data.find('\n', offset);
			if (term_pos != data.length() - 1 && term_pos != std::string::npos)
				log_cmd_error("read failed: more than one response\n");
		}
		return data;
	}

	~FdRpcServer() {
		close(fdsend);
		if (fdrecv != fdsend)
			close(fdrecv);
	}
};

#endif

// RpcFrontend does not inherit from Frontend since it does not read files.
struct RpcFrontend : public Pass {
	RpcFrontend() : Pass("connect_rpc", "connect to RPC frontend") { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    connect_rpc -exec <command> [args...]\n");
		log("    connect_rpc -path <path>\n");
		log("\n");
		log("Load modules using an out-of-process frontend.\n");
		log("\n");
		log("    -exec <command> [args...]\n");
		log("        run <command> with arguments [args...]. send requests on stdin, read\n");
		log("        responses from stdout.\n");
		log("\n");
		log("    -path <path>\n");
		log("        connect to Unix domain socket at <path>. (Unix)\n");
		log("        connect to bidirectional byte-type named pipe at <path>. (Windows)\n");
		log("\n");
		log("A simple JSON-based, newline-delimited protocol is used for communicating with\n");
		log("the frontend. Yosys requests data from the frontend by sending exactly 1 line\n");
		log("of JSON. Frontend responds with data or error message by replying with exactly\n");
		log("1 line of JSON as well.\n");
		log("\n");
		log("    -> {\"method\": \"modules\"}\n");
		log("    <- {\"modules\": [\"<module-name>\", ...]}\n");
		log("    <- {\"error\": \"<error-message>\"}\n");
		log("        request for the list of modules that can be derived by this frontend.\n");
		log("        the 'hierarchy' command will call back into this frontend if a cell\n");
		log("        with type <module-name> is instantiated in the design.\n");
		log("\n");
		log("    -> {\"method\": \"derive\", \"module\": \"<module-name\">, \"parameters\": {\n");
		log("        \"<param-name>\": {\"type\": \"[unsigned|signed|string|real]\",\n");
		log("                           \"value\": \"<param-value>\"}, ...}}\n");
		log("    <- {\"frontend\": \"[ilang|verilog|...]\",\"source\": \"<source>\"}}\n");
		log("    <- {\"error\": \"<error-message>\"}\n");
		log("        request for the module <module-name> to be derived for a specific set of\n");
		log("        parameters. <param-name> starts with \\ for named parameters, and with $\n");
		log("        for unnamed parameters, which are numbered starting at 1.<param-value>\n");
		log("        for integer parameters is always specified as a binary string of unlimited\n");
		log("        precision. the <source> returned by the frontend is hygienically parsed\n");
		log("        by a built-in Yosys <frontend>, allowing the RPC frontend to return any\n");
		log("        convenient representation of the module. the derived module is cached,\n");
		log("        so the response should be the same whenever the same set of parameters\n");
		log("        is provided.\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		log_header(design, "Connecting to RPC frontend.\n");

		std::vector<std::string> command;
		std::string path;
		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++) {
			std::string arg = args[argidx];
			if (arg == "-exec" && argidx+1 < args.size()) {
				command.insert(command.begin(), args.begin() + argidx + 1, args.end());
				continue;
			}
			if (arg == "-path" && argidx+1 < args.size()) {
				path = args[argidx+1];
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		if ((!command.empty()) + (!path.empty()) != 1)
			log_cmd_error("Exactly one of -exec, -unix must be specified.\n");

		std::shared_ptr<RpcServer> server;
		if (!command.empty()) {
			std::string command_line;
			bool first = true;
			for (auto &arg : command) {
				if (!first) command_line += ' ';
				command_line += arg;
				first = false;
			}

#ifdef _WIN32
			std::wstring command_w = str2wstr(command[0]);
			std::wstring command_path_w;
			std::wstring command_line_w = str2wstr(command_line);
			DWORD command_path_len_w;
			SECURITY_ATTRIBUTES pipe_attr = {};
			HANDLE send_r = NULL, send_w = NULL, recv_r = NULL, recv_w = NULL;
			STARTUPINFOW startup_info = {};
			PROCESS_INFORMATION proc_info = {};

			command_path_len_w = SearchPathW(/*lpPath=*/NULL, /*lpFileName=*/command_w.c_str(), /*lpExtension=*/L".exe", /*nBufferLength=*/0, /*lpBuffer=*/NULL, /*lpFilePart=*/NULL);
			if (command_path_len_w == 0) {
				log_error("SearchPathW failed: %s\n", get_last_error_str().c_str());
				goto cleanup_exec;
			}
			command_path_w.resize(command_path_len_w - 1);
			command_path_len_w = SearchPathW(/*lpPath=*/NULL, /*lpFileName=*/command_w.c_str(), /*lpExtension=*/L".exe", /*nBufferLength=*/command_path_len_w, /*lpBuffer=*/&command_path_w[0], /*lpFilePart=*/NULL);
			log_assert(command_path_len_w == command_path_w.length());

			pipe_attr.nLength = sizeof(pipe_attr);
			pipe_attr.bInheritHandle = TRUE;
			pipe_attr.lpSecurityDescriptor = NULL;
			if (!CreatePipe(&send_r, &send_w, &pipe_attr, /*nSize=*/0)) {
				log_error("CreatePipe failed: %s\n", get_last_error_str().c_str());
				goto cleanup_exec;
			}
			if (!SetHandleInformation(send_w, HANDLE_FLAG_INHERIT, 0)) {
				log_error("SetHandleInformation failed: %s\n", get_last_error_str().c_str());
				goto cleanup_exec;
			}
			if (!CreatePipe(&recv_r, &recv_w, &pipe_attr, /*nSize=*/0)) {
				log_error("CreatePipe failed: %s\n", get_last_error_str().c_str());
				goto cleanup_exec;
			}
			if (!SetHandleInformation(recv_r, HANDLE_FLAG_INHERIT, 0)) {
				log_error("SetHandleInformation failed: %s\n", get_last_error_str().c_str());
				goto cleanup_exec;
			}

			startup_info.cb = sizeof(startup_info);
			startup_info.hStdInput = send_r;
			startup_info.hStdOutput = recv_w;
			startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
			startup_info.dwFlags |= STARTF_USESTDHANDLES;
			if (!CreateProcessW(/*lpApplicationName=*/command_path_w.c_str(), /*lpCommandLine=*/&command_line_w[0], /*lpProcessAttributes=*/NULL, /*lpThreadAttributes=*/NULL, /*bInheritHandles=*/TRUE, /*dwCreationFlags=*/0, /*lpEnvironment=*/NULL, /*lpCurrentDirectory=*/NULL, &startup_info, &proc_info)) {
				log_error("CreateProcessW failed: %s\n", get_last_error_str().c_str());
				goto cleanup_exec;
			}
			CloseHandle(proc_info.hProcess);
			CloseHandle(proc_info.hThread);

			server = std::make_shared<HandleRpcServer>(path, send_w, recv_r);
			send_w = NULL;
			recv_r = NULL;

cleanup_exec:
			if (send_r != NULL) CloseHandle(send_r);
			if (send_w != NULL) CloseHandle(send_w);
			if (recv_r != NULL) CloseHandle(recv_r);
			if (recv_w != NULL) CloseHandle(recv_w);
#else
			std::vector<char *> argv;
			int send[2] = {-1,-1}, recv[2] = {-1,-1};
			posix_spawn_file_actions_t file_actions, *file_actions_p = NULL;
			pid_t pid;

			for (auto &arg : command)
				argv.push_back(&arg[0]);
			argv.push_back(nullptr);

			if (pipe(send) != 0) {
				log_error("pipe failed: %s\n", strerror(errno));
				goto cleanup_exec;
			}
			if (pipe(recv) != 0) {
				log_error("pipe failed: %s\n", strerror(errno));
				goto cleanup_exec;
			}

			if (posix_spawn_file_actions_init(&file_actions) != 0) {
				log_error("posix_spawn_file_actions_init failed: %s\n", strerror(errno));
				goto cleanup_exec;
			}
			file_actions_p = &file_actions;
			if (posix_spawn_file_actions_adddup2(file_actions_p, send[0], STDIN_FILENO) != 0) {
				log_error("posix_spawn_file_actions_adddup2 failed: %s\n", strerror(errno));
				goto cleanup_exec;
			}
			if (posix_spawn_file_actions_addclose(file_actions_p, send[1]) != 0) {
				log_error("posix_spawn_file_actions_addclose failed: %s\n", strerror(errno));
				goto cleanup_exec;
			}
			if (posix_spawn_file_actions_adddup2(file_actions_p, recv[1], STDOUT_FILENO) != 0) {
				log_error("posix_spawn_file_actions_adddup2 failed: %s\n", strerror(errno));
				goto cleanup_exec;
			}
			if (posix_spawn_file_actions_addclose(file_actions_p, recv[0]) != 0) {
				log_error("posix_spawn_file_actions_addclose failed: %s\n", strerror(errno));
				goto cleanup_exec;
			}

			if (posix_spawnp(&pid, argv[0], file_actions_p, /*attrp=*/NULL, argv.data(), environ) != 0) {
				log_error("posix_spawnp failed: %s\n", strerror(errno));
				goto cleanup_exec;
			}

			server = std::make_shared<FdRpcServer>(command_line, send[1], recv[0], pid);
			send[1] = -1;
			recv[0] = -1;

cleanup_exec:
			if (send[0] != -1) close(send[0]);
			if (send[1] != -1) close(send[1]);
			if (recv[0] != -1) close(recv[0]);
			if (recv[1] != -1) close(recv[1]);
			if (file_actions_p != NULL)
				posix_spawn_file_actions_destroy(file_actions_p);
#endif
		} else if (!path.empty()) {
#ifdef _WIN32
			std::wstring path_w = str2wstr(path);
			HANDLE h;

			h = CreateFileW(path_w.c_str(), GENERIC_READ|GENERIC_WRITE, /*dwShareMode=*/0, /*lpSecurityAttributes=*/NULL, /*dwCreationDisposition=*/OPEN_EXISTING, /*dwFlagsAndAttributes=*/0, /*hTemplateFile=*/NULL);
			if (h == INVALID_HANDLE_VALUE) {
				log_error("CreateFileW failed: %s\n", get_last_error_str().c_str());
				goto cleanup_path;
			}

			server = std::make_shared<HandleRpcServer>(path, h, h);

cleanup_path:
			;
#else
			struct sockaddr_un addr;
			addr.sun_family = AF_UNIX;
			strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path) - 1);

			int fd = socket(AF_UNIX, SOCK_STREAM, 0);
			if (fd == -1) {
				log_error("socket failed: %s\n", strerror(errno));
				goto cleanup_path;
			}

			if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
				log_error("connect failed: %s\n", strerror(errno));
				goto cleanup_path;
			}

			server = std::make_shared<FdRpcServer>(path, fd, fd);
			fd = -1;

cleanup_path:
			if (fd != -1) close(fd);
#endif
		}

		if (!server)
			log_cmd_error("Failed to connect to RPC frontend.\n");

		for (auto &module_name : server->get_module_names()) {
			log("Linking module `%s'.\n", module_name.c_str());
			RpcModule *module = new RpcModule;
			module->name = "$abstract\\" + module_name;
			module->server = server;
			design->add(module);
		}
	}
} RpcFrontend;

YOSYS_NAMESPACE_END
G5", 0, 25, 1), ("G10", 33, 20, 1), ("G11", 33, 21, 1), ("G12", 33, 24, 1), ("G13", 33, 23, 1), ("G14", 33, 22, 1), ("G15", 33, 20, 0), ("G16", 33, 19, 0), ( "H1", 0, 16, 0), ( "H2", 0, 18, 0), ( "H3", 0, 21, 1), ( "H4", 0, 19, 1), ( "H5", 0, 23, 1), ( "H6", 0, 20, 1), ("H11", 33, 16, 1), ("H12", 33, 19, 1), ("H13", 33, 16, 0), ("H14", 33, 17, 1), ("H16", 33, 17, 0), ( "J1", 0, 14, 0), ( "J2", 0, 14, 1), ( "J3", 0, 16, 1), ( "J4", 0, 18, 1), ( "J5", 0, 17, 1), ("J10", 33, 7, 1), ("J11", 33, 9, 1), ("J12", 33, 14, 1), ("J13", 33, 15, 0), ("J14", 33, 13, 1), ("J15", 33, 11, 1), ("J16", 33, 15, 1), ( "K1", 0, 13, 1), ( "K3", 0, 13, 0), ( "K4", 0, 11, 1), ( "K5", 0, 9, 1), ( "K9", 17, 0, 0), ("K11", 29, 0, 0), ("K12", 33, 6, 1), ("K13", 33, 10, 1), ("K14", 33, 11, 0), ("K15", 33, 12, 0), ("K16", 33, 13, 0), ( "L1", 0, 12, 0), ( "L3", 0, 10, 0), ( "L4", 0, 12, 1), ( "L5", 0, 6, 1), ( "L6", 0, 10, 1), ( "L7", 0, 8, 1), ( "L9", 13, 0, 0), ("L10", 19, 0, 1), ("L11", 26, 0, 1), ("L12", 33, 4, 1), ("L13", 33, 5, 1), ("L14", 33, 6, 0), ("L16", 33, 10, 0), ( "M1", 0, 11, 0), ( "M2", 0, 9, 0), ( "M3", 0, 7, 0), ( "M4", 0, 5, 0), ( "M5", 0, 4, 0), ( "M6", 0, 7, 1), ( "M7", 8, 0, 0), ( "M8", 10, 0, 0), ( "M9", 16, 0, 0), ("M11", 23, 0, 1), ("M12", 27, 0, 1), ("M13", 33, 3, 1), ("M14", 33, 4, 0), ("M15", 33, 8, 0), ("M16", 33, 7, 0), ( "N2", 0, 8, 0), ( "N3", 0, 6, 0), ( "N4", 0, 3, 0), ( "N5", 4, 0, 0), ( "N6", 2, 0, 0), ( "N7", 9, 0, 0), ( "N9", 15, 0, 0), ("N10", 20, 0, 1), ("N12", 26, 0, 0), ("N16", 33, 5, 0), ( "P1", 0, 5, 1), ( "P2", 0, 4, 1), ( "P4", 3, 0, 0), ( "P5", 5, 0, 0), ( "P6", 9, 0, 1), ( "P7", 14, 0, 1), ( "P8", 12, 0, 0), ( "P9", 17, 0, 1), ("P10", 20, 0, 0), ("P11", 30, 0, 1), ("P12", 30, 0, 0), ("P13", 29, 0, 1), ("P14", 33, 2, 0), ("P15", 33, 2, 1), ("P16", 33, 3, 0), ( "R1", 0, 3, 1), ( "R2", 3, 0, 1), ( "R3", 5, 0, 1), ( "R4", 7, 0, 1), ( "R5", 6, 0, 0), ( "R6", 11, 0, 1), ( "R9", 16, 0, 1), ("R10", 19, 0, 0), ("R11", 31, 0, 0), ("R12", 31, 0, 1), ("R14", 33, 1, 0), ("R15", 33, 1, 1), ("R16", 28, 0, 0), ( "T1", 2, 0, 1), ( "T2", 4, 0, 1), ( "T3", 6, 0, 1), ( "T5", 10, 0, 1), ( "T6", 12, 0, 1), ( "T7", 13, 0, 1), ( "T8", 14, 0, 0), ( "T9", 15, 0, 1), ("T10", 21, 0, 0), ("T11", 21, 0, 1), ("T13", 24, 0, 0), ("T14", 23, 0, 0), ("T15", 22, 0, 1), ("T16", 27, 0, 0), ], "384-qn32": [ ( "1", 0, 7, 0), ( "2", 0, 7, 1), ( "5", 0, 5, 1), ( "6", 0, 5, 0), ( "7", 0, 4, 0), ( "8", 0, 4, 1), ( "12", 5, 0, 0), ( "13", 5, 0, 1), ( "14", 6, 0, 1), ( "15", 6, 0, 0), ( "18", 7, 4, 0), ( "19", 7, 4, 1), ( "20", 7, 5, 0), ( "22", 7, 6, 0), ( "23", 7, 6, 1), ( "26", 6, 9, 0), ( "27", 5, 9, 0), ( "29", 4, 9, 0), ( "30", 3, 9, 1), ( "31", 2, 9, 0), ( "32", 2, 9, 1), ], "384-cm36": [ ( "A1", 0, 7, 0), ( "A2", 2, 9, 1), ( "A3", 3, 9, 1), ( "B1", 0, 7, 1), ( "B3", 4, 9, 0), ( "B4", 7, 5, 0), ( "B5", 7, 5, 1), ( "B6", 7, 6, 0), ( "C1", 0, 5, 0), ( "C2", 0, 5, 1), ( "C3", 2, 9, 0), ( "C5", 7, 4, 1), ( "C6", 7, 6, 1), ( "D1", 0, 4, 1), ( "D5", 6, 0, 1), ( "D6", 7, 4, 0), ( "E1", 0, 4, 0), ( "E2", 3, 0, 1), ( "E3", 4, 0, 0), ( "E4", 5, 0, 0), ( "E5", 6, 0, 0), ( "E6", 7, 3, 1), ( "F2", 3, 0, 0), ( "F3", 4, 0, 1), ( "F5", 5, 0, 1), ], "384-cm49": [ ( "A1", 0, 7, 1), ( "A2", 2, 9, 1), ( "A3", 3, 9, 0), ( "A4", 4, 9, 1), ( "A5", 5, 9, 0), ( "A6", 6, 9, 0), ( "A7", 6, 9, 1), ( "B1", 0, 7, 0), ( "B2", 0, 6, 0), ( "B3", 2, 9, 0), ( "B4", 4, 9, 0), ( "C1", 0, 5, 1), ( "C2", 0, 6, 1), ( "C4", 3, 9, 1), ( "C5", 7, 6, 1), ( "C6", 7, 5, 1), ( "C7", 7, 6, 0), ( "D1", 0, 4, 0), ( "D2", 0, 5, 0), ( "D3", 0, 2, 0), ( "D4", 5, 9, 1), ( "D6", 7, 4, 1), ( "D7", 7, 5, 0), ( "E2", 0, 4, 1), ( "E6", 6, 0, 1), ( "E7", 7, 4, 0), ( "F1", 0, 2, 1), ( "F2", 0, 1, 0), ( "F3", 3, 0, 1), ( "F4", 4, 0, 0), ( "F5", 5, 0, 0), ( "F6", 6, 0, 0), ( "F7", 7, 3, 1), ( "G1", 0, 1, 1), ( "G3", 3, 0, 0), ( "G4", 4, 0, 1), ( "G6", 5, 0, 1), ], "5k-sg48": [ ( "2", 8, 0, 0), ( "3", 9, 0, 1), ( "4", 9, 0, 0), ( "6", 13, 0, 1), ( "9", 15, 0, 0), ( "10", 16, 0, 0), ( "11", 17, 0, 0), ( "12", 18, 0, 0), ( "13", 19, 0, 0), ( "14", 23, 0, 0), ( "15", 24, 0, 0), ( "16", 24, 0, 1), ( "17", 23, 0, 1), ( "18", 22, 0, 1), ( "19", 21, 0, 1), ( "20", 19, 0, 1), ( "21", 18, 0, 1), ( "23", 19, 31, 0), ( "25", 19, 31, 1), ( "26", 18, 31, 0), ( "27", 18, 31, 1), ( "28", 17, 31, 0), ( "31", 16, 31, 1), ( "32", 16, 31, 0), ( "34", 13, 31, 1), ( "35", 12, 31, 1), ( "36", 9, 31, 1), ( "37", 13, 31, 0), ( "38", 8, 31, 1), ( "39", 4, 31, 0), ( "40", 5, 31, 0), ( "41", 6, 31, 0), ( "42", 8, 31, 0), ( "43", 9, 31, 0), ( "44", 6, 0, 1), ( "45", 7, 0, 1), ( "46", 5, 0, 0), ( "47", 6, 0, 0), ( "48", 7, 0, 0), ], "5k-uwg30": [ ( "A1", 19, 31, 1), ( "A2", 19, 31, 0), ( "A4", 12, 31, 0), ( "A5", 4, 31, 0), ( "B1", 19, 0, 0), ( "B3", 12, 31, 1), ( "B5", 5, 31, 0), ( "C1", 24, 0, 1), ( "C3", 12, 0, 0), ( "C5", 6, 31, 0), ( "D1", 24, 0, 0), ( "D3", 13, 0, 0), ( "D5", 6, 0, 0), ( "E1", 23, 0, 1), ( "E3", 13, 0, 1), ( "E4", 9, 0, 1), ( "E5", 5, 0, 0), ( "F1", 23, 0, 0), ( "F2", 19, 0, 1), ( "F4", 12, 0, 1), ( "F5", 6, 0, 1), ] } # This database contains the locations of configuration bits of the DSP tiles # The standard configuration is stored under the key "default". If it is necessary to # override it for a certain DSP on a certain device use the key "{device}_{x}_{y}" where # {x} and {y} are the location of the DSP0 tile of the DSP (NOT the tile the cbit is in). # x and y are relative to the DSP0 tile. dsp_config_db = { "default" : { "C_REG": (0, 0, "CBIT_0"), "A_REG": (0, 0, "CBIT_1"), "B_REG": (0, 0, "CBIT_2"), "D_REG": (0, 0, "CBIT_3"), "TOP_8x8_MULT_REG": (0, 0, "CBIT_4"), "BOT_8x8_MULT_REG": (0, 0, "CBIT_5"), "PIPELINE_16x16_MULT_REG1": (0, 0, "CBIT_6"), "PIPELINE_16x16_MULT_REG2": (0, 0, "CBIT_7"), "TOPOUTPUT_SELECT_0": (0, 1, "CBIT_0"), "TOPOUTPUT_SELECT_1": (0, 1, "CBIT_1"), "TOPADDSUB_LOWERINPUT_0": (0, 1, "CBIT_2"), "TOPADDSUB_LOWERINPUT_1": (0, 1, "CBIT_3"), "TOPADDSUB_UPPERINPUT": (0, 1, "CBIT_4"), "TOPADDSUB_CARRYSELECT_0": (0, 1, "CBIT_5"), "TOPADDSUB_CARRYSELECT_1": (0, 1, "CBIT_6"), "BOTOUTPUT_SELECT_0": (0, 1, "CBIT_7"), "BOTOUTPUT_SELECT_1": (0, 2, "CBIT_0"), "BOTADDSUB_LOWERINPUT_0": (0, 2, "CBIT_1"), "BOTADDSUB_LOWERINPUT_1": (0, 2, "CBIT_2"), "BOTADDSUB_UPPERINPUT": (0, 2, "CBIT_3"), "BOTADDSUB_CARRYSELECT_0": (0, 2, "CBIT_4"), "BOTADDSUB_CARRYSELECT_1": (0, 2, "CBIT_5"), "MODE_8x8": (0, 2, "CBIT_6"), "A_SIGNED": (0, 2, "CBIT_7"), "B_SIGNED": (0, 3, "CBIT_0") }, "5k_0_15": { "TOPOUTPUT_SELECT_1": (0, 4, "CBIT_3"), "TOPADDSUB_LOWERINPUT_0": (0, 4, "CBIT_4"), "TOPADDSUB_LOWERINPUT_1": (0, 4, "CBIT_5"), "TOPADDSUB_UPPERINPUT": (0, 4, "CBIT_6") } } # SPRAM data for UltraPlus devices, use icefuzz/tests/fuzz_spram.py # to generate this spram_db = { "5k" : { (0, 0, 1): { "ADDRESS_0": (0, 2, "lutff_0/in_1"), "ADDRESS_10": (0, 2, "lutff_2/in_0"), "ADDRESS_11": (0, 2, "lutff_3/in_0"), "ADDRESS_12": (0, 2, "lutff_4/in_0"), "ADDRESS_13": (0, 2, "lutff_5/in_0"), "ADDRESS_1": (0, 2, "lutff_1/in_1"), "ADDRESS_2": (0, 2, "lutff_2/in_1"), "ADDRESS_3": (0, 2, "lutff_3/in_1"), "ADDRESS_4": (0, 2, "lutff_4/in_1"), "ADDRESS_5": (0, 2, "lutff_5/in_1"), "ADDRESS_6": (0, 2, "lutff_6/in_1"), "ADDRESS_7": (0, 2, "lutff_7/in_1"), "ADDRESS_8": (0, 2, "lutff_0/in_0"), "ADDRESS_9": (0, 2, "lutff_1/in_0"), "CHIPSELECT": (0, 3, "lutff_6/in_1"), "CLOCK": (0, 1, "clk"), "DATAIN_0": (0, 1, "lutff_0/in_3"), "DATAIN_10": (0, 1, "lutff_2/in_1"), "DATAIN_11": (0, 1, "lutff_3/in_1"), "DATAIN_12": (0, 1, "lutff_4/in_1"), "DATAIN_13": (0, 1, "lutff_5/in_1"), "DATAIN_14": (0, 1, "lutff_6/in_1"), "DATAIN_15": (0, 1, "lutff_7/in_1"), "DATAIN_1": (0, 1, "lutff_1/in_3"), "DATAIN_2": (0, 1, "lutff_2/in_3"), "DATAIN_3": (0, 1, "lutff_3/in_3"), "DATAIN_4": (0, 1, "lutff_4/in_3"), "DATAIN_5": (0, 1, "lutff_5/in_3"), "DATAIN_6": (0, 1, "lutff_6/in_3"), "DATAIN_7": (0, 1, "lutff_7/in_3"), "DATAIN_8": (0, 1, "lutff_0/in_1"), "DATAIN_9": (0, 1, "lutff_1/in_1"), "DATAOUT_0": (0, 1, "slf_op_0"), "DATAOUT_10": (0, 2, "slf_op_2"), "DATAOUT_11": (0, 2, "slf_op_3"), "DATAOUT_12": (0, 2, "slf_op_4"), "DATAOUT_13": (0, 2, "slf_op_5"), "DATAOUT_14": (0, 2, "slf_op_6"), "DATAOUT_15": (0, 2, "slf_op_7"), "DATAOUT_1": (0, 1, "slf_op_1"), "DATAOUT_2": (0, 1, "slf_op_2"), "DATAOUT_3": (0, 1, "slf_op_3"), "DATAOUT_4": (0, 1, "slf_op_4"), "DATAOUT_5": (0, 1, "slf_op_5"), "DATAOUT_6": (0, 1, "slf_op_6"), "DATAOUT_7": (0, 1, "slf_op_7"), "DATAOUT_8": (0, 2, "slf_op_0"), "DATAOUT_9": (0, 2, "slf_op_1"), "MASKWREN_0": (0, 3, "lutff_0/in_0"), "MASKWREN_1": (0, 3, "lutff_1/in_0"), "MASKWREN_2": (0, 3, "lutff_2/in_0"), "MASKWREN_3": (0, 3, "lutff_3/in_0"), "POWEROFF": (0, 4, "lutff_4/in_3"), "SLEEP": (0, 4, "lutff_2/in_3"), "SPRAM_EN": (0, 1, "CBIT_0"), "STANDBY": (0, 4, "lutff_0/in_3"), "WREN": (0, 3, "lutff_4/in_1"), }, (0, 0, 2): { "ADDRESS_0": (0, 2, "lutff_6/in_0"), "ADDRESS_10": (0, 3, "lutff_0/in_1"), "ADDRESS_11": (0, 3, "lutff_1/in_1"), "ADDRESS_12": (0, 3, "lutff_2/in_1"), "ADDRESS_13": (0, 3, "lutff_3/in_1"), "ADDRESS_1": (0, 2, "lutff_7/in_0"), "ADDRESS_2": (0, 3, "lutff_0/in_3"), "ADDRESS_3": (0, 3, "lutff_1/in_3"), "ADDRESS_4": (0, 3, "lutff_2/in_3"), "ADDRESS_5": (0, 3, "lutff_3/in_3"), "ADDRESS_6": (0, 3, "lutff_4/in_3"), "ADDRESS_7": (0, 3, "lutff_5/in_3"), "ADDRESS_8": (0, 3, "lutff_6/in_3"), "ADDRESS_9": (0, 3, "lutff_7/in_3"), "CHIPSELECT": (0, 3, "lutff_7/in_1"), "CLOCK": (0, 2, "clk"), "DATAIN_0": (0, 1, "lutff_0/in_0"), "DATAIN_10": (0, 2, "lutff_2/in_3"), "DATAIN_11": (0, 2, "lutff_3/in_3"), "DATAIN_12": (0, 2, "lutff_4/in_3"), "DATAIN_13": (0, 2, "lutff_5/in_3"), "DATAIN_14": (0, 2, "lutff_6/in_3"), "DATAIN_15": (0, 2, "lutff_7/in_3"), "DATAIN_1": (0, 1, "lutff_1/in_0"), "DATAIN_2": (0, 1, "lutff_2/in_0"), "DATAIN_3": (0, 1, "lutff_3/in_0"), "DATAIN_4": (0, 1, "lutff_4/in_0"), "DATAIN_5": (0, 1, "lutff_5/in_0"), "DATAIN_6": (0, 1, "lutff_6/in_0"), "DATAIN_7": (0, 1, "lutff_7/in_0"), "DATAIN_8": (0, 2, "lutff_0/in_3"), "DATAIN_9": (0, 2, "lutff_1/in_3"), "DATAOUT_0": (0, 3, "slf_op_0"), "DATAOUT_10": (0, 4, "slf_op_2"), "DATAOUT_11": (0, 4, "slf_op_3"), "DATAOUT_12": (0, 4, "slf_op_4"), "DATAOUT_13": (0, 4, "slf_op_5"), "DATAOUT_14": (0, 4, "slf_op_6"), "DATAOUT_15": (0, 4, "slf_op_7"), "DATAOUT_1": (0, 3, "slf_op_1"), "DATAOUT_2": (0, 3, "slf_op_2"), "DATAOUT_3": (0, 3, "slf_op_3"), "DATAOUT_4": (0, 3, "slf_op_4"), "DATAOUT_5": (0, 3, "slf_op_5"), "DATAOUT_6": (0, 3, "slf_op_6"), "DATAOUT_7": (0, 3, "slf_op_7"), "DATAOUT_8": (0, 4, "slf_op_0"), "DATAOUT_9": (0, 4, "slf_op_1"), "MASKWREN_0": (0, 3, "lutff_4/in_0"), "MASKWREN_1": (0, 3, "lutff_5/in_0"), "MASKWREN_2": (0, 3, "lutff_6/in_0"), "MASKWREN_3": (0, 3, "lutff_7/in_0"), "POWEROFF": (0, 4, "lutff_5/in_3"), "SLEEP": (0, 4, "lutff_3/in_3"), "SPRAM_EN": (0, 1, "CBIT_1"), "STANDBY": (0, 4, "lutff_1/in_3"), "WREN": (0, 3, "lutff_5/in_1"), }, (25, 0, 3): { "ADDRESS_0": (25, 2, "lutff_0/in_1"), "ADDRESS_10": (25, 2, "lutff_2/in_0"), "ADDRESS_11": (25, 2, "lutff_3/in_0"), "ADDRESS_12": (25, 2, "lutff_4/in_0"), "ADDRESS_13": (25, 2, "lutff_5/in_0"), "ADDRESS_1": (25, 2, "lutff_1/in_1"), "ADDRESS_2": (25, 2, "lutff_2/in_1"), "ADDRESS_3": (25, 2, "lutff_3/in_1"), "ADDRESS_4": (25, 2, "lutff_4/in_1"), "ADDRESS_5": (25, 2, "lutff_5/in_1"), "ADDRESS_6": (25, 2, "lutff_6/in_1"), "ADDRESS_7": (25, 2, "lutff_7/in_1"), "ADDRESS_8": (25, 2, "lutff_0/in_0"), "ADDRESS_9": (25, 2, "lutff_1/in_0"), "CHIPSELECT": (25, 3, "lutff_6/in_1"), "CLOCK": (25, 1, "clk"), "DATAIN_0": (25, 1, "lutff_0/in_3"), "DATAIN_10": (25, 1, "lutff_2/in_1"), "DATAIN_11": (25, 1, "lutff_3/in_1"), "DATAIN_12": (25, 1, "lutff_4/in_1"), "DATAIN_13": (25, 1, "lutff_5/in_1"), "DATAIN_14": (25, 1, "lutff_6/in_1"), "DATAIN_15": (25, 1, "lutff_7/in_1"), "DATAIN_1": (25, 1, "lutff_1/in_3"), "DATAIN_2": (25, 1, "lutff_2/in_3"), "DATAIN_3": (25, 1, "lutff_3/in_3"), "DATAIN_4": (25, 1, "lutff_4/in_3"), "DATAIN_5": (25, 1, "lutff_5/in_3"), "DATAIN_6": (25, 1, "lutff_6/in_3"), "DATAIN_7": (25, 1, "lutff_7/in_3"), "DATAIN_8": (25, 1, "lutff_0/in_1"), "DATAIN_9": (25, 1, "lutff_1/in_1"), "DATAOUT_0": (25, 1, "slf_op_0"), "DATAOUT_10": (25, 2, "slf_op_2"), "DATAOUT_11": (25, 2, "slf_op_3"), "DATAOUT_12": (25, 2, "slf_op_4"), "DATAOUT_13": (25, 2, "slf_op_5"), "DATAOUT_14": (25, 2, "slf_op_6"), "DATAOUT_15": (25, 2, "slf_op_7"), "DATAOUT_1": (25, 1, "slf_op_1"), "DATAOUT_2": (25, 1, "slf_op_2"), "DATAOUT_3": (25, 1, "slf_op_3"), "DATAOUT_4": (25, 1, "slf_op_4"), "DATAOUT_5": (25, 1, "slf_op_5"), "DATAOUT_6": (25, 1, "slf_op_6"), "DATAOUT_7": (25, 1, "slf_op_7"), "DATAOUT_8": (25, 2, "slf_op_0"), "DATAOUT_9": (25, 2, "slf_op_1"), "MASKWREN_0": (25, 3, "lutff_0/in_0"), "MASKWREN_1": (25, 3, "lutff_1/in_0"), "MASKWREN_2": (25, 3, "lutff_2/in_0"), "MASKWREN_3": (25, 3, "lutff_3/in_0"), "POWEROFF": (25, 4, "lutff_4/in_3"), "SLEEP": (25, 4, "lutff_2/in_3"), "SPRAM_EN": (25, 1, "CBIT_0"), "STANDBY": (25, 4, "lutff_0/in_3"), "WREN": (25, 3, "lutff_4/in_1"), }, (25, 0, 4): { "ADDRESS_0": (25, 2, "lutff_6/in_0"), "ADDRESS_10": (25, 3, "lutff_0/in_1"), "ADDRESS_11": (25, 3, "lutff_1/in_1"), "ADDRESS_12": (25, 3, "lutff_2/in_1"), "ADDRESS_13": (25, 3, "lutff_3/in_1"), "ADDRESS_1": (25, 2, "lutff_7/in_0"), "ADDRESS_2": (25, 3, "lutff_0/in_3"), "ADDRESS_3": (25, 3, "lutff_1/in_3"), "ADDRESS_4": (25, 3, "lutff_2/in_3"), "ADDRESS_5": (25, 3, "lutff_3/in_3"), "ADDRESS_6": (25, 3, "lutff_4/in_3"), "ADDRESS_7": (25, 3, "lutff_5/in_3"), "ADDRESS_8": (25, 3, "lutff_6/in_3"), "ADDRESS_9": (25, 3, "lutff_7/in_3"), "CHIPSELECT": (25, 3, "lutff_7/in_1"), "CLOCK": (25, 2, "clk"), "DATAIN_0": (25, 1, "lutff_0/in_0"), "DATAIN_10": (25, 2, "lutff_2/in_3"), "DATAIN_11": (25, 2, "lutff_3/in_3"), "DATAIN_12": (25, 2, "lutff_4/in_3"), "DATAIN_13": (25, 2, "lutff_5/in_3"), "DATAIN_14": (25, 2, "lutff_6/in_3"), "DATAIN_15": (25, 2, "lutff_7/in_3"), "DATAIN_1": (25, 1, "lutff_1/in_0"), "DATAIN_2": (25, 1, "lutff_2/in_0"), "DATAIN_3": (25, 1, "lutff_3/in_0"), "DATAIN_4": (25, 1, "lutff_4/in_0"), "DATAIN_5": (25, 1, "lutff_5/in_0"), "DATAIN_6": (25, 1, "lutff_6/in_0"), "DATAIN_7": (25, 1, "lutff_7/in_0"), "DATAIN_8": (25, 2, "lutff_0/in_3"), "DATAIN_9": (25, 2, "lutff_1/in_3"), "DATAOUT_0": (25, 3, "slf_op_0"), "DATAOUT_10": (25, 4, "slf_op_2"), "DATAOUT_11": (25, 4, "slf_op_3"), "DATAOUT_12": (25, 4, "slf_op_4"), "DATAOUT_13": (25, 4, "slf_op_5"), "DATAOUT_14": (25, 4, "slf_op_6"), "DATAOUT_15": (25, 4, "slf_op_7"), "DATAOUT_1": (25, 3, "slf_op_1"), "DATAOUT_2": (25, 3, "slf_op_2"), "DATAOUT_3": (25, 3, "slf_op_3"), "DATAOUT_4": (25, 3, "slf_op_4"), "DATAOUT_5": (25, 3, "slf_op_5"), "DATAOUT_6": (25, 3, "slf_op_6"), "DATAOUT_7": (25, 3, "slf_op_7"), "DATAOUT_8": (25, 4, "slf_op_0"), "DATAOUT_9": (25, 4, "slf_op_1"), "MASKWREN_0": (25, 3, "lutff_4/in_0"), "MASKWREN_1": (25, 3, "lutff_5/in_0"), "MASKWREN_2": (25, 3, "lutff_6/in_0"), "MASKWREN_3": (25, 3, "lutff_7/in_0"), "POWEROFF": (25, 4, "lutff_5/in_3"), "SLEEP": (25, 4, "lutff_3/in_3"), "SPRAM_EN": (25, 1, "CBIT_1"), "STANDBY": (25, 4, "lutff_1/in_3"), "WREN": (25, 3, "lutff_5/in_1"), } } } # This contains the data for extra cells not included # in any previous databases extra_cells_db = { "5k" : { ("HFOSC", (0, 31, 1)) : { "CLKHFPU": (0, 29, "lutff_0/in_1"), "CLKHFEN": (0, 29, "lutff_7/in_3"), "CLKHF": (0, 29, "glb_netwk_4"), "CLKHF_FABRIC": (0, 28, "slf_op_7"), "TRIM0": (25, 28, "lutff_4/in_0"), "TRIM1": (25, 28, "lutff_5/in_0"), "TRIM2": (25, 28, "lutff_6/in_0"), "TRIM3": (25, 28, "lutff_7/in_0"), "TRIM4": (25, 29, "lutff_0/in_3"), "TRIM5": (25, 29, "lutff_1/in_3"), "TRIM6": (25, 29, "lutff_2/in_3"), "TRIM7": (25, 29, "lutff_3/in_3"), "TRIM8": (25, 29, "lutff_4/in_3"), "TRIM9": (25, 29, "lutff_5/in_3"), "CLKHF_DIV_1": (0, 16, "CBIT_4"), "CLKHF_DIV_0": (0, 16, "CBIT_3"), "TRIM_EN": (0, 16, "CBIT_5") }, ("LFOSC", (25, 31, 1)) : { "CLKLFPU": (25, 29, "lutff_0/in_1"), "CLKLFEN": (25, 29, "lutff_7/in_3"), "CLKLF": (25, 29, "glb_netwk_5"), "CLKLF_FABRIC": (25, 29, "slf_op_0") }, ("RGBA_DRV", (0, 30, 0)) : { "CURREN": (25, 29, "lutff_6/in_3"), "RGBLEDEN": (0, 30, "lutff_1/in_1"), "RGB0PWM": (0, 30, "lutff_2/in_1"), "RGB1PWM": (0, 30, "lutff_3/in_1"), "RGB2PWM": (0, 30, "lutff_4/in_1"), "RGBA_DRV_EN": (0, 28, "CBIT_5"), "RGB0_CURRENT_0": (0, 28, "CBIT_6"), "RGB0_CURRENT_1": (0, 28, "CBIT_7"), "RGB0_CURRENT_2": (0, 29, "CBIT_0"), "RGB0_CURRENT_3": (0, 29, "CBIT_1"), "RGB0_CURRENT_4": (0, 29, "CBIT_2"), "RGB0_CURRENT_5": (0, 29, "CBIT_3"), "RGB1_CURRENT_0": (0, 29, "CBIT_4"), "RGB1_CURRENT_1": (0, 29, "CBIT_5"), "RGB1_CURRENT_2": (0, 29, "CBIT_6"), "RGB1_CURRENT_3": (0, 29, "CBIT_7"), "RGB1_CURRENT_4": (0, 30, "CBIT_0"), "RGB1_CURRENT_5": (0, 30, "CBIT_1"), "RGB2_CURRENT_0": (0, 30, "CBIT_2"), "RGB2_CURRENT_1": (0, 30, "CBIT_3"), "RGB2_CURRENT_2": (0, 30, "CBIT_4"), "RGB2_CURRENT_3": (0, 30, "CBIT_5"), "RGB2_CURRENT_4": (0, 30, "CBIT_6"), "RGB2_CURRENT_5": (0, 30, "CBIT_7"), "CURRENT_MODE": (0, 28, "CBIT_4"), "RGB0": (4, 31, 0), "RGB1": (5, 31, 0), "RGB2": (6, 31, 0), }, ("I2C", (0, 31, 0)): { "I2CIRQ": (0, 30, "slf_op_7"), "I2CWKUP": (0, 29, "slf_op_5"), "I2C_ENABLE_0": (13, 31, "cbit2usealt_in_0"), "I2C_ENABLE_1": (12, 31, "cbit2usealt_in_1"), "SBACKO": (0, 30, "slf_op_6"), "SBADRI0": (0, 30, "lutff_1/in_0"), "SBADRI1": (0, 30, "lutff_2/in_0"), "SBADRI2": (0, 30, "lutff_3/in_0"), "SBADRI3": (0, 30, "lutff_4/in_0"), "SBADRI4": (0, 30, "lutff_5/in_0"), "SBADRI5": (0, 30, "lutff_6/in_0"), "SBADRI6": (0, 30, "lutff_7/in_0"), "SBADRI7": (0, 29, "lutff_2/in_0"), "SBCLKI": (0, 30, "clk"), "SBDATI0": (0, 29, "lutff_5/in_0"), "SBDATI1": (0, 29, "lutff_6/in_0"), "SBDATI2": (0, 29, "lutff_7/in_0"), "SBDATI3": (0, 30, "lutff_0/in_3"), "SBDATI4": (0, 30, "lutff_5/in_1"), "SBDATI5": (0, 30, "lutff_6/in_1"), "SBDATI6": (0, 30, "lutff_7/in_1"), "SBDATI7": (0, 30, "lutff_0/in_0"), "SBDATO0": (0, 29, "slf_op_6"), "SBDATO1": (0, 29, "slf_op_7"), "SBDATO2": (0, 30, "slf_op_0"), "SBDATO3": (0, 30, "slf_op_1"), "SBDATO4": (0, 30, "slf_op_2"), "SBDATO5": (0, 30, "slf_op_3"), "SBDATO6": (0, 30, "slf_op_4"), "SBDATO7": (0, 30, "slf_op_5"), "SBRWI": (0, 29, "lutff_4/in_0"), "SBSTBI": (0, 29, "lutff_3/in_0"), "SCLI": (0, 29, "lutff_2/in_1"), "SCLO": (0, 29, "slf_op_3"), "SCLOE": (0, 29, "slf_op_4"), "SDAI": (0, 29, "lutff_1/in_1"), "SDAO": (0, 29, "slf_op_1"), "SDAOE": (0, 29, "slf_op_2"), "SDA_INPUT_DELAYED": (12, 31, "SDA_input_delay"), "SDA_OUTPUT_DELAYED": (12, 31, "SDA_output_delay"), }, ("I2C", (25, 31, 0)): { "I2CIRQ": (25, 30, "slf_op_7"), "I2CWKUP": (25, 29, "slf_op_5"), "I2C_ENABLE_0": (19, 31, "cbit2usealt_in_0"), "I2C_ENABLE_1": (19, 31, "cbit2usealt_in_1"), "SBACKO": (25, 30, "slf_op_6"), "SBADRI0": (25, 30, "lutff_1/in_0"), "SBADRI1": (25, 30, "lutff_2/in_0"), "SBADRI2": (25, 30, "lutff_3/in_0"), "SBADRI3": (25, 30, "lutff_4/in_0"), "SBADRI4": (25, 30, "lutff_5/in_0"), "SBADRI5": (25, 30, "lutff_6/in_0"), "SBADRI6": (25, 30, "lutff_7/in_0"), "SBADRI7": (25, 29, "lutff_2/in_0"), "SBCLKI": (25, 30, "clk"), "SBDATI0": (25, 29, "lutff_5/in_0"), "SBDATI1": (25, 29, "lutff_6/in_0"), "SBDATI2": (25, 29, "lutff_7/in_0"), "SBDATI3": (25, 30, "lutff_0/in_3"), "SBDATI4": (25, 30, "lutff_5/in_1"), "SBDATI5": (25, 30, "lutff_6/in_1"), "SBDATI6": (25, 30, "lutff_7/in_1"), "SBDATI7": (25, 30, "lutff_0/in_0"), "SBDATO0": (25, 29, "slf_op_6"), "SBDATO1": (25, 29, "slf_op_7"), "SBDATO2": (25, 30, "slf_op_0"), "SBDATO3": (25, 30, "slf_op_1"), "SBDATO4": (25, 30, "slf_op_2"), "SBDATO5": (25, 30, "slf_op_3"), "SBDATO6": (25, 30, "slf_op_4"), "SBDATO7": (25, 30, "slf_op_5"), "SBRWI": (25, 29, "lutff_4/in_0"), "SBSTBI": (25, 29, "lutff_3/in_0"), "SCLI": (25, 29, "lutff_2/in_1"), "SCLO": (25, 29, "slf_op_3"), "SCLOE": (25, 29, "slf_op_4"), "SDAI": (25, 29, "lutff_1/in_1"), "SDAO": (25, 29, "slf_op_1"), "SDAOE": (25, 29, "slf_op_2"), "SDA_INPUT_DELAYED": (19, 31, "SDA_input_delay"), "SDA_OUTPUT_DELAYED": (19, 31, "SDA_output_delay"), }, ("SPI", (0, 0, 0)): { "MCSNO0": (0, 21, "slf_op_2"), "MCSNO1": (0, 21, "slf_op_4"), "MCSNO2": (0, 21, "slf_op_7"), "MCSNO3": (0, 22, "slf_op_1"), "MCSNOE0": (0, 21, "slf_op_3"), "MCSNOE1": (0, 21, "slf_op_5"), "MCSNOE2": (0, 22, "slf_op_0"), "MCSNOE3": (0, 22, "slf_op_2"), "MI": (0, 22, "lutff_0/in_1"), "MO": (0, 20, "slf_op_6"), "MOE": (0, 20, "slf_op_7"), "SBACKO": (0, 20, "slf_op_1"), "SBADRI0": (0, 19, "lutff_1/in_1"), "SBADRI1": (0, 19, "lutff_2/in_1"), "SBADRI2": (0, 20, "lutff_0/in_3"), "SBADRI3": (0, 20, "lutff_1/in_3"), "SBADRI4": (0, 20, "lutff_2/in_3"), "SBADRI5": (0, 20, "lutff_3/in_3"), "SBADRI6": (0, 20, "lutff_4/in_3"), "SBADRI7": (0, 20, "lutff_5/in_3"), "SBCLKI": (0, 20, "clk"), "SBDATI0": (0, 19, "lutff_1/in_3"), "SBDATI1": (0, 19, "lutff_2/in_3"), "SBDATI2": (0, 19, "lutff_3/in_3"), "SBDATI3": (0, 19, "lutff_4/in_3"), "SBDATI4": (0, 19, "lutff_5/in_3"), "SBDATI5": (0, 19, "lutff_6/in_3"), "SBDATI6": (0, 19, "lutff_7/in_3"), "SBDATI7": (0, 19, "lutff_0/in_1"), "SBDATO0": (0, 19, "slf_op_1"), "SBDATO1": (0, 19, "slf_op_2"), "SBDATO2": (0, 19, "slf_op_3"), "SBDATO3": (0, 19, "slf_op_4"), "SBDATO4": (0, 19, "slf_op_5"), "SBDATO5": (0, 19, "slf_op_6"), "SBDATO6": (0, 19, "slf_op_7"), "SBDATO7": (0, 20, "slf_op_0"), "SBRWI": (0, 19, "lutff_0/in_3"), "SBSTBI": (0, 20, "lutff_6/in_3"), "SCKI": (0, 22, "lutff_1/in_1"), "SCKO": (0, 21, "slf_op_0"), "SCKOE": (0, 21, "slf_op_1"), "SCSNI": (0, 22, "lutff_2/in_1"), "SI": (0, 22, "lutff_7/in_3"), "SO": (0, 20, "slf_op_4"), "SOE": (0, 20, "slf_op_5"), "SPIIRQ": (0, 20, "slf_op_2"), "SPIWKUP": (0, 20, "slf_op_3"), "SPI_ENABLE_0": (7, 0, "cbit2usealt_in_0"), "SPI_ENABLE_1": (7, 0, "cbit2usealt_in_1"), "SPI_ENABLE_2": (6, 0, "cbit2usealt_in_0"), "SPI_ENABLE_3": (6, 0, "cbit2usealt_in_1"), }, ("SPI", (25, 0, 1)): { "MCSNO0": (25, 21, "slf_op_2"), "MCSNO1": (25, 21, "slf_op_4"), "MCSNO2": (25, 21, "slf_op_7"), "MCSNO3": (25, 22, "slf_op_1"), "MCSNOE0": (25, 21, "slf_op_3"), "MCSNOE1": (25, 21, "slf_op_5"), "MCSNOE2": (25, 22, "slf_op_0"), "MCSNOE3": (25, 22, "slf_op_2"), "MI": (25, 22, "lutff_0/in_1"), "MO": (25, 20, "slf_op_6"), "MOE": (25, 20, "slf_op_7"), "SBACKO": (25, 20, "slf_op_1"), "SBADRI0": (25, 19, "lutff_1/in_1"), "SBADRI1": (25, 19, "lutff_2/in_1"), "SBADRI2": (25, 20, "lutff_0/in_3"), "SBADRI3": (25, 20, "lutff_1/in_3"), "SBADRI4": (25, 20, "lutff_2/in_3"), "SBADRI5": (25, 20, "lutff_3/in_3"), "SBADRI6": (25, 20, "lutff_4/in_3"), "SBADRI7": (25, 20, "lutff_5/in_3"), "SBCLKI": (25, 20, "clk"), "SBDATI0": (25, 19, "lutff_1/in_3"), "SBDATI1": (25, 19, "lutff_2/in_3"), "SBDATI2": (25, 19, "lutff_3/in_3"), "SBDATI3": (25, 19, "lutff_4/in_3"), "SBDATI4": (25, 19, "lutff_5/in_3"), "SBDATI5": (25, 19, "lutff_6/in_3"), "SBDATI6": (25, 19, "lutff_7/in_3"), "SBDATI7": (25, 19, "lutff_0/in_1"), "SBDATO0": (25, 19, "slf_op_1"), "SBDATO1": (25, 19, "slf_op_2"), "SBDATO2": (25, 19, "slf_op_3"), "SBDATO3": (25, 19, "slf_op_4"), "SBDATO4": (25, 19, "slf_op_5"), "SBDATO5": (25, 19, "slf_op_6"), "SBDATO6": (25, 19, "slf_op_7"), "SBDATO7": (25, 20, "slf_op_0"), "SBRWI": (25, 19, "lutff_0/in_3"), "SBSTBI": (25, 20, "lutff_6/in_3"), "SCKI": (25, 22, "lutff_1/in_1"), "SCKO": (25, 21, "slf_op_0"), "SCKOE": (25, 21, "slf_op_1"), "SCSNI": (25, 22, "lutff_2/in_1"), "SI": (25, 22, "lutff_7/in_3"), "SO": (25, 20, "slf_op_4"), "SOE": (25, 20, "slf_op_5"), "SPIIRQ": (25, 20, "slf_op_2"), "SPIWKUP": (25, 20, "slf_op_3"), "SPI_ENABLE_0": (23, 0, "cbit2usealt_in_0"), "SPI_ENABLE_1": (24, 0, "cbit2usealt_in_0"), "SPI_ENABLE_2": (23, 0, "cbit2usealt_in_1"), "SPI_ENABLE_3": (24, 0, "cbit2usealt_in_1"), }, ("LEDDA_IP", (0, 31, 2)): { "LEDDADDR0": (0, 28, "lutff_4/in_0"), "LEDDADDR1": (0, 28, "lutff_5/in_0"), "LEDDADDR2": (0, 28, "lutff_6/in_0"), "LEDDADDR3": (0, 28, "lutff_7/in_0"), "LEDDCLK": (0, 29, "clk"), "LEDDCS": (0, 28, "lutff_2/in_0"), "LEDDDAT0": (0, 28, "lutff_2/in_1"), "LEDDDAT1": (0, 28, "lutff_3/in_1"), "LEDDDAT2": (0, 28, "lutff_4/in_1"), "LEDDDAT3": (0, 28, "lutff_5/in_1"), "LEDDDAT4": (0, 28, "lutff_6/in_1"), "LEDDDAT5": (0, 28, "lutff_7/in_1"), "LEDDDAT6": (0, 28, "lutff_0/in_0"), "LEDDDAT7": (0, 28, "lutff_1/in_0"), "LEDDDEN": (0, 28, "lutff_1/in_1"), "LEDDEXE": (0, 28, "lutff_0/in_1"), "LEDDON": (0, 29, "slf_op_0"), "PWMOUT0": (0, 28, "slf_op_4"), "PWMOUT1": (0, 28, "slf_op_5"), "PWMOUT2": (0, 28, "slf_op_6"), }, ("IO_I3C", (25, 27, 0)): { "PU_ENB": (25, 27, "lutff_6/in_0"), "WEAK_PU_ENB": (25, 27, "lutff_4/in_0"), "PACKAGE_PIN": (19, 31, 0) }, ("IO_I3C", (25, 27, 1)): { "PU_ENB": (25, 27, "lutff_7/in_0"), "WEAK_PU_ENB": (25, 27, "lutff_5/in_0"), "PACKAGE_PIN": (19, 31, 1) } } } iotile_full_db = parse_db(iceboxdb.database_io_txt) logictile_db = parse_db(iceboxdb.database_logic_txt, "1k") logictile_5k_db = parse_db(iceboxdb.database_logic_txt, "5k") logictile_8k_db = parse_db(iceboxdb.database_logic_txt, "8k") logictile_384_db = parse_db(iceboxdb.database_logic_txt, "384") rambtile_db = parse_db(iceboxdb.database_ramb_txt, "1k") ramttile_db = parse_db(iceboxdb.database_ramt_txt, "1k") rambtile_8k_db = parse_db(iceboxdb.database_ramb_8k_txt, "8k") ramttile_8k_db = parse_db(iceboxdb.database_ramt_8k_txt, "8k") ipcon_5k_db = parse_db(iceboxdb.database_ipcon_5k_txt, "5k") dsp0_5k_db = parse_db(iceboxdb.database_dsp0_5k_txt, "5k") dsp1_5k_db = parse_db(iceboxdb.database_dsp1_5k_txt, "5k") #This bit doesn't exist in DB because icecube won't ever set it, #but it exists dsp1_5k_db.append([["B4[7]"], "IpConfig", "CBIT_5"]) dsp2_5k_db = parse_db(iceboxdb.database_dsp2_5k_txt, "5k") dsp3_5k_db = parse_db(iceboxdb.database_dsp3_5k_txt, "5k") #Add missing LC_ bits to DSP and IPCon databases for db_to_fix in [ipcon_5k_db, dsp0_5k_db, dsp1_5k_db, dsp2_5k_db, dsp3_5k_db]: for entry in db_to_fix: if len(entry) >= 2 and entry[1].startswith("LC_"): for lentry in logictile_5k_db: if len(lentry) >= 2 and lentry[1] == entry[1]: entry[0] = lentry[0] iotile_l_db = list() iotile_r_db = list() iotile_t_db = list() iotile_b_db = list() for entry in iotile_full_db: if entry[1] == "buffer" and entry[2].startswith("IO_L."): new_entry = entry[:] new_entry[2] = new_entry[2][5:] iotile_l_db.append(new_entry) elif entry[1] == "buffer" and entry[2].startswith("IO_R."): new_entry = entry[:] new_entry[2] = new_entry[2][5:] iotile_r_db.append(new_entry) elif entry[1] == "buffer" and entry[2].startswith("IO_T."): new_entry = entry[:] new_entry[2] = new_entry[2][5:] iotile_t_db.append(new_entry) elif entry[1] == "buffer" and entry[2].startswith("IO_B."): new_entry = entry[:] new_entry[2] = new_entry[2][5:] iotile_b_db.append(new_entry) else: iotile_l_db.append(entry) iotile_r_db.append(entry) iotile_t_db.append(entry) iotile_b_db.append(entry) logictile_db.append([["B1[49]"], "buffer", "carry_in", "carry_in_mux"]) logictile_db.append([["B1[50]"], "CarryInSet"]) logictile_5k_db.append([["B1[49]"], "buffer", "carry_in", "carry_in_mux"]) logictile_5k_db.append([["B1[50]"], "CarryInSet"]) logictile_8k_db.append([["B1[49]"], "buffer", "carry_in", "carry_in_mux"]) logictile_8k_db.append([["B1[50]"], "CarryInSet"]) logictile_384_db.append([["B1[49]"], "buffer", "carry_in", "carry_in_mux"]) logictile_384_db.append([["B1[50]"], "CarryInSet"]) # The 5k series has a couple of extra IO configuration bits. Add them in to a copy of the db here iotile_t_5k_db = list(iotile_t_db) iotile_t_5k_db.append([["B14[15]"], "IoCtrl", "padeb_test_1"]) iotile_t_5k_db.append([["B15[14]"], "IoCtrl", "padeb_test_0"]) iotile_t_5k_db.append([["B7[10]"], "IoCtrl", "cf_bit_32"]) iotile_t_5k_db.append([["B6[10]"], "IoCtrl", "cf_bit_33"]) iotile_t_5k_db.append([["B7[15]"], "IoCtrl", "cf_bit_34"]) iotile_t_5k_db.append([["B6[15]"], "IoCtrl", "cf_bit_35"]) iotile_t_5k_db.append([["B13[10]"], "IoCtrl", "cf_bit_36"]) iotile_t_5k_db.append([["B12[10]"], "IoCtrl", "cf_bit_37"]) iotile_t_5k_db.append([["B13[15]"], "IoCtrl", "cf_bit_38"]) iotile_t_5k_db.append([["B12[15]"], "IoCtrl", "cf_bit_39"]) iotile_t_5k_db.append([["B10[3]"], "IpConfig", "cbit2usealt_in_0"]) iotile_t_5k_db.append([["B12[2]"], "IpConfig", "cbit2usealt_in_1"]) iotile_t_5k_db.append([["B12[3]"], "IpConfig", "SDA_input_delay"]) iotile_t_5k_db.append([["B15[3]"], "IpConfig", "SDA_output_delay"]) iotile_b_5k_db = list(iotile_b_db) iotile_b_5k_db.append([["B14[15]"], "IoCtrl", "padeb_test_1"]) iotile_b_5k_db.append([["B15[14]"], "IoCtrl", "padeb_test_0"]) iotile_b_5k_db.append([["B7[10]"], "IoCtrl", "cf_bit_32"]) iotile_b_5k_db.append([["B6[10]"], "IoCtrl", "cf_bit_33"]) iotile_b_5k_db.append([["B7[15]"], "IoCtrl", "cf_bit_34"]) iotile_b_5k_db.append([["B6[15]"], "IoCtrl", "cf_bit_35"]) iotile_b_5k_db.append([["B13[10]"], "IoCtrl", "cf_bit_36"]) iotile_b_5k_db.append([["B12[10]"], "IoCtrl", "cf_bit_37"]) iotile_b_5k_db.append([["B13[15]"], "IoCtrl", "cf_bit_38"]) iotile_b_5k_db.append([["B12[15]"], "IoCtrl", "cf_bit_39"]) iotile_b_5k_db.append([["B10[3]"], "IpConfig", "cbit2usealt_in_0"]) iotile_b_5k_db.append([["B12[2]"], "IpConfig", "cbit2usealt_in_1"]) iotile_b_5k_db.append([["B12[3]"], "IpConfig", "SDA_input_delay"]) iotile_b_5k_db.append([["B15[3]"], "IpConfig", "SDA_output_delay"]) for db in [iotile_l_db, iotile_r_db, iotile_t_db, iotile_b_db, iotile_t_5k_db, iotile_b_5k_db, logictile_db, logictile_5k_db, logictile_8k_db, logictile_384_db, rambtile_db, ramttile_db, rambtile_8k_db, ramttile_8k_db, dsp0_5k_db, dsp1_5k_db, dsp2_5k_db, dsp3_5k_db, ipcon_5k_db]: for entry in db: if entry[1] in ("buffer", "routing"): entry[2] = netname_normalize(entry[2], ramb=(db == rambtile_db), ramt=(db == ramttile_db), ramb_8k=(db == rambtile_8k_db), ramt_8k=(db == ramttile_8k_db)) entry[3] = netname_normalize(entry[3], ramb=(db == rambtile_db), ramt=(db == ramttile_db), ramb_8k=(db == rambtile_8k_db), ramt_8k=(db == ramttile_8k_db)) unique_entries = dict() while db: entry = db.pop() key = " ".join(entry[1:]) + str(entry) unique_entries[key] = entry for key in sorted(unique_entries): db.append(unique_entries[key]) if __name__ == "__main__": run_checks()