From 88eebff7db9d76e418ccbddd884c4e617596a428 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 12 Nov 2017 19:13:55 +0000 Subject: Start UltraPlus DSP documentation --- docs/ultraplus.html | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 docs/ultraplus.html (limited to 'docs/ultraplus.html') diff --git a/docs/ultraplus.html b/docs/ultraplus.html new file mode 100644 index 0000000..86fd857 --- /dev/null +++ b/docs/ultraplus.html @@ -0,0 +1,157 @@ + + + +Project IceStorm – UltraPlus Features Documentation + +

Project IceStorm – UltraPlus Features Documentation

+ +

+Project IceStorm aims at documenting the bitstream format of Lattice iCE40 +FPGAs and providing simple tools for analyzing and creating bitstream files. +This is work in progress. +

+ +

The ice40 UltraPlus devices have a number of new features compared to the older LP/HX series + devices, in particular: +

+ In order to implement these new features, a significant architecural change has been made: the + left and right sides of the device are no longer IO, but instead DSP and IPConnect tiles. +

+ +

DSP Tiles

+

Each MAC16 DSP comprises of 4 DSP tiles, all of which perform part of the DSP function and have +different routing bit configurations. Structually they are similar to logic tiles, but with the DSP +function wired into where the LUTs and DFFs would be. The four types of DSP tiles will be referred to +as DSP0 through DSP3, with DSP0 at the lowest y-position. One signal CO, is also routed through the +IPConnect tile above the DSP tile, referred to as IPCON4 in this context. + +A work-in-progress effort to determine where signals and configuration bits are located is below:

+

+Signal Assignments
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SB_MAC16 portDSP0DSP1DSP2DSP3IPCON4
CLK--lutff_global/clk--
CE--lutff_global/cen--
C[7:0]---lutff_[7:0]/in_3-
C[15:8]---lutff_[7:0]/in_1-
A[7:0]--lutff_[7:0]/in_3--
A[15:8]--lutff_[7:0]/in_1--
B[7:0]-lutff_[7:0]/in_3---
B[15:8]-lutff_[7:0]/in_1---
D[7:0]lutff_[7:0]/in_3----
D[15:8]lutff_[7:0]/in_1----
IRSTTOP-lutff_global/s_r---
IRSTBOTlutff_global/s_r----
ORSTTOP---lutff_global/s_r-
ORSTBOT--lutff_global/s_r--
AHOLD--lutff_0/in_0--
BHOLD-lutff_0/in_0---
CHOLD---lutff_0/in_0-
DHOLDlutff_0/in_0----
OHOLDTOP---lutff_1/in_0-
OHOLDBOTlutff_1/in_0----
ADDSUBTOP---lutff_3/in_0-
ADDSUBBOTlutff_3/in_0----
OLOADTOP---lutff_2/in_0-
OLOADBOTlutff_2/in_0----
CIlutff_4/in_0----
O[31:0]mult/O_[7:0]mult/O_[15:8]mult/O_[23:16]mult/O_[31:24]-
CO----slf_op_0
+ + +

+ +

+Configuration Bits
+

The DSP configuration bits mostly follow the order stated in the ICE Technology Library document, where they are described asCBIT[24:0]. For most DSP tiles, + these follow a logical order where CBIT[7:0] maps to DSP0 CBIT[7:0]; CBIT[15:8] + to DSP1 CBIT[7:0], CBIT[23:16] to DSP2 CBIT[7:0] + and CBIT[24] to DSP3 CBIT0. +

+

However, there are some locations where configuration bits are swapped between DSP tiles and IPConnect tiles. For example, DSP1 (0, 16) CBIT[4:3] is used + for the internal oscillator, and the DSP configuration bits are then located in IPConnect tile (0, 19) CBIT[6:5].

+

The exact permutations are not yet known, but a script will be developed to find them.

+

+Other Implementation Notes
+

+ All active DSP tiles, and all IPConnect tiles whether used or not, have some bits set which reflect their logic tile heritage. The LC_x + bits which would be used to configure the logic cell, are set to the below pattern for each "logic cell" (interpreting them like a logic tile):
+
0000111100001111 0000

+ Coincidentally or not, this corresponds to a buffer passing through input 2 to the output. For each "cell" the cascade bit LC0x_inmux02_5 is + also set, effectively creating one large chain, as this connects input 2 to the output of the previous LUT. It is not yet known if this serves any purpose, or is merely a remainder of Lattice's + internal testing. +

+

+

IPConnect Tiles

+

IPConnect tiles are used for connections to all of the other UltraPlus features, such as I2C/SPI, SPRAM, RGB and oscillators. Like DSP tiles, +they are structually similar to logic tiles. The outputs of IP functions are connected to nets named slf_op_0 through slf_op_7, +and the inputs use the LUT/FF inputs in the same way as DSP tiles.

+ + + +

Internal Oscillators

+ +Both of the internal oscillators are connected through IPConnect tiles, with their outputs optionally connected to the global networks, +by setting the "padin" extra bit (the used global networks 4 and 5 don't have physical pins on UltraPlus devices). + +

SB_HFOSC

+

The CLKHFPU input connects through IPConnect tile (0, 29) input lutff_0/in_1; +and the CLKHFEN input connects through input lutff_7/in_3 of the same tile.
+ +The CLKHF output of SB_HFOSC is connected to both IPConnect tile (0, 28) output slf_op_7 and to the padin + of glb_netwk_4.

+ +

Configuration bit CLKHF_DIV[1] maps to DSP1 tile (0, 16) config bit CBIT_4, and +CLKHF_DIV[0] maps to DSP1 tile (0, 16) config bit CBIT_3.

+ +

SB_LFOSC

+

The CLKLFPU input connects through IPConnect tile (25, 29) input lutff_0/in_1; +and the CLKLFEN input connects through input lutff_7/in_3 of the same tile.
+ +The CLKLF output of SB_LFOSC is connected to both IPConnect tile (25, 29) output slf_op_0 and to the padin + of glb_netwk_5.

+ +

SB_LFOSC has no configuration bits.

+ + -- cgit v1.2.3 From 64e3c1a9cd81e61d9a3b163c9e9f9390fa4c5c21 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 13 Nov 2017 16:15:16 +0000 Subject: Figure out DSP config bits for all locs --- docs/ultraplus.html | 45 +++++++++- icefuzz/tests/dsp_cbit/.gitignore | 1 + icefuzz/tests/dsp_cbit/dsp_cbits_up5k.txt | 9 ++ icefuzz/tests/dsp_cbit/fuzz_dsp_cbit.py | 132 ++++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+), 3 deletions(-) create mode 100644 icefuzz/tests/dsp_cbit/.gitignore create mode 100644 icefuzz/tests/dsp_cbit/dsp_cbits_up5k.txt create mode 100755 icefuzz/tests/dsp_cbit/fuzz_dsp_cbit.py (limited to 'docs/ultraplus.html') diff --git a/docs/ultraplus.html b/docs/ultraplus.html index 86fd857..4220cad 100644 --- a/docs/ultraplus.html +++ b/docs/ultraplus.html @@ -109,9 +109,48 @@ A work-in-progress effort to determine where signals and configuration bits are to DSP1 CBIT[7:0], CBIT[23:16] to DSP2 CBIT[7:0] and CBIT[24] to DSP3 CBIT0.

