Merge pull request #223 from corecode/u4k

add RGB_DRV/LED_DRV_CUR for u4k
diff --git a/icebox/icebox.py b/icebox/icebox.py
index c4b435c..335e328 100644
--- a/icebox/icebox.py
+++ b/icebox/icebox.py
@@ -5801,6 +5801,38 @@
         ("SMCCLK", (25, 3, 0)) : {
             "CLK":                          (25, 3, "slf_op_5")
         },
+        ("LED_DRV_CUR", (25, 21, 2)) : {
+            "LED_DRV_CUR_EN":               (25, 19, "CBIT_5"),
+            "EN":                           (25, 19, "lutff_6/in_3"),
+        },
+        ("RGB_DRV", (0, 21, 3)) : {
+            "RGB_DRV_EN":                   (0, 18, "CBIT_5"),
+            "RGB0_CURRENT_0":               (0, 18, "CBIT_6"),
+            "RGB0_CURRENT_1":               (0, 18, "CBIT_7"),
+            "RGB0_CURRENT_2":               (0, 19, "CBIT_0"),
+            "RGB0_CURRENT_3":               (0, 19, "CBIT_1"),
+            "RGB0_CURRENT_4":               (0, 19, "CBIT_2"),
+            "RGB0_CURRENT_5":               (0, 19, "CBIT_3"),
+            "RGB1_CURRENT_0":               (0, 19, "CBIT_4"),
+            "RGB1_CURRENT_1":               (0, 19, "CBIT_5"),
+            "RGB1_CURRENT_2":               (0, 19, "CBIT_6"),
+            "RGB1_CURRENT_3":               (0, 19, "CBIT_7"),
+            "RGB1_CURRENT_4":               (0, 20, "CBIT_0"),
+            "RGB1_CURRENT_5":               (0, 20, "CBIT_1"),
+            "RGB2_CURRENT_0":               (0, 20, "CBIT_2"),
+            "RGB2_CURRENT_1":               (0, 20, "CBIT_3"),
+            "RGB2_CURRENT_2":               (0, 20, "CBIT_4"),
+            "RGB2_CURRENT_3":               (0, 20, "CBIT_5"),
+            "RGB2_CURRENT_4":               (0, 20, "CBIT_6"),
+            "RGB2_CURRENT_5":               (0, 20, "CBIT_7"),
+            "RGBLEDEN":                     (0, 20, "lutff_1/in_1"),
+            "RGB0PWM":                      (0, 20, "lutff_2/in_1"),
+            "RGB1PWM":                      (0, 20, "lutff_3/in_1"),
+            "RGB2PWM":                      (0, 20, "lutff_4/in_1"),
+            "RGB0":                         (13, 21, 0),
+            "RGB1":                         (12, 21, 0),
+            "RGB2":                         (8, 21, 0)
+        },
     }
 }
 
diff --git a/icefuzz/extract.py b/icefuzz/extract.py
index 32bf289..75a65fa 100644
--- a/icefuzz/extract.py
+++ b/icefuzz/extract.py
@@ -41,7 +41,7 @@
                 cur_text_db = text_db.setdefault("ipcon_5k", set())
                 ignore = False
             elif device_class == "u4k" and line.startswith("IpCon"):
-                cur_text_db = text_db.setdefault("ipcon_u4k", set())
+                cur_text_db = text_db.setdefault("ipcon_5k", set())
                 ignore = False
             elif device_class == "5k" and line.startswith("DSP"):
                 match = re.match(r"DSP_Tile_\d+_(\d+)", line)
@@ -71,7 +71,7 @@
                 if ypos in [8, 16]:
                     dsp_idx = 3
                 assert dsp_idx != None
-                cur_text_db = text_db.setdefault("dsp%d_u4k" % dsp_idx, set())
+                cur_text_db = text_db.setdefault("dsp%d_5k" % dsp_idx, set())
                 ignore = False
             elif not ignore:
                 print("'" + line + "'")
diff --git a/icefuzz/make_uip.py b/icefuzz/make_uip.py
index 4452607..4d4fa5a 100755
--- a/icefuzz/make_uip.py
+++ b/icefuzz/make_uip.py
@@ -22,7 +22,7 @@
             module top (
                 input  [%d:0] glb_pins,
                 input  [%d:0] in_pins,
-                output [15:0] out_pins,
+                input   [2:0] led_data,
                 output [%d:0] led_pins
             );
             wire [%d:0] glb, glb_pins;
