aboutsummaryrefslogtreecommitdiffstats
path: root/icefuzz
diff options
context:
space:
mode:
authorDavid Shah <davey1576@gmail.com>2017-10-30 11:32:17 +0000
committerDavid Shah <davey1576@gmail.com>2017-10-30 11:32:17 +0000
commit3059607dd799e18d5ce22c536021fc690d3ac13a (patch)
tree65c9c04da4cebf82412c2f1b7c84f560a1146ac7 /icefuzz
parentb78417ee78487947165a6552627a6d4e95945891 (diff)
downloadicestorm-3059607dd799e18d5ce22c536021fc690d3ac13a.tar.gz
icestorm-3059607dd799e18d5ce22c536021fc690d3ac13a.tar.bz2
icestorm-3059607dd799e18d5ce22c536021fc690d3ac13a.zip
PLL configuration fuzzing script
Diffstat (limited to 'icefuzz')
-rw-r--r--icefuzz/tests/pllauto/.gitignore1
-rw-r--r--icefuzz/tests/pllauto/pll_data_up5k.txt39
-rwxr-xr-xicefuzz/tests/pllauto/pllauto.py276
3 files changed, 316 insertions, 0 deletions
diff --git a/icefuzz/tests/pllauto/.gitignore b/icefuzz/tests/pllauto/.gitignore
new file mode 100644
index 0000000..7fafebe
--- /dev/null
+++ b/icefuzz/tests/pllauto/.gitignore
@@ -0,0 +1 @@
+work_pllauto/ \ No newline at end of file
diff --git a/icefuzz/tests/pllauto/pll_data_up5k.txt b/icefuzz/tests/pllauto/pll_data_up5k.txt
new file mode 100644
index 0000000..2010989
--- /dev/null
+++ b/icefuzz/tests/pllauto/pll_data_up5k.txt
@@ -0,0 +1,39 @@
+"PLLTYPE_1": (14, 31, "PLLCONFIG_1"),
+"PLLTYPE_2": (14, 31, "PLLCONFIG_3"),
+"PLLTYPE_0": (12, 31, "PLLCONFIG_5"),
+"FEEDBACK_PATH_0": (14, 31, "PLLCONFIG_5"),
+"FEEDBACK_PATH_1": (11, 31, "PLLCONFIG_9"),
+"FEEDBACK_PATH_2": (12, 31, "PLLCONFIG_1"),
+"PLLOUT_SELECT_A_0": (12, 31, "PLLCONFIG_6"),
+"PLLOUT_SELECT_A_1": (12, 31, "PLLCONFIG_7"),
+"PLLOUT_SELECT_B_0": (12, 31, "PLLCONFIG_2"),
+"PLLOUT_SELECT_B_1": (12, 31, "PLLCONFIG_3"),
+"SHIFTREG_DIV_MODE": (12, 31, "PLLCONFIG_4"),
+"FDA_FEEDBACK_0": (12, 31, "PLLCONFIG_9"),
+"FDA_FEEDBACK_1": (13, 31, "PLLCONFIG_1"),
+"FDA_FEEDBACK_2": (13, 31, "PLLCONFIG_2"),
+"FDA_FEEDBACK_3": (13, 31, "PLLCONFIG_3"),
+"FDA_RELATIVE_0": (13, 31, "PLLCONFIG_5"),
+"FDA_RELATIVE_1": (13, 31, "PLLCONFIG_6"),
+"FDA_RELATIVE_2": (13, 31, "PLLCONFIG_7"),
+"FDA_RELATIVE_3": (13, 31, "PLLCONFIG_8"),
+"DIVR_0": (10, 31, "PLLCONFIG_1"),
+"DIVR_1": (10, 31, "PLLCONFIG_2"),
+"DIVR_2": (10, 31, "PLLCONFIG_3"),
+"DIVR_3": (10, 31, "PLLCONFIG_4"),
+"DIVF_0": (10, 31, "PLLCONFIG_5"),
+"DIVF_1": (10, 31, "PLLCONFIG_6"),
+"DIVF_2": (10, 31, "PLLCONFIG_7"),
+"DIVF_3": (10, 31, "PLLCONFIG_8"),
+"DIVF_4": (10, 31, "PLLCONFIG_9"),
+"DIVF_5": (11, 31, "PLLCONFIG_1"),
+"DIVF_6": (11, 31, "PLLCONFIG_2"),
+"DIVQ_0": (11, 31, "PLLCONFIG_3"),
+"DIVQ_1": (11, 31, "PLLCONFIG_4"),
+"DIVQ_2": (11, 31, "PLLCONFIG_5"),
+"FILTER_RANGE_0": (11, 31, "PLLCONFIG_6"),
+"FILTER_RANGE_1": (11, 31, "PLLCONFIG_7"),
+"FILTER_RANGE_2": (11, 31, "PLLCONFIG_8"),
+"TEST_MODE": (12, 31, "PLLCONFIG_8"),
+"DELAY_ADJMODE_FB": (13, 31, "PLLCONFIG_4"),
+"DELAY_ADJMODE_REL": (13, 31, "PLLCONFIG_9"),
diff --git a/icefuzz/tests/pllauto/pllauto.py b/icefuzz/tests/pllauto/pllauto.py
new file mode 100755
index 0000000..647be29
--- /dev/null
+++ b/icefuzz/tests/pllauto/pllauto.py
@@ -0,0 +1,276 @@
+#!/usr/bin/env python3
+
+import os, sys
+# PLL automatic fuzzing script (WIP)
+
+device = "up5k"
+
+# PLL 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
+# e.g. PLL_TYPE must be fuzzed first as these will need to be set later on by virtue of enabling the PLL
+
+fuzz_bits = [
+ "PLLTYPE_1",
+ "PLLTYPE_2",
+ "PLLTYPE_0", #NB: as per the rule above this comes later is it can only be set by also setting 1 or 2
+
+ "FEEDBACK_PATH_0",
+ "FEEDBACK_PATH_1",
+ "FEEDBACK_PATH_2",
+
+ "PLLOUT_SELECT_A_0",
+ "PLLOUT_SELECT_A_1",
+
+ "PLLOUT_SELECT_B_0",
+ "PLLOUT_SELECT_B_1",
+
+ "SHIFTREG_DIV_MODE",
+
+ "FDA_FEEDBACK_0",
+ "FDA_FEEDBACK_1",
+ "FDA_FEEDBACK_2",
+ "FDA_FEEDBACK_3",
+
+ "FDA_RELATIVE_0",
+ "FDA_RELATIVE_1",
+ "FDA_RELATIVE_2",
+ "FDA_RELATIVE_3",
+
+ "DIVR_0",
+ "DIVR_1",
+ "DIVR_2",
+ "DIVR_3",
+
+ "DIVF_0",
+ "DIVF_1",
+ "DIVF_2",
+ "DIVF_3",
+ "DIVF_4",
+ "DIVF_5",
+ "DIVF_6",
+
+ #DIVQ_0 is missing, see comments later on
+ "DIVQ_1",
+ "DIVQ_2",
+
+ "FILTER_RANGE_0",
+ "FILTER_RANGE_1",
+ "FILTER_RANGE_2",
+
+ "TEST_MODE",
+
+ "DELAY_ADJMODE_FB", #these come at the end in case they set FDA_RELATIVE??
+ "DELAY_ADJMODE_REL"
+]
+
+# Boilerplate code based on the icefuzz script
+code_prefix = """
+module top(packagepin, a, b, w, x, y, z, extfeedback, bypass, resetb, lock, latchinputvalue, sdi, sdo, sclk, dynamicdelay_0, dynamicdelay_1, dynamicdelay_2, dynamicdelay_3, dynamicdelay_4, dynamicdelay_5, dynamicdelay_6, dynamicdelay_7);
+input packagepin;
+input a;
+input b;
+output w;
+output x;
+output reg y;
+output reg z;
+input extfeedback;
+input bypass;
+input resetb;
+output lock;
+input latchinputvalue;
+input sdi;
+output sdo;
+input sclk;
+wire plloutcorea;
+wire plloutcoreb;
+wire plloutglobala;
+wire plloutglobalb;
+assign w = plloutcorea ^ a;
+assign x = plloutcoreb ^ b;
+always @(posedge plloutglobala) y <= a;
+always @(posedge plloutglobalb) z <= b;
+input dynamicdelay_0;
+input dynamicdelay_1;
+input dynamicdelay_2;
+input dynamicdelay_3;
+input dynamicdelay_4;
+input dynamicdelay_5;
+input dynamicdelay_6;
+input dynamicdelay_7;
+"""
+
+def get_param_value(param_name, param_size, fuzz_bit):
+ param = str(param_size) + "'b";
+ for i in range(param_size - 1, -1, -1):
+ if fuzz_bit == param_name + "_" + str(i):
+ param += '1'
+ else:
+ param += '0'
+ return param
+def inst_pll(fuzz_bit):
+ pll_type = "SB_PLL40_2F_PAD" #default to this as it's most flexible
+
+ if fuzz_bit == "PLLTYPE_0":
+ pll_type = "SB_PLL40_CORE"
+ elif fuzz_bit == "PLLTYPE_1":
+ pll_type = "SB_PLL40_PAD"
+ elif fuzz_bit == "PLLTYPE_2":
+ pll_type = "SB_PLL40_2_PAD"
+
+ v = pll_type + " pll_inst (\n"
+ if pll_type == "SB_PLL40_CORE":
+ v += "\t.REFERENCECLK(referenceclk), \n"
+ else:
+ v += "\t.PACKAGEPIN(packagepin), \n"
+ v += "\t.RESETB(resetb),\n"
+ v += "\t.BYPASS(bypass),\n"
+ v += "\t.EXTFEEDBACK(extfeedback),\n"
+ v += "\t.LOCK(lock),\n"
+ v += "\t.LATCHINPUTVALUE(latchinputvalue),\n"
+ v += "\t.SDI(sdi),\n"
+ v += "\t.SDO(sdo),\n"
+ v += "\t.SCLK(sclk),\n"
+ if pll_type == "SB_PLL40_2F_PAD" or pll_type == "SB_PLL40_2_PAD":
+ v += "\t.PLLOUTCOREA(plloutcorea),\n"
+ v += "\t.PLLOUTGLOBALA(plloutglobala),\n"
+ v += "\t.PLLOUTCOREB(plloutcoreb),\n"
+ v += "\t.PLLOUTGLOBALB(plloutglobalb),\n"
+ else:
+ v += "\t.PLLOUTCORE(plloutcorea),\n"
+ v += "\t.PLLOUTGLOBAL(plloutglobala),\n"
+ v += "\t.DYNAMICDELAY({dynamicdelay_7, dynamicdelay_6, dynamicdelay_5, dynamicdelay_4, dynamicdelay_3, dynamicdelay_2, dynamicdelay_1, dynamicdelay_0})\n"
+ v += ");\n"
+
+ v += "defparam pll_inst.DIVR = " + get_param_value("DIVR", 4, fuzz_bit) + ";\n"
+ v += "defparam pll_inst.DIVF = " + get_param_value("DIVF", 7, fuzz_bit) + ";\n"
+ v += "defparam pll_inst.DIVQ = " + get_param_value("DIVQ", 3, fuzz_bit) + ";\n"
+ v += "defparam pll_inst.FILTER_RANGE = " + get_param_value("FILTER_RANGE", 3, fuzz_bit) + ";\n"
+
+ if fuzz_bit == "FEEDBACK_PATH_0":
+ v += "defparam pll_inst.FEEDBACK_PATH = \"SIMPLE\";\n"
+ elif fuzz_bit == "FEEDBACK_PATH_1":
+ v += "defparam pll_inst.FEEDBACK_PATH = \"PHASE_AND_DELAY\";\n"
+ elif fuzz_bit == "FEEDBACK_PATH_2":
+ v += "defparam pll_inst.FEEDBACK_PATH = \"EXTERNAL\";\n"
+ else:
+ v += "defparam pll_inst.FEEDBACK_PATH = \"DELAY\";\n"
+
+ v += "defparam pll_inst.DELAY_ADJUSTMENT_MODE_FEEDBACK = \"" + ("DYNAMIC" if (fuzz_bit == "DELAY_ADJMODE_FB") else "FIXED") + "\";\n"
+ v += "defparam pll_inst.FDA_FEEDBACK = " + get_param_value("FDA_FEEDBACK", 4, fuzz_bit) + ";\n"
+ v += "defparam pll_inst.DELAY_ADJUSTMENT_MODE_RELATIVE = \"" + ("DYNAMIC" if (fuzz_bit == "DELAY_ADJMODE_REL") else "FIXED") + "\";\n"
+ v += "defparam pll_inst.FDA_RELATIVE = " + get_param_value("FDA_RELATIVE", 4, fuzz_bit) + ";\n"
+ v += "defparam pll_inst.SHIFTREG_DIV_MODE = " + ("1'b1" if (fuzz_bit == "SHIFTREG_DIV_MODE") else "1'b0") + ";\n"
+
+
+
+ if pll_type == "SB_PLL40_2F_PAD" or pll_type == "SB_PLL40_2_PAD":
+ if pll_type == "SB_PLL40_2F_PAD":
+ if fuzz_bit == "PLLOUT_SELECT_A_0":
+ v += "defparam pll_inst.PLLOUT_SELECT_PORTA = \"GENCLK_HALF\";\n"
+ elif fuzz_bit == "PLLOUT_SELECT_A_1":
+ v += "defparam pll_inst.PLLOUT_SELECT_PORTA = \"SHIFTREG_90deg\";\n"
+ else:
+ v += "defparam pll_inst.PLLOUT_SELECT_PORTA = \"GENCLK\";\n"
+ if fuzz_bit == "PLLOUT_SELECT_B_0":
+ v += "defparam pll_inst.PLLOUT_SELECT_PORTB = \"GENCLK_HALF\";\n"
+ elif fuzz_bit == "PLLOUT_SELECT_B_1":
+ v += "defparam pll_inst.PLLOUT_SELECT_PORTB = \"SHIFTREG_90deg\";\n"
+ else:
+ v += "defparam pll_inst.PLLOUT_SELECT_PORTB = \"GENCLK\";\n"
+ else:
+ if fuzz_bit == "PLLOUT_SELECT_A_0":
+ v += "defparam pll_inst.PLLOUT_SELECT = \"GENCLK_HALF\";\n"
+ elif fuzz_bit == "PLLOUT_SELECT_A_1":
+ v += "defparam pll_inst.PLLOUT_SELECT = \"SHIFTREG_90deg\";\n"
+ else:
+ v += "defparam pll_inst.PLLOUT_SELECT = \"GENCLK\";\n"
+ v += "defparam pll_inst.TEST_MODE = " + ("1'b1" if (fuzz_bit == "TEST_MODE") else "1'b0") + ";\n"
+
+ return v;
+
+def make_vlog(fuzz_bit):
+ vlog = code_prefix
+ vlog += inst_pll(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 DIVQ 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
+divq_bit0 = {
+ "up5k" : (11, 31, 3)
+}
+
+#Return a list of PLL 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] == ".io_tile":
+ current_x = int(splitline[1])
+ current_y = int(splitline[2])
+ elif splitline[0] == "PLL":
+ if splitline[1][:10] == "PLLCONFIG_":
+ bitidx = int(splitline[1][10:])
+ 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, \"PLLCONFIG_%d\")" % bit
+
+#The main fuzzing function
+def do_fuzz():
+ if not os.path.exists("./work_pllauto"):
+ os.mkdir("./work_pllauto")
+ known_bits.append(divq_bit0[device])
+ with open("pll_data_" + device + ".txt", 'w') as dat:
+ for fuzz_bit in fuzz_bits:
+ vlog = make_vlog(fuzz_bit)
+ with open("./work_pllauto/pllauto.v", 'w') as f:
+ f.write(vlog)
+ retval = os.system("bash ../../icecube.sh -" + device + " ./work_pllauto/pllauto.v > ./work_pllauto/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_pllauto/pllauto.asc > ./work_pllauto/pllauto.exp")
+ if retval != 0:
+ sys.stderr.write('ERROR: icebox_explain returned non-zero error code\n')
+ sys.exit(1)
+ pll_bits = parse_exp("./work_pllauto/pllauto.exp")
+ new_bits = []
+ for set_bit in pll_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 == "DIVQ_1":
+ print(("\"DIVQ_0\":").ljust(24) + bit_to_str(divq_bit0[device]) + ",")
+ dat.write(("\"DIVQ_0\":").ljust(24) + bit_to_str(divq_bit0[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