-

However, there are some locations where configuration bits are swapped between DSP tiles and IPConnect tiles. For example, DSP1 (0, 16) CBIT[4:3] is used - for the internal oscillator, and the DSP configuration bits are then located in IPConnect tile (0, 19) CBIT[6:5].

-

The exact permutations are not yet known, but a script will be developed to find them.

+

However, there is one location where configuration bits are swapped between DSP tiles and IPConnect tiles. In DSP1 (0, 16) CBIT[4:1] are used + for IP such as the internal oscillator, and the DSP configuration bits are then located in IPConnect tile (0, 19) CBIT[6:3].

+

The full list of configuration bits, including the changes for the DSP at (0, 15) are described in the table below.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterNormal PositionDSP (0, 15)
Changes
C_REGDSP0.CBIT_0
A_REGDSP0.CBIT_1
B_REGDSP0.CBIT_2
D_REGDSP0.CBIT_3
TOP_8x8_MULT_REGDSP0.CBIT_4
BOT_8x8_MULT_REGDSP0.CBIT_5
PIPELINE_16x16_MULT_REG1DSP0.CBIT_6
PIPELINE_16x16_MULT_REG2DSP0.CBIT_7
TOPOUTPUT_SELECT[0]DSP1.CBIT_0
TOPOUTPUT_SELECT[1]DSP1.CBIT_1(0, 19).CBIT_3
TOPADDSUB_LOWERINPUT[1:0]DSP1.CBIT_[3:2](0, 19).CBIT_[5:4]
TOPADDSUB_UPPERINUTDSP1.CBIT_4(0, 19).CBIT_6
TOPADDSUB_CARRYSELECT[1:0]DSP1.CBIT_[6:5]
BOTOUTPUT_SELECT[0]DSP1.CBIT_7
BOTOUTPUT_SELECT[1]DSP2.CBIT_0
BOTADDSUB_LOWERINPUT[1:0]DSP2.CBIT_[2:1]
BOTADDSUB_UPPERINPUTDSP2.CBIT_3
BOTADDSUB_CARRYSELECTDSP2.CBIT_[5:4]
MODE_8x8DSP2.CBIT_6
A_SIGNEDDSP2.CBIT_7
B_SIGNEDDSP3.CBIT_0
+ +

Lattice document a limited number of supported configurations in the ICE Technology Library document, and Lattice's EDIF parser will + reject designs not following a supported configuration. It is not yet known whether unsupported configurations (such as mixed + signed and unsigned) function correctly or not. +

Other Implementation Notes

diff --git a/icefuzz/tests/dsp_cbit/.gitignore b/icefuzz/tests/dsp_cbit/.gitignore new file mode 100644 index 0000000..83d459d --- /dev/null +++ b/icefuzz/tests/dsp_cbit/.gitignore @@ -0,0 +1 @@ +work_dsp_cbit/ \ No newline at end of file diff --git a/icefuzz/tests/dsp_cbit/dsp_cbits_up5k.txt b/icefuzz/tests/dsp_cbit/dsp_cbits_up5k.txt new file mode 100644 index 0000000..e90c647 --- /dev/null +++ b/icefuzz/tests/dsp_cbit/dsp_cbits_up5k.txt @@ -0,0 +1,9 @@ +DSP (0, 15): + Missing (0, 16, CBIT_1) + Missing (0, 16, CBIT_2) + Missing (0, 16, CBIT_3) + Missing (0, 16, CBIT_4) + New: (0, 19, CBIT_3) + New: (0, 19, CBIT_5) + New: (0, 19, CBIT_4) + New: (0, 19, CBIT_6) diff --git a/icefuzz/tests/dsp_cbit/fuzz_dsp_cbit.py b/icefuzz/tests/dsp_cbit/fuzz_dsp_cbit.py new file mode 100755 index 0000000..79f376c --- /dev/null +++ b/icefuzz/tests/dsp_cbit/fuzz_dsp_cbit.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 + +import os, sys + +device = "up5k" + +# This script is designed to determine which DSPs have configuration bits +# not in their usual position, as in some cases DSP and IPConnect tiles have +# their config bits swapped + +# Unfortunately, arbitrary configurations are not allowed by icecube, so +# we define a set that gives us maximum coverage (full coverage is not +# possible as one CBIT is never set) + +allowed_configs = ["1110000010000001001110110", "0010000101000010111111111", "0001111000101100000000000"] + +coverage = set() +for c in allowed_configs: + for i in range(25): + if c[i] == "1": + coverage.add(i) + +assert len(coverage) >= 24 + +def parse_exp(f): + current_x = 0 + current_y = 0 + bits = set() + for line in f: + splitline = line.split(' ') + if splitline[0].endswith("_tile"): + current_x = int(splitline[1]) + current_y = int(splitline[2]) + elif splitline[0] == "IpConfig": + if splitline[1][:5] == "CBIT_": + bitidx = int(splitline[1][5:]) + bits.add((current_x, current_y, bitidx)) + return bits +dsp_locs = [( 0, 5, 0), ( 0, 10, 0), ( 0, 15, 0), ( 0, 23, 0), + (25, 5, 0), (25, 10, 0), (25, 15, 0), (25, 23, 0)] + +dsp_data = {} + +if not os.path.exists("./work_dsp_cbit"): + os.mkdir("./work_dsp_cbit") + +for loc in dsp_locs: + x, y, z = loc + missing_bits = set() + new_bits = set() + for config in allowed_configs: + params = config[::-1] + with open("./work_dsp_cbit/dsp_cbit.v","w") as f: + print(""" + module top(input clk, input a, input b, input c, input d, output y); + """, file=f) + print(""" + SB_MAC16 #( + .C_REG(1'b%s), + .A_REG(1'b%s), + .B_REG(1'b%s), + .D_REG(1'b%s), + .TOP_8x8_MULT_REG(1'b%s), + .BOT_8x8_MULT_REG(1'b%s), + .PIPELINE_16x16_MULT_REG1(1'b%s), + .PIPELINE_16x16_MULT_REG2(1'b%s), + .TOPOUTPUT_SELECT(2'b%s), + .TOPADDSUB_LOWERINPUT(2'b%s), + .TOPADDSUB_UPPERINPUT(1'b%s), + .TOPADDSUB_CARRYSELECT(2'b%s), + .BOTOUTPUT_SELECT(2'b%s), + .BOTADDSUB_LOWERINPUT(2'b%s), + .BOTADDSUB_UPPERINPUT(1'b%s), + .BOTADDSUB_CARRYSELECT(2'b%s), + .MODE_8x8(1'b%s), + .A_SIGNED(1'b%s), + .B_SIGNED(1'b%s) + ) dsp ( + .CLK(clk), + .C(c), + .A(a), + .B(b), + .D(d), + .O(y) + );""" + % ( + params[0], params[1], params[2], params[3], + params[4], params[5], params[6], params[7], + params[8:10][::-1], params[10:12][::-1], params[12], params[13:15][::-1], + params[15:17][::-1], params[17:19][::-1], params[19], params[20:22][::-1], + params[22], params[23], params[24]), file=f) + print("endmodule",file=f) + with open("./work_dsp_cbit/dsp_cbit.pcf","w") as f: + print("set_location dsp %d %d %d" % loc, file=f) + retval = os.system("bash ../../icecube.sh -" + device + " ./work_dsp_cbit/dsp_cbit.v > ./work_dsp_cbit/icecube.log 2>&1") + if retval != 0: + sys.stderr.write('ERROR: icecube returned non-zero error code\n') + sys.exit(1) + retval = os.system("../../../icebox/icebox_explain.py ./work_dsp_cbit/dsp_cbit.asc > ./work_dsp_cbit/dsp_cbit.exp") + if retval != 0: + sys.stderr.write('ERROR: icebox_explain returned non-zero error code\n') + sys.exit(1) + bits = set() + known = set() + with open('./work_dsp_cbit/dsp_cbit.exp', 'r') as f: + bits = parse_exp(f) + for i in range(25): + if params[i] == "1": + exp_pos = (x, y + (i // 8), i % 8) + if exp_pos not in bits: + missing_bits.add(exp_pos) + else: + known.add(exp_pos) + for bit in bits: + if bit not in known: + new_bits.add(bit) + if len(missing_bits) > 0 or len(new_bits) > 0: + print("DSP (%d, %d):" % (x, y)) + for bit in missing_bits: + print("\tMissing (%d, %d, CBIT_%d)" % bit) + for bit in new_bits: + print("\tNew: (%d, %d, CBIT_%d)" % bit) + dsp_data[loc] = (missing_bits, new_bits) +with open("dsp_cbits_%s.txt" % device, 'w') as f: + for loc in dsp_data: + x, y, z = loc + missing_bits, new_bits = dsp_data[loc] + print("DSP (%d, %d):" % (x, y), file=f) + for bit in missing_bits: + print("\tMissing (%d, %d, CBIT_%d)" % bit,file=f) + for bit in new_bits: + print("\tNew: (%d, %d, CBIT_%d)" % bit,file=f) -- cgit v1.2.3 From 2f962ac92e018370793b9db3635fabd5b599afef Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 13 Nov 2017 16:51:28 +0000 Subject: Fix 5k corner routing, and reverse engineer SPRAM --- docs/ultraplus.html | 24 ++++ icebox/icebox.py | 113 +++++++++++++--- icefuzz/tests/spram/.gitignore | 1 + icefuzz/tests/spram/fuzz_spram.py | 173 ++++++++++++++++++++++++ icefuzz/tests/spram/up5k_spram_data.txt | 232 ++++++++++++++++++++++++++++++++ 5 files changed, 523 insertions(+), 20 deletions(-) create mode 100644 icefuzz/tests/spram/.gitignore create mode 100755 icefuzz/tests/spram/fuzz_spram.py create mode 100644 icefuzz/tests/spram/up5k_spram_data.txt (limited to 'docs/ultraplus.html') diff --git a/docs/ultraplus.html b/docs/ultraplus.html index 4220cad..1074862 100644 --- a/docs/ultraplus.html +++ b/docs/ultraplus.html @@ -193,4 +193,28 @@ The CLKLF output of SB_LFOSC is conne