@@ -92,39 +92,39 @@
         # bits.append("pwm_out[1]")
         # bits.append("pwm_out[2]")
 
-        # current_choices = ["0b000000", "0b000001", "0b000011", "0b000111", "0b001111", "0b011111", "0b111111"]
+        current_choices = ["0b000000", "0b000001", "0b000011", "0b000111", "0b001111", "0b011111", "0b111111"]
 
-        # currents = [np.random.choice(current_choices) for i in range(3)]
+        currents = [np.random.choice(current_choices) for i in range(3)]
 
-        # bit_curren = np.random.choice(bits)
-        # bit_rgbleden = np.random.choice(bits)
-        # bits_pwm = [np.random.choice([np.random.choice(bits), "pwm_out[%d]" % i]) for i in range(3)]
+        bit_curren = np.random.choice(bits)
+        bit_rgbleden = np.random.choice(bits)
+        bits_pwm = [np.random.choice([np.random.choice(bits), "led_data[%d]" % i]) for i in range(3)]
 
-        # print("""
-		# 	wire rgbpu;
-		# 	SB_LED_DRV_CUR led_drv_cur (
-		# 		.EN(%s),
-		# 		.LEDPU(rgbpu)
-		# 	);
+        print("""
+			wire rgbpu;
+			SB_LED_DRV_CUR led_drv_cur (
+				.EN(%s),
+				.LEDPU(rgbpu)
+			);
 
-        #     SB_RGB_DRV #(
-        #         .RGB0_CURRENT(\"%s\"),
-        #         .RGB1_CURRENT(\"%s\"),
-        #         .RGB2_CURRENT(\"%s\")
-        #     ) rgb_drv (
-        #         .RGBLEDEN(%s),
-        #         .RGBPU(rgbpu),
-        #         .RGB0PWM(%s),
-        #         .RGB1PWM(%s),
-        #         .RGB2PWM(%s),
-        #         .RGB0(led_pins[0]),
-        #         .RGB1(led_pins[1]),
-        #         .RGB2(led_pins[2])
-        #     );
-        # """ % (
-        #     bit_curren, currents[0], currents[1], currents[2],
-        #     bit_rgbleden, bits_pwm[0], bits_pwm[1], bits_pwm[2]
-        # ), file = f)
+            SB_RGB_DRV #(
+                .RGB0_CURRENT(\"%s\"),
+                .RGB1_CURRENT(\"%s\"),
+                .RGB2_CURRENT(\"%s\")
+            ) rgb_drv (
+                .RGBLEDEN(%s),
+                .RGBPU(rgbpu),
+                .RGB0PWM(%s),
+                .RGB1PWM(%s),
+                .RGB2PWM(%s),
+                .RGB0(led_pins[0]),
+                .RGB1(led_pins[1]),
+                .RGB2(led_pins[2])
+            );
+        """ % (
+            bit_curren, currents[0], currents[1], currents[2],
+            bit_rgbleden, bits_pwm[0], bits_pwm[1], bits_pwm[2]
+        ), file = f)
 
         # TODO: I2C and SPI
 
@@ -133,9 +133,7 @@
         p = list(np.random.permutation(pins))
         for i in range(len(pins) - len(glbs) - 16):
             print("set_io in_pins[%d] %s" % (i, p.pop()), file=f)
-        for i in range(16):
-            print("set_io out_pins[%d] %s" % (i, p.pop()), file=f)
-        # for i in range(len(led_pins)):
-        #     print("set_io led_pins[%d] %s" % (i, led_pins[i]), file=f)
+        for i in range(len(led_pins)):
+            print("set_io led_pins[%d] %s" % (i, led_pins[i]), file=f)
 
 output_makefile(working_dir, "uip")
diff --git a/icefuzz/tests/rgb_drv_cbit/.gitignore b/icefuzz/tests/rgb_drv_cbit/.gitignore
new file mode 100644
index 0000000..a1bf670
--- /dev/null
+++ b/icefuzz/tests/rgb_drv_cbit/.gitignore
@@ -0,0 +1 @@
+work_rgb_drv/
diff --git a/icefuzz/tests/rgb_drv_cbit/fuzz_rgb_drv_cbit.py b/icefuzz/tests/rgb_drv_cbit/fuzz_rgb_drv_cbit.py
new file mode 100755
index 0000000..57f69b4
--- /dev/null
+++ b/icefuzz/tests/rgb_drv_cbit/fuzz_rgb_drv_cbit.py
@@ -0,0 +1,181 @@
+#!/usr/bin/env python3
+
+import os, sys
+# SB_RGB_DRV automatic fuzzing script
+
+device = "u4k"
+
+# SB_RGB_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"
+]
+
+
+# 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 is_high:
+            param += '1'
+            is_high = True
+        else:
+            param += '0'
+    param += "\""
+    return param
+def inst_rgb(fuzz_bit):
+    v = ""
+    v += """wire ledpu;
+        SB_LED_DRV_CUR led_cur_inst (
+          .EN(curren),
+          .LEDPU(ledpu));
+"""
+    v += """SB_RGB_DRV rgb_inst (
+        .RGBPU(ledpu),
+        .RGBLEDEN(rgbleden),
+        .RGB0PWM(r_in),
+        .RGB1PWM(g_in),
+        .RGB2PWM(b_in),
+        .RGB0(r_led),
+        .RGB1(g_led),
+        .RGB2(b_led)
+      );
+"""
+
+    v += "defparam rgb_inst.RGB0_CURRENT = " + get_param_value("RGB0_CURRENT", 6, fuzz_bit) + ";\n"
+    v += "defparam rgb_inst.RGB1_CURRENT = " + get_param_value("RGB1_CURRENT", 6, fuzz_bit) + ";\n"
+    v += "defparam rgb_inst.RGB2_CURRENT = " + get_param_value("RGB2_CURRENT", 6, fuzz_bit) + ";\n"
+
+    return v;
+
+def make_vlog(fuzz_bit):
+    vlog = code_prefix
+    vlog += inst_rgb(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
+
+#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
+rgb_drv_en_bit = {
+    "u4k" : (0, 18, 5)
+}
+
+led_drv_cur_en_bit = {
+    "u4k" : (25, 19, 5)
+}
+
+#Return a list of RGB_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_rgb_drv"):
+        os.mkdir("./work_rgb_drv")
+    known_bits.append(rgb_drv_en_bit[device])
+    known_bits.append(led_drv_cur_en_bit[device])
+    with open("rgb_drv_data_" + device + ".txt", 'w') as dat:
+        for fuzz_bit in fuzz_bits:
+            vlog = make_vlog(fuzz_bit)
+            with open("./work_rgb_drv/rgb_drv.v", 'w') as f:
+                f.write(vlog)
+            with open("./work_rgb_drv/rgb_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_rgb_drv/rgb_drv.v > ./work_rgb_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_rgb_drv/rgb_drv.asc > ./work_rgb_drv/rgb_drv.exp")
+            if retval != 0:
+                sys.stderr.write('ERROR: icebox_explain returned non-zero error code\n')
+                sys.exit(1)
+            rgb_bits = parse_exp("./work_rgb_drv/rgb_drv.exp")
+            new_bits = []
+            for set_bit in rgb_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])
+                if fuzz_bit == "RGB0_CURRENT_0":
+                    print(("\"RGB_DRV_EN\":").ljust(24) + bit_to_str(rgb_drv_en_bit[device]) + ",")
+                    dat.write(("\"RGB_DRV_EN\":").ljust(24) + bit_to_str(rgb_drv_en_bit[device]) + ",\n")
+                    print(("\"LED_DRV_CUR_EN\":").ljust(24) + bit_to_str(led_drv_cur_en_bit[device]) + ",")
+                    dat.write(("\"LED_DRV_CUR_EN\":").ljust(24) + bit_to_str(led_drv_cur_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()
diff --git a/icefuzz/tests/rgb_drv_cbit/rgb_drv_data_u4k.txt b/icefuzz/tests/rgb_drv_cbit/rgb_drv_data_u4k.txt
new file mode 100644
index 0000000..54f4aa0
--- /dev/null
+++ b/icefuzz/tests/rgb_drv_cbit/rgb_drv_data_u4k.txt
@@ -0,0 +1,20 @@
+"RGB_DRV_EN":           (0, 18, "CBIT_5"),
+"LED_DRV_CUR_EN":       (25, 19, "CBIT_5"),
+"RGB0_CURRENT_0":       (0, 18, "CBIT_6"),
+"RGB0_CURRENT_1":       (0, 18, "CBIT_7"),
+"RGB0_CURRENT_2":       (0, 19, "CBIT_0"),
+"RGB0_CURRENT_3":       (0, 19, "CBIT_1"),
+"RGB0_CURRENT_4":       (0, 19, "CBIT_2"),
+"RGB0_CURRENT_5":       (0, 19, "CBIT_3"),
+"RGB1_CURRENT_0":       (0, 19, "CBIT_4"),
+"RGB1_CURRENT_1":       (0, 19, "CBIT_5"),
+"RGB1_CURRENT_2":       (0, 19, "CBIT_6"),
+"RGB1_CURRENT_3":       (0, 19, "CBIT_7"),
+"RGB1_CURRENT_4":       (0, 20, "CBIT_0"),
+"RGB1_CURRENT_5":       (0, 20, "CBIT_1"),
+"RGB2_CURRENT_0":       (0, 20, "CBIT_2"),
+"RGB2_CURRENT_1":       (0, 20, "CBIT_3"),
+"RGB2_CURRENT_2":       (0, 20, "CBIT_4"),
+"RGB2_CURRENT_3":       (0, 20, "CBIT_5"),
+"RGB2_CURRENT_4":       (0, 20, "CBIT_6"),
+"RGB2_CURRENT_5":       (0, 20, "CBIT_7"),
diff --git a/icefuzz/tests/sb_rgb_drv.pcf b/icefuzz/tests/sb_rgb_drv.pcf
new file mode 100644
index 0000000..993782a
--- /dev/null
+++ b/icefuzz/tests/sb_rgb_drv.pcf
@@ -0,0 +1,8 @@
+set_io r_led 39
+set_io g_led 40
+set_io b_led 41
+set_io r_in 25
+set_io g_in 26
+set_io b_in 27
+set_io en 28
+set_io rgbleden 31
diff --git a/icefuzz/tests/sb_rgb_drv.v b/icefuzz/tests/sb_rgb_drv.v
new file mode 100644
index 0000000..77533d8
--- /dev/null
+++ b/icefuzz/tests/sb_rgb_drv.v
@@ -0,0 +1,36 @@
+module top
+(
+ input  en,
+ input  rgbleden,
+ input  r_in,
+ input  g_in,
+ input  b_in,
+ output r_led,
+ output g_led,
+ output b_led);
+
+   wire ledpu;
+
+SB_LED_DRV_CUR
+LED_DRV_CUR(.EN(en),
+            .LEDPU(ledpu));
+
+   wire rgbpu;
+
+SB_RGB_DRV
+  RGB_DRV(.RGBLEDEN(rgbleden),
+          .RGBPU(rgbpu),
+          .RGB0PWM(r_in),
+          .RGB1PWM(g_in),
+          .RGB2PWM(b_in),
+          .RGB0(r_led),
+          .RGB1(g_led),
+          .RGB2(b_led));
+
+defparam RGB_DRV.RGB0_CURRENT = "0b000011";
+defparam RGB_DRV.RGB1_CURRENT = "0b001111";
+defparam RGB_DRV.RGB2_CURRENT = "0b111111";
+
+assign rgbpu = ledpu;
+
+endmodule
diff --git a/icefuzz/timings_u4k.txt b/icefuzz/timings_u4k.txt
index 5bdb59e..221bd78 100644
--- a/icefuzz/timings_u4k.txt
+++ b/icefuzz/timings_u4k.txt
@@ -177,6 +177,9 @@
 CELL PRE_IO_GBUF
 IOPATH  PADSIGNALTOGLOBALBUFFER  GLOBALBUFFEROUTPUT  1622.53:2836.85:4370.7  1106.27:1934.21:2980.02
 
+CELL SB_LED_DRV_CUR
+IOPATH  EN  LEDPU  1.72086e+07:3.00878e+07:4.63559e+07  1.72086e+07:3.00878e+07:4.63559e+07
+
 CELL SB_MAC16_ACC_U_16P16_ALL_PIPELINE
 HOLD      negedge:A[0]       posedge:CLK  110.748:193.633:298.328
 HOLD      negedge:A[1]       posedge:CLK  109.024:190.62:293.686
@@ -4198,6 +4201,11 @@
 IOPATH  posedge:RCLK       RDATA[14]     437.591:765.089:1178.76  437.591:765.089:1178.76
 IOPATH  posedge:RCLK       RDATA[15]     437.591:765.089:1178.76  437.591:765.089:1178.76
 
+CELL SB_RGB_DRV
+IOPATH  RGB0PWM  RGB0  17208.6:30087.8:46355.9  118002:206316:317869
+IOPATH  RGB1PWM  RGB1  17208.6:30087.8:46355.9  118002:206316:317869
+IOPATH  RGB2PWM  RGB2  17208.6:30087.8:46355.9  118002:206316:317869
+
 CELL Sp12to4
 IOPATH  I  O  221.254:386.843:596.004  314.672:550.176:847.65
 
diff --git a/icefuzz/tmedges.txt b/icefuzz/tmedges.txt
index 199fa2e..56366d6 100644
--- a/icefuzz/tmedges.txt
+++ b/icefuzz/tmedges.txt
@@ -172,6 +172,7 @@
 InMux.O LogicCell40.in3
 InMux.O SB_HFOSC.CLKHFEN
 InMux.O SB_HFOSC.CLKHFPU
+InMux.O SB_LED_DRV_CUR.EN
 InMux.O SB_LFOSC.CLKLFEN
 InMux.O SB_LFOSC.CLKLFPU
 InMux.O SB_MAC16_ACC_U_16P16_ALL_PIPELINE.ADDSUBBOT
@@ -2311,6 +2312,10 @@
 InMux.O SB_RGBA_DRV.RGB1PWM
 InMux.O SB_RGBA_DRV.RGB2PWM
 InMux.O SB_RGBA_DRV.RGBLEDEN
+InMux.O SB_RGB_DRV.RGB0PWM
+InMux.O SB_RGB_DRV.RGB1PWM
+InMux.O SB_RGB_DRV.RGB2PWM
+InMux.O SB_RGB_DRV.RGBLEDEN
 InMux.O SB_SPRAM256KA.ADDRESS[0]
 InMux.O SB_SPRAM256KA.ADDRESS[10]
 InMux.O SB_SPRAM256KA.ADDRESS[11]
@@ -2532,6 +2537,7 @@
 SB_LEDDA_IP.PWMOUT0 DummyBuf.I
 SB_LEDDA_IP.PWMOUT1 DummyBuf.I
 SB_LEDDA_IP.PWMOUT2 DummyBuf.I
+SB_LED_DRV_CUR.LEDPU SB_RGB_DRV.RGBPU
 SB_LFOSC.CLKLF GlobalMux.I
 SB_LFOSC.CLKLF Odrv12.I
 SB_MAC16_ACC_U_16P16_ALL_PIPELINE.ACCUMCO SB_MAC16_ACC_U_16P16_ALL_PIPELINE.ACCUMCI
diff --git a/icefuzz/tmedges.ys b/icefuzz/tmedges.ys
index 8520fb4..c1e8b3d 100644
--- a/icefuzz/tmedges.ys
+++ b/icefuzz/tmedges.ys
@@ -15,6 +15,8 @@
 hierarchy -generate SB_SPRAM256KA i:ADDRESS i:DATAIN i:MASKWREN i:WREN i:CHIPSELECT i:CLOCK i:STANDBY i:SLEEP \
    i:POWEROFF i:DATAOUT
 hierarchy -generate SB_RGBA_DRV i:CURREN i:RGBLEDEN i:RGB*PWM o:RGB*
+hierarchy -generate SB_LED_DRV_CUR i:EN o:LEDPU
+hierarchy -generate SB_RGB_DRV i:RGBPU i:RGBLEDEN i:RGB*PWM o:RGB*
 hierarchy -generate SB_LFOSC i:CLKLFPU i:CLKLFEN o:CLKLF
 hierarchy -generate SB_HFOSC i:CLKHFPU i:CLKHFEN o:CLKHF
 hierarchy -generate SB_LEDDA_IP i:LEDDCS i:LEDDCLK i:LEDDDAT* i:LEDDADDR* i:LEDDDEN i:LEDDEXE i:LEDDRST o:PWMOUT* o:LEDDON