SB_LFOSC has no configuration bits.

+

SPRAM

+

The UltraPlus devices have 1Mbit of extra single-ported RAM, split into 4 256kbit blocks. The full list of connections for each SPRAM block in the 5k device is shown below, + as well as the location of the 1 configuration bit which is set to enable use of that SPRAM block.

+ + + + + + + + + + + + + + + + + + + +
SignalSPRAM (0, 0, 1)SPRAM (0, 0, 2)SPRAM (25, 0, 3)SPRAM (25, 0, 4)
ADDRESS[1:0](0, 2, lutff_[1:0]/in_1)(0, 2, lutff_[7:6]/in_0)(25, 2, lutff_[1:0]/in_1)(25, 2, lutff_[7:6]/in_0)
ADDRESS[7:2](0, 2, lutff_[7:2]/in_1)(0, 3, lutff_[5:0]/in_3)(25, 2, lutff_[7:2]/in_1)(25, 3, lutff_[5:0]/in_3)
ADDRESS[9:8](0, 2, lutff_[1:0]/in_0)(0, 3, lutff_[7:6]/in_3)(25, 2, lutff_[1:0]/in_0)(25, 3, lutff_[7:6]/in_3)
ADDRESS[13:10](0, 2, lutff_[5:2]/in_0)(0, 3, lutff_[3:0]/in_1)(25, 2, lutff_[5:2]/in_0)(25, 3, lutff_[3:0]/in_1)
DATAIN[7:0](0, 1, lutff_[7:0]/in_3)(0, 1, lutff_[7:0]/in_0)(25, 1, lutff_[7:0]/in_3)(25, 1, lutff_[7:0]/in_0)
DATAIN[15:8](0, 1, lutff_[7:0]/in_1)(0, 2, lutff_[7:0]/in_3)(25, 1, lutff_[7:0]/in_1)(25, 2, lutff_[7:0]/in_3)
MASKWREN[3:0](0, 3, lutff_[3:0]/in_0)(0, 3, lutff_[7:4]/in_0)(25, 3, lutff_[3:0]/in_0)(25, 3, lutff_[7:4]/in_0)
WREN(0, 3, lutff_4/in_1)(0, 3, lutff_5/in_1)(25, 3, lutff_4/in_1)(25, 3, lutff_5/in_1)
CHIPSELECT(0, 3, lutff_6/in_1)(0, 3, lutff_7/in_1)(25, 3, lutff_6/in_1)(25, 3, lutff_7/in_1)
CLOCK(0, 1, clk)(0, 2, clk)(25, 1, clk)(25, 2, clk)
STANDBY(0, 4, lutff_0/in_3)(0, 4, lutff_1/in_3)(25, 4, lutff_0/in_3)(25, 4, lutff_1/in_3)
SLEEP(0, 4, lutff_2/in_3)(0, 4, lutff_3/in_3)(25, 4, lutff_2/in_3)(25, 4, lutff_3/in_3)
POWEROFF(0, 4, lutff_4/in_3)(0, 4, lutff_5/in_3)(25, 4, lutff_4/in_3)(25, 4, lutff_5/in_3)
DATAOUT[7:0](0, 1, slf_op_[7:0])(0, 3, slf_op_[7:0])(25, 1, slf_op_[7:0])(25, 3, slf_op_[7:0])
DATAOUT[15:8](0, 2, slf_op_[7:0])(0, 4, slf_op_[7:0])(25, 2, slf_op_[7:0])(25, 4, slf_op_[7:0])
SPRAM_ENABLE(0, 1, CBIT_0)(0, 1, CBIT_1)(25, 1, CBIT_0)(25, 1, CBIT_1)
+ diff --git a/icebox/icebox.py b/icebox/icebox.py index a6d7155..9b3e35f 100644 --- a/icebox/icebox.py +++ b/icebox/icebox.py @@ -313,25 +313,25 @@ class iceconfig: 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: return True + if x == self.max_x and 1 < y < self.max_y and (self.device != "5k"): 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: return True + if x == 0 and 1 < y < self.max_y and (self.device != "5k"): 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: return True + if x == self.max_x and 0 < y < self.max_y-1 and (self.device != "5k"): 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: return True + if x == 0 and 0 < y < self.max_y-1 and (self.device != "5k"): 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: return True + if x == self.max_x and (self.device != "5k"): return True if netname.startswith("logic_op_rgt_"): - if x == 0: return True + if x == 0 and (self.device != "5k"): return True return False @@ -355,7 +355,7 @@ class iceconfig: def follow_funcnet(self, x, y, func): neighbours = set() def do_direction(name, nx, ny): - if 0 < nx < self.max_x and 0 < ny < self.max_y: + if (0 < nx < self.max_x or self.device == "5k") 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: neighbours.add((nx, ny, "logic_op_%s_%d" % (name, func))) @@ -444,7 +444,52 @@ class iceconfig: assert False return funcnets - + + #UltraPlus corner routing: given the corner name and net index, + #return a tuple containing H and V indexes, or none if NA + def ultraplus_trace_corner(self, corner, idx): + h_idx = None + v_idx = None + if corner == "bl": + if idx >= 4: + v_idx = idx + 28 + if idx >= 32 and idx < 48: + h_idx = idx - 28 + elif corner == "tl": + #TODO: bounds check for v_idx case? + v_idx = (idx + 8) ^ 1 + if idx >= 8 and idx < 32: + h_idx = (idx ^ 1) - 8 + elif corner == "tr": + #TODO: bounds check for v_idx case? + if idx <= 24: + v_idx = (idx + 12) ^ 1 + if idx >= 12 and idx < 36: + h_idx = (idx ^ 1) - 12 + elif corner == "br": + #TODO: bounds check for v_idx case? + if idx <= 16: + v_idx = idx + 32 + if idx >= 32 and idx < 48: #check + h_idx = idx - 32 + return (h_idx, v_idx) + + def get_corner(self, x, y): + corner = "" + if y == 0: + corner += "b" + elif y == self.max_y: + corner += "t" + else: + corner += "x" + if x == 0: + corner += "l" + elif x == self.max_x: + corner += "r" + else: + corner += "x" + return corner + def follow_net(self, netspec): x, y, netname = netspec neighbours = self.rlookup_funcnet(x, y, netname) @@ -465,7 +510,7 @@ class iceconfig: neighbours.add((nx, ny, netname)) match = re.match(r"sp4_r_v_b_(\d+)", netname) - if match and ((0 < x < self.max_x-1) or (self.device == "5k")): + if match and ((0 < x < self.max_x-1) or (self.device == "5k" and (x < self.max_x))): neighbours.add((x+1, y, sp4v_normalize("sp4_v_b_" + match.group(1)))) #print('\tafter r_v_b', neighbours) @@ -501,23 +546,39 @@ class iceconfig: if s[0] in (0, self.max_x) and s[1] in (0, self.max_y): if re.match("span4_(vert|horz)_[lrtb]_\d+$", n): - + m = re.match("span4_(vert|horz)_([lrtb])_\d+$", n) + if self.device == "5k" and (m.group(2) == "l" or m.group(2) == "t"): + continue vert_net = n.replace("_l_", "_t_").replace("_r_", "_b_").replace("_horz_", "_vert_") horz_net = n.replace("_t_", "_l_").replace("_b_", "_r_").replace("_vert_", "_horz_") if self.device == "5k": m = re.match("span4_vert_([lrtb])_(\d+)$", vert_net) assert m - vert_net = "sp4_v_%s_%d" % (m.group(1), int(m.group(2)) + 28) + idx = int(m.group(2)) + h_idx, v_idx = self.ultraplus_trace_corner(self.get_corner(s[0], s[1]), idx) + if v_idx is None: + if (s[0] == 0 and s[1] == 0 and direction == "l") or (s[0] == self.max_x and s[1] == self.max_y and direction == "r"): + continue + else: + vert_net = "sp4_v_%s_%d" % (m.group(1), v_idx) m = re.match("span4_horz_([lrtb])_(\d+)$", horz_net) assert m - horz_net = "span4_horz_%s_%d" % (m.group(1), int(m.group(2)) - 28) + idx = int(m.group(2)) + h_idx, v_idx = self.ultraplus_trace_corner(self.get_corner(s[0], s[1]), idx) + if h_idx is None: + if (s[0] == 0 and s[1] == 0 and direction == "b") or (s[0] == self.max_x and s[1] == self.max_y and direction == "t"): + continue + else: + horz_net = "span4_horz_%s_%d" % (m.group(1), h_idx) + + if s[0] == 0 and s[1] == 0: if direction == "l": s = (0, 1, vert_net) if direction == "b": s = (1, 0, horz_net) - + if s[0] == self.max_x and s[1] == self.max_y: if direction == "r": s = (self.max_x, self.max_y-1, vert_net) if direction == "t": s = (self.max_x-1, self.max_y, horz_net) @@ -525,23 +586,35 @@ class iceconfig: vert_net = netname.replace("_l_", "_t_").replace("_r_", "_b_").replace("_horz_", "_vert_").replace("_h_", "_v_") horz_net = netname.replace("_t_", "_l_").replace("_b_", "_r_").replace("_vert_", "_horz_").replace("_v_", "_h_") - if self.device == "5k": + if self.device == "5k": m = re.match("(span4_vert|sp4_v)_([lrtb])_(\d+)$", vert_net) assert m - vert_net = "sp4_v_%s_%d" % (m.group(2), int(m.group(3)) + 28) + idx = int(m.group(3)) + h_idx, v_idx = self.ultraplus_trace_corner(self.get_corner(s[0], s[1]), idx) + if v_idx is None: + if (s[0] == 0 and s[1] == self.max_y and direction == "l") or (s[0] == self.max_x and s[1] == 0 and direction == "r"): + continue + else: + vert_net = "sp4_v_%s_%d" % (m.group(2), v_idx) m = re.match("(span4_horz|sp4_h)_([lrtb])_(\d+)$", horz_net) assert m - horz_net = "span4_horz_%s_%d" % (m.group(2), int(m.group(3)) - 28) + idx = int(m.group(3)) + h_idx, v_idx = self.ultraplus_trace_corner(self.get_corner(s[0], s[1]), idx) + if h_idx is None: + if (s[0] == 0 and s[1] == self.max_y and direction == "t") or (s[0] == self.max_x and s[1] == 0 and direction == "b"): + continue + else: + horz_net = "span4_horz_%s_%d" % (m.group(2), h_idx) if s[0] == 0 and s[1] == self.max_y: if direction == "l": s = (0, self.max_y-1, vert_net) if direction == "t": s = (1, self.max_y, horz_net) - + if s[0] == self.max_x and s[1] == 0: if direction == "r": s = (self.max_x, 1, vert_net) if direction == "b": s = (self.max_x-1, 0, horz_net) - + if self.tile_has_net(s[0], s[1], s[2]): neighbours.add((s[0], s[1], s[2])) @@ -1097,13 +1170,13 @@ def pos_follow_net(pos, direction, netname, device): if case == "rr" and idx >= 12: return "span4_horz_l_%d" % idx - if pos == "l" and direction == "r": + if pos == "l" and direction == "r" and (device != "5k"): m = re.match("span4_horz_(\d+)$", netname) if m: return sp4h_normalize("sp4_h_l_%s" % m.group(1)) m = re.match("span12_horz_(\d+)$", netname) if m: return sp12h_normalize("sp12_h_l_%s" % m.group(1)) - if pos == "r" and direction == "l": + if pos == "r" and direction == "l" and (device != "5k"): m = re.match("span4_horz_(\d+)$", netname) if m: return sp4h_normalize("sp4_h_r_%s" % m.group(1)) m = re.match("span12_horz_(\d+)$", netname) diff --git a/icefuzz/tests/spram/.gitignore b/icefuzz/tests/spram/.gitignore new file mode 100644 index 0000000..c6ebe02 --- /dev/null +++ b/icefuzz/tests/spram/.gitignore @@ -0,0 +1 @@ +work_spram/ \ No newline at end of file diff --git a/icefuzz/tests/spram/fuzz_spram.py b/icefuzz/tests/spram/fuzz_spram.py new file mode 100755 index 0000000..33e62cb --- /dev/null +++ b/icefuzz/tests/spram/fuzz_spram.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python3 + +import os, sys, re + +device = "up5k" + +pins = "2 3 4 6 9 10 11 12 13 18 19 20 21 25 26 27 28 31 32 34 35 36 37 38 42 43 44 45 46 47 48".split() + +# This script is designed to determine the routing of 5k SPRAM signals, +# and the location of the enable config bits + +spram_locs = [(0, 0, 1), (0, 0, 2), (25, 0, 3), (25, 0, 4)] +#spram_locs = [(0, 0, 1)] +spram_data = { } + +spram_signals = ["WREN", "CHIPSELECT", "CLOCK", "STANDBY", "SLEEP", "POWEROFF"] + +for i in range(14): + spram_signals.append("ADDRESS[%d]" % i) + +for i in range(16): + spram_signals.append("DATAIN[%d]" % i) + +for i in range(16): + spram_signals.append("DATAOUT[%d]" % i) + +for i in range(4): + spram_signals.append("MASKWREN[%d]" % i) + +fuzz_options = ["ADDRESS", "DATAIN", "MASKWREN", "DATAOUT"] + +#Parse the output of an icebox vlog file to determine connectivity +def parse_vlog(f, pin2net, net_map): + current_net = None + + for line in f: + m = re.match(r"wire ([a-zA-Z0-9_]+);", line) + if m: + net = m.group(1) + mp = re.match(r"pin_([a-zA-Z0-9]+)", net) + if mp: + pin = mp.group(1) + if pin in pin2net: + current_net = pin2net[pin] + else: + current_net = None + else: + current_net = None + elif current_net is not None: + m = re.match(r"// \((\d+), (\d+), '([a-zA-Z0-9_/]+)'\)", line) + if m: + x = int(m.group(1)) + y = int(m.group(2)) + net = m.group(3) + if not (net.startswith("sp") or net.startswith("glb") or net.startswith("neigh") or net.startswith("io") or net.startswith("local") or net.startswith("fabout")): + net_map[current_net].add((x, y, net)) +def parse_exp(f): + current_x = 0 + current_y = 0 + bits = set() + for line in f: + splitline = line.split(' ') + if splitline[0].endswith("_tile"): + current_x = int(splitline[1]) + current_y = int(splitline[2]) + elif splitline[0] == "IpConfig": + if splitline[1][:5] == "CBIT_": + bitidx = int(splitline[1][5:]) + bits.add((current_x, current_y, splitline[1].strip())) + return bits + +if not os.path.exists("./work_spram"): + os.mkdir("./work_spram") + +for loc in spram_locs: + x, y, z = loc + net_map = {} + for sig in spram_signals: + net_map[sig] = set() + net_map["C_SPRAM_EN"] = set() # actually a CBIT not a net + + for n in fuzz_options: + with open("./work_spram/spram.v","w") as f: + print(""" + module top( + input WREN, + input CHIPSELECT, + input CLOCK, + input STANDBY, + input SLEEP, + input POWEROFF, + """, file=f) + if n == "ADDRESS": + print("\t\t\tinput [13:0] ADDRESS,", file=f) + if n == "DATAIN": + print("\t\t\tinput [15:0] DATAIN,", file=f) + if n == "MASKWREN": + print("\t\t\tinput [3:0] MASKWREN,", file=f) + if n == "DATAOUT": + print("\t\t\toutput [15:0] DATAOUT);", file=f) + else: + print("\t\t\toutput [0:0] DATAOUT);", file=f) #some dataout is always required to prevent optimisation away + + addr_net = "ADDRESS" if n == "ADDRESS" else "" + din_net = "DATAIN" if n == "DATAIN" else "" + mwren_net = "MASKWREN" if n == "MASKWREN" else "" + + print(""" + SB_SPRAM256KA spram_i + ( + .ADDRESS(%s), + .DATAIN(%s), + .MASKWREN(%s), + .WREN(WREN), + .CHIPSELECT(CHIPSELECT), + .CLOCK(CLOCK), + .STANDBY(STANDBY), + .SLEEP(SLEEP), + .POWEROFF(POWEROFF), + .DATAOUT(DATAOUT) + ); + """ % (addr_net, din_net, mwren_net), file=f) + print("endmodule",file=f) + pin2net = {} + with open("./work_spram/spram.pcf","w") as f: + temp_pins = list(pins) + for sig in spram_signals: + if sig.startswith("ADDRESS") and n != "ADDRESS": + continue + if sig.startswith("DATAIN") and n != "DATAIN": + continue + if sig.startswith("MASKWREN") and n != "MASKWREN": + continue + if sig.startswith("DATAOUT") and n != "DATAOUT" and sig != "DATAOUT[0]": + continue + + if len(temp_pins) == 0: + sys.stderr.write("ERROR: no remaining pins to alloc") + sys.exit(1) + + pin = temp_pins.pop() + pin2net[pin] = sig + print("set_io %s %s" % (sig, pin), file=f) + print("set_location spram_i %d %d %d" % loc, file=f) + retval = os.system("bash ../../icecube.sh -" + device + " ./work_spram/spram.v > ./work_spram/icecube.log 2>&1") + if retval != 0: + sys.stderr.write('ERROR: icecube returned non-zero error code\n') + sys.exit(1) + retval = os.system("../../../icebox/icebox_explain.py ./work_spram/spram.asc > ./work_spram/spram.exp") + if retval != 0: + sys.stderr.write('ERROR: icebox_explain returned non-zero error code\n') + sys.exit(1) + retval = os.system("../../../icebox/icebox_vlog.py -l ./work_spram/spram.asc > ./work_spram/spram.vlog") + if retval != 0: + sys.stderr.write('ERROR: icebox_vlog returned non-zero error code\n') + sys.exit(1) + with open("./work_spram/spram.vlog", "r") as f: + parse_vlog(f, pin2net, net_map) + bits = [] + with open("./work_spram/spram.exp", "r") as f: + bits = parse_exp(f) + net_map["C_SPRAM_EN"].update(bits) + spram_data[loc] = net_map + +with open(device + "_spram_data.txt", "w") as f: + for loc in spram_data: + print("SPRAM %d %d %d" % loc, file=f) + data = spram_data[loc] + for net in sorted(data): + cnets = [] + for cnet in data[net]: + cnets.append("(%d, %d, %s)" % cnet) + print("\t%s: %s" % (net, " ".join(cnets)), file=f) \ No newline at end of file diff --git a/icefuzz/tests/spram/up5k_spram_data.txt b/icefuzz/tests/spram/up5k_spram_data.txt new file mode 100644 index 0000000..c824e73 --- /dev/null +++ b/icefuzz/tests/spram/up5k_spram_data.txt @@ -0,0 +1,232 @@ +SPRAM 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) + C_SPRAM_EN: (0, 1, CBIT_0) + 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) + STANDBY: (0, 4, lutff_0/in_3) + WREN: (0, 3, lutff_4/in_1) +SPRAM 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) + C_SPRAM_EN: (0, 1, CBIT_1) + 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) + STANDBY: (0, 4, lutff_1/in_3) + WREN: (0, 3, lutff_5/in_1) +SPRAM 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) + C_SPRAM_EN: (25, 1, CBIT_0) + 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) + STANDBY: (25, 4, lutff_0/in_3) + WREN: (25, 3, lutff_4/in_1) +SPRAM 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) + C_SPRAM_EN: (25, 1, CBIT_1) + 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) + STANDBY: (25, 4, lutff_1/in_3) + WREN: (25, 3, lutff_5/in_1) -- cgit v1.2.3 From 25ad7a24b96b021c6ab25e275059e20187b4f882 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 14 Nov 2017 14:06:38 +0000 Subject: 5k RGB driver reverse engineered --- docs/ultraplus.html | 28 ++++ icefuzz/tests/rgba_drv_cbit/.gitignore | 1 + icefuzz/tests/rgba_drv_cbit/fuzz_rgba_drv_cbit.py | 174 +++++++++++++++++++++ icefuzz/tests/rgba_drv_cbit/rgba_drv_data_up5k.txt | 20 +++ 4 files changed, 223 insertions(+) create mode 100644 icefuzz/tests/rgba_drv_cbit/.gitignore create mode 100755 icefuzz/tests/rgba_drv_cbit/fuzz_rgba_drv_cbit.py create mode 100644 icefuzz/tests/rgba_drv_cbit/rgba_drv_data_up5k.txt (limited to 'docs/ultraplus.html') diff --git a/docs/ultraplus.html b/docs/ultraplus.html index 1074862..1b9e950 100644 --- a/docs/ultraplus.html +++ b/docs/ultraplus.html @@ -217,4 +217,32 @@ The CLKLF output of SB_LFOSC is conne SPRAM_ENABLE(0, 1, CBIT_0)(0, 1, CBIT_1)(25, 1, CBIT_0)(25, 1, CBIT_1) +

RGB LED Driver

+

The UltraPlus devices contain an internal 3-channel 2-24mA constant-current driver intended for RGB led driving (SB_RGBA_DRV). It is broken out onto 3 pins: 39, 40 and 41 on the QFN48 package. +The LED driver is implemented using the IPConnect tiles and is entirely seperate to the IO cells, if the LED driver is ignored or disabled on a pin then the pin +can be used as an open-drain IO using the standard IO cell.

+

Note that the UltraPlus devices also have a seperate PWM generator IP core, which would often be connected to this one to create LED effects such as "breathing" without + involving FPGA resources.

+

The LED driver connections are shown in the label below.

+ + + + + + + +
SignalNet
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)
+

The configuration bits are as follows. As well as the documented bits, another bit "RGBA_DRV_EN" is set if any of the channels are enabled.

+ + + + + + + + + + + +
ParameterBit
RGBA_DRV_EN(0, 28, CBIT_5)
RGB0_CURRENT[1:0](0, 28, CBIT_[7:6])
RGB0_CURRENT[5:2](0, 29, CBIT_[3:0])
RGB1_CURRENT[3:0](0, 29, CBIT_[7:4])
RGB1_CURRENT[5:4](0, 30, CBIT_[1:0])
RGB2_CURRENT[5:0](0, 30, CBIT_[7:2])
CURRENT_MODE(0, 28, CBIT_4)
diff --git a/icefuzz/tests/rgba_drv_cbit/.gitignore b/icefuzz/tests/rgba_drv_cbit/.gitignore new file mode 100644 index 0000000..68b6394 --- /dev/null +++ b/icefuzz/tests/rgba_drv_cbit/.gitignore @@ -0,0 +1 @@ +work_rgba_drv/ \ No newline at end of file diff --git a/icefuzz/tests/rgba_drv_cbit/fuzz_rgba_drv_cbit.py b/icefuzz/tests/rgba_drv_cbit/fuzz_rgba_drv_cbit.py new file mode 100755 index 0000000..a7e2006 --- /dev/null +++ b/icefuzz/tests/rgba_drv_cbit/fuzz_rgba_drv_cbit.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 + +import os, sys +# SB_RGBA_DRV automatic fuzzing script + +device = "up5k" + +# SB_RGBA_DRV config bits to be fuzzed +# These must be in an order such that a config with bit i set doesn't set any other undiscovered bits yet + + +fuzz_bits = [ + "RGB0_CURRENT_0", + "RGB0_CURRENT_1", + "RGB0_CURRENT_2", + "RGB0_CURRENT_3", + "RGB0_CURRENT_4", + "RGB0_CURRENT_5", + + "RGB1_CURRENT_0", + "RGB1_CURRENT_1", + "RGB1_CURRENT_2", + "RGB1_CURRENT_3", + "RGB1_CURRENT_4", + "RGB1_CURRENT_5", + + "RGB2_CURRENT_0", + "RGB2_CURRENT_1", + "RGB2_CURRENT_2", + "RGB2_CURRENT_3", + "RGB2_CURRENT_4", + "RGB2_CURRENT_5", + + "CURRENT_MODE" +] + + +# Boilerplate code based on the icefuzz script +code_prefix = """ +module top( + input curren, + input rgbleden, + input r_in, + input g_in, + input b_in, + output r_led, + output g_led, + output b_led); +""" + +def get_param_value(param_name, param_size, fuzz_bit): + param = "\"0b"; + #In the RGB driver, once bit i of a current parameter is set i-1..0 must also be set + is_high = False + for i in range(param_size - 1, -1, -1): + if fuzz_bit == param_name + "_" + str(i) or (i == 0 and fuzz_bit == "CURRENT_MODE") or is_high: + param += '1' + is_high = True + else: + param += '0' + param += "\"" + return param +def inst_rgba(fuzz_bit): + v = "" + v += """SB_RGBA_DRV rgba_inst ( + .CURREN(curren), + .RGBLEDEN(rgbleden), + .RGB0PWM(r_in), + .RGB1PWM(g_in), + .RGB2PWM(b_in), + .RGB0(r_led), + .RGB1(g_led), + .RGB2(b_led) + );""" + + v += "defparam rgba_inst.CURRENT_MODE = " + get_param_value("CURRENT_MODE", 1, fuzz_bit) + ";\n" + v += "defparam rgba_inst.RGB0_CURRENT = " + get_param_value("RGB0_CURRENT", 6, fuzz_bit) + ";\n" + v += "defparam rgba_inst.RGB1_CURRENT = " + get_param_value("RGB1_CURRENT", 6, fuzz_bit) + ";\n" + v += "defparam rgba_inst.RGB2_CURRENT = " + get_param_value("RGB2_CURRENT", 6, fuzz_bit) + ";\n" + + return v; + +def make_vlog(fuzz_bit): + vlog = code_prefix + vlog += inst_rgba(fuzz_bit) + vlog += "endmodule" + return vlog + +known_bits = [] + +# Set to true to continue even if multiple bits are changed (needed because +# of the issue discusssed below) +show_all_bits = False #TODO: make this an argument + +device = "up5k" #TODO: environment variable? + +#HACK: icecube doesn't let you set all of the config bits to 0, +#which makes fuzzing early on annoying as there is never a case +#with just 1 bit set. So a tiny bit of semi-manual work is needed +#first to discover this (basically run this script with show_all_bits=True +#and look for the stuck bit) +#TODO: clever code could get rid of this +rgba_drv_en_bit = { + "up5k" : (0, 28, 5) +} + +#Return a list of RGBA_DRIVER config bits in the format (x, y, bit) +def parse_exp(expfile): + current_x = 0 + current_y = 0 + bits = [] + with open(expfile, 'r') as f: + for line in f: + splitline = line.split(' ') + if splitline[0].endswith("_tile"): + current_x = int(splitline[1]) + current_y = int(splitline[2]) + elif splitline[0] == "IpConfig": + if splitline[1][:5] == "CBIT_": + bitidx = int(splitline[1][5:]) + bits.append((current_x, current_y, bitidx)) + return bits + +#Convert a bit tuple as returned from the above to a nice string +def bit_to_str(bit): + return "(%d, %d, \"CBIT_%d\")" % bit + +#The main fuzzing function +def do_fuzz(): + if not os.path.exists("./work_rgba_drv"): + os.mkdir("./work_rgba_drv") + known_bits.append(rgba_drv_en_bit[device]) + with open("rgba_drv_data_" + device + ".txt", 'w') as dat: + for fuzz_bit in fuzz_bits: + vlog = make_vlog(fuzz_bit) + with open("./work_rgba_drv/rgba_drv.v", 'w') as f: + f.write(vlog) + with open("./work_rgba_drv/rgba_drv.pcf", 'w') as f: + f.write(""" +set_io r_led 39 +set_io g_led 40 +set_io b_led 41 + """) + retval = os.system("bash ../../icecube.sh -" + device + " ./work_rgba_drv/rgba_drv.v > ./work_rgba_drv/icecube.log 2>&1") + if retval != 0: + sys.stderr.write('ERROR: icecube returned non-zero error code\n') + sys.exit(1) + retval = os.system("../../../icebox/icebox_explain.py ./work_rgba_drv/rgba_drv.asc > ./work_rgba_drv/rgba_drv.exp") + if retval != 0: + sys.stderr.write('ERROR: icebox_explain returned non-zero error code\n') + sys.exit(1) + rgba_bits = parse_exp("./work_rgba_drv/rgba_drv.exp") + new_bits = [] + for set_bit in rgba_bits: + if not (set_bit in known_bits): + new_bits.append(set_bit) + if len(new_bits) == 0: + sys.stderr.write('ERROR: no new bits set when setting config bit ' + fuzz_bit + '\n') + sys.exit(1) + if len(new_bits) > 1: + sys.stderr.write('ERROR: multiple new bits set when setting config bit ' + fuzz_bit + '\n') + for bit in new_bits: + sys.stderr.write('\t' + bit_to_str(bit) + '\n') + if not show_all_bits: + sys.exit(1) + if len(new_bits) == 1: + known_bits.append(new_bits[0]) + #print DIVQ_0 at the right moment, as it's not fuzzed normally + if fuzz_bit == "RGB0_CURRENT_0": + print(("\"RGBA_DRV_EN\":").ljust(24) + bit_to_str(rgba_drv_en_bit[device]) + ",") + dat.write(("\"RGBA_DRV_EN\":").ljust(24) + bit_to_str(rgba_drv_en_bit[device]) + ",\n") + print(("\"" + fuzz_bit + "\":").ljust(24) + bit_to_str(new_bits[0]) + ",") + dat.write(("\"" + fuzz_bit + "\":").ljust(24) + bit_to_str(new_bits[0]) + ",\n") +do_fuzz() \ No newline at end of file diff --git a/icefuzz/tests/rgba_drv_cbit/rgba_drv_data_up5k.txt b/icefuzz/tests/rgba_drv_cbit/rgba_drv_data_up5k.txt new file mode 100644 index 0000000..73bfb90 --- /dev/null +++ b/icefuzz/tests/rgba_drv_cbit/rgba_drv_data_up5k.txt @@ -0,0 +1,20 @@ +"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"), -- cgit v1.2.3 From 8fc49d07560f6bc434f9028086825388e5731a4f Mon Sep 17 00:00:00 2001 From: David Shah Date: Sat, 18 Nov 2017 11:40:52 +0000 Subject: Corrections and changes to UltraPlus doc --- docs/ultraplus.html | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'docs/ultraplus.html') diff --git a/docs/ultraplus.html b/docs/ultraplus.html index 1b9e950..e5706e6 100644 --- a/docs/ultraplus.html +++ b/docs/ultraplus.html @@ -35,9 +35,13 @@ This is work in progress.
  • 24mA constant current LED ouputs and PWM hard IP
  • In order to implement these new features, a significant architecural change has been made: the - left and right sides of the device are no longer IO, but instead DSP and IPConnect tiles. + left and right sides of the device are no longer IO, but instead DSP and IPConnect tiles. +

    +

    Currently icestorm and arachne-pnr support the DSPs (except for cascading), SPRAM , internal oscillators and constant current + LED drivers. Work to support the remaining features is underway.

    +

    DSP Tiles

    Each MAC16 DSP comprises of 4 DSP tiles, all of which perform part of the DSP function and have different routing bit configurations. Structually they are similar to logic tiles, but with the DSP @@ -45,7 +49,7 @@ function wired into where the LUTs and DFFs would be. The four types of DSP tile as DSP0 through DSP3, with DSP0 at the lowest y-position. One signal CO, is also routed through the IPConnect tile above the DSP tile, referred to as IPCON4 in this context. -A work-in-progress effort to determine where signals and configuration bits are located is below:

    +The location of signals and configuration bits is documented below.

    Signal Assignments
    @@ -101,10 +105,10 @@ A work-in-progress effort to determine where signals and configuration bits are

    - +

    Configuration Bits
    -

    The DSP configuration bits mostly follow the order stated in the ICE Technology Library document, where they are described asCBIT[24:0]. For most DSP tiles, +

    The DSP configuration bits mostly follow the order stated in the ICE Technology Library document, where they are described as CBIT[24:0]. For most DSP tiles, these follow a logical order where CBIT[7:0] maps to DSP0 CBIT[7:0]; CBIT[15:8] to DSP1 CBIT[7:0], CBIT[23:16] to DSP2 CBIT[7:0] and CBIT[24] to DSP3 CBIT0. @@ -138,7 +142,7 @@ A work-in-progress effort to determine where signals and configuration bits are

    - + @@ -158,8 +162,8 @@ A work-in-progress effort to determine where signals and configuration bits are bits which would be used to configure the logic cell, are set to the below pattern for each "logic cell" (interpreting them like a logic tile):

    0000111100001111 0000

    Coincidentally or not, this corresponds to a buffer passing through input 2 to the output. For each "cell" the cascade bit LC0x_inmux02_5 is - also set, effectively creating one large chain, as this connects input 2 to the output of the previous LUT. It is not yet known if this serves any purpose, or is merely a remainder of Lattice's - internal testing. + also set, effectively creating one large chain, as this connects input 2 to the output of the previous LUT. The DSPs at least will not function unless these bits are set correctly, so they + have some purpose and presumably indicate that the remains of a LUT are still present. There does not seem to be any case under which iCEcube generates a pattern other than this though.

    IPConnect Tiles

    @@ -171,7 +175,7 @@ and the inputs use the LUT/FF inputs in the same way as DSP tiles.

    Internal Oscillators

    -Both of the internal oscillators are connected through IPConnect tiles, with their outputs optionally connected to the global networks, +Both of the internal oscillators are connected through IPConnect tiles, with their outputs optionally connected to the global networks, by setting the "padin" extra bit (the used global networks 4 and 5 don't have physical pins on UltraPlus devices).

    SB_HFOSC

    @@ -181,7 +185,7 @@ and the CLKHFEN input connects throug The CLKHF output of SB_HFOSC is connected to both IPConnect tile (0, 28) output slf_op_7 and to the padin of glb_netwk_4.

    -

    Configuration bit CLKHF_DIV[1] maps to DSP1 tile (0, 16) config bit CBIT_4, and +

    Configuration bit CLKHF_DIV[1] maps to DSP1 tile (0, 16) config bit CBIT_4, and CLKHF_DIV[0] maps to DSP1 tile (0, 16) config bit CBIT_3.

    SB_LFOSC

    @@ -196,7 +200,7 @@ The CLKLF output of SB_LFOSC is conne

    SPRAM

    The UltraPlus devices have 1Mbit of extra single-ported RAM, split into 4 256kbit blocks. The full list of connections for each SPRAM block in the 5k device is shown below, as well as the location of the 1 configuration bit which is set to enable use of that SPRAM block.

    - +
    BOTADDSUB_LOWERINPUT[1:0]DSP2.CBIT_[2:1]
    BOTADDSUB_UPPERINPUTDSP2.CBIT_3
    BOTADDSUB_CARRYSELECTDSP2.CBIT_[5:4]
    BOTADDSUB_CARRYSELECT[1:0]DSP2.CBIT_[5:4]
    MODE_8x8DSP2.CBIT_6
    @@ -218,7 +222,7 @@ The CLKLF output of SB_LFOSC is conne
    SignalSPRAM (0, 0, 1)SPRAM (0, 0, 2)SPRAM (25, 0, 3)SPRAM (25, 0, 4)
    ADDRESS[1:0](0, 2, lutff_[1:0]/in_1)(0, 2, lutff_[7:6]/in_0)(25, 2, lutff_[1:0]/in_1)(25, 2, lutff_[7:6]/in_0)

    RGB LED Driver

    -

    The UltraPlus devices contain an internal 3-channel 2-24mA constant-current driver intended for RGB led driving (SB_RGBA_DRV). It is broken out onto 3 pins: 39, 40 and 41 on the QFN48 package. +

    The UltraPlus devices contain an internal 3-channel 2-24mA constant-current driver intended for RGB led driving (SB_RGBA_DRV). It is broken out onto 3 pins: 39, 40 and 41 on the QFN48 package. The LED driver is implemented using the IPConnect tiles and is entirely seperate to the IO cells, if the LED driver is ignored or disabled on a pin then the pin can be used as an open-drain IO using the standard IO cell.

    Note that the UltraPlus devices also have a seperate PWM generator IP core, which would often be connected to this one to create LED effects such as "breathing" without @@ -232,7 +236,7 @@ can be used as an open-drain IO using the standard IO cell.

    RGB1PWM(0, 30, lutff_3/in_1) RGB2PWM(0, 30, lutff_4/in_1) -

    The configuration bits are as follows. As well as the documented bits, another bit "RGBA_DRV_EN" is set if any of the channels are enabled.

    +

    The configuration bits are as follows. As well as the documented bits, another bit RGBA_DRV_EN is set if any of the channels are enabled.

    -- cgit v1.2.3 From b059f37b5006bd12ae10f3e847fb394b2540aa6a Mon Sep 17 00:00:00 2001 From: David Shah Date: Sat, 18 Nov 2017 15:38:14 +0000 Subject: Add all cf_bits and pullup strength notes --- docs/ultraplus.html | 15 +++++++++++++++ icebox/icebox.py | 12 ++++++++++++ 2 files changed, 27 insertions(+) (limited to 'docs/ultraplus.html') diff --git a/docs/ultraplus.html b/docs/ultraplus.html index e5706e6..da109b5 100644 --- a/docs/ultraplus.html +++ b/docs/ultraplus.html @@ -248,5 +248,20 @@ can be used as an open-drain IO using the standard IO cell.

    +
    ParameterBit
    RGB2_CURRENT[5:0](0, 30, CBIT_[7:2])
    CURRENT_MODE(0, 28, CBIT_4)
    + +

    IO Changes

    +

    The IO tiles contain a few new bits compared to earlier ice40 devices. + The bits padeb_test_0 and + padeb_test_1 are set for all pins, + even unused ones, unless set as an output.

    +

    There are also some new bits used to control the pullup strength:

    + + + + + + +
    StrengthCell 0Cell 1
    3.3kΩcf_bit_32
    B7[10]
    cf_bit_36
    B13[10]
    6.8kΩcf_bit_33
    B6[10]
    cf_bit_37
    B12[10]
    10kΩcf_bit_34
    B7[15]
    cf_bit_38
    B13[15]
    100kΩ
    (default)
    !cf_bit_35
    !B6[15]
    !cf_bit_39
    !B12[15]
    diff --git a/icebox/icebox.py b/icebox/icebox.py index ce2a3cd..6b0dfd8 100644 --- a/icebox/icebox.py +++ b/icebox/icebox.py @@ -4808,13 +4808,25 @@ logictile_384_db.append([["B1[50]"], "CarryInSet"]) 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_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"]) 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_5k_db, ramttile_5k_db, rambtile_8k_db, ramttile_8k_db, dsp0_5k_db, dsp1_5k_db, dsp2_5k_db, dsp3_5k_db, ipcon_5k_db]: -- cgit v1.2.3