Merge remote-tracking branch 'origin/master' into facade
diff --git a/.gitmodules b/.gitmodules
index e837083..d01ee12 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
[submodule "database"]
path = database
- url = https://github.com/SymbiFlow/prjtrellis-db
+ url = https://github.com/cr1901/prjtrellis-db.git
+ branch = facade
diff --git a/database b/database
index c137076..13da868 160000
--- a/database
+++ b/database
@@ -1 +1 @@
-Subproject commit c137076fdd8bfca3d2bf9cdacda9983dbbec599a
+Subproject commit 13da86838ba39f882a81a9fabe030b4c653854c9
diff --git a/devices.json b/devices.json
index 61eaaa8..68df05f 100644
--- a/devices.json
+++ b/devices.json
@@ -24,7 +24,7 @@
"max_row" : 50,
"max_col" : 72,
"col_bias" : 0,
- "fuzz": 1
+ "fuzz": 0
},
"LFE5U-45F": {
"packages": ["csfBGA285", "caBGA256", "caBGA381", "caBGA554", "caBGA756"],
@@ -36,7 +36,7 @@
"max_row" : 71,
"max_col" : 90,
"col_bias" : 0,
- "fuzz": 1
+ "fuzz": 0
},
"LFE5U-85F": {
"packages": ["csfBGA285", "caBGA381", "caBGA554", "caBGA756"],
@@ -48,7 +48,7 @@
"max_row" : 95,
"max_col" : 126,
"col_bias" : 0,
- "fuzz": 1
+ "fuzz": 0
},
"LFE5UM-25F": {
"packages": ["csfBGA285", "caBGA256", "caBGA381", "caBGA554", "caBGA756"],
@@ -60,7 +60,7 @@
"max_row" : 50,
"max_col" : 72,
"col_bias" : 0,
- "fuzz": 1
+ "fuzz": 0
},
"LFE5UM-45F": {
"packages": ["csfBGA285", "caBGA256", "caBGA381", "caBGA554", "caBGA756"],
@@ -72,7 +72,7 @@
"max_row" : 71,
"max_col" : 90,
"col_bias" : 0,
- "fuzz": 1
+ "fuzz": 0
},
"LFE5UM-85F": {
"packages": ["csfBGA285", "caBGA381", "caBGA554", "caBGA756"],
@@ -84,7 +84,7 @@
"max_row" : 95,
"max_col" : 126,
"col_bias" : 0,
- "fuzz": 1
+ "fuzz": 0
},
"LFE5UM5G-25F": {
"packages": ["csfBGA285", "caBGA256", "caBGA381", "caBGA554", "caBGA756"],
@@ -96,7 +96,7 @@
"max_row" : 50,
"max_col" : 72,
"col_bias" : 0,
- "fuzz": 1
+ "fuzz": 0
},
"LFE5UM5G-45F": {
"packages": ["csfBGA285", "caBGA256", "caBGA381", "caBGA554", "caBGA756"],
@@ -108,7 +108,7 @@
"max_row" : 71,
"max_col" : 90,
"col_bias" : 0,
- "fuzz": 1
+ "fuzz": 0
},
"LFE5UM5G-85F": {
"packages": ["csfBGA285", "caBGA381", "caBGA554", "caBGA756"],
@@ -120,6 +120,35 @@
"max_row" : 95,
"max_col" : 126,
"col_bias" : 0,
+ "fuzz": 0
+ }
+ }
+ },
+
+ "MachXO2" : {
+ "devices" : {
+ "LCMXO2-256HC": {
+ "packages": ["QFN32"],
+ "idcode": "0x012b8043",
+ "frames": 186,
+ "bits_per_frame": 504,
+ "pad_bits_after_frame": 0,
+ "pad_bits_before_frame": 0,
+ "max_row" : 7,
+ "max_col" : 9,
+ "col_bias" : 1,
+ "fuzz": 1
+ },
+ "LCMXO2-1200HC": {
+ "packages": ["QFN32"],
+ "idcode": "0x012ba043",
+ "frames": 333,
+ "bits_per_frame": 1080,
+ "pad_bits_after_frame": 0,
+ "pad_bits_before_frame": 0,
+ "max_row" : 12,
+ "max_col" : 21,
+ "col_bias" : 1,
"fuzz": 1
}
}
diff --git a/examples/tinyfpga_ax/.gitignore b/examples/tinyfpga_ax/.gitignore
new file mode 100644
index 0000000..26ec132
--- /dev/null
+++ b/examples/tinyfpga_ax/.gitignore
@@ -0,0 +1,7 @@
+*.dump
+*.twr
+*.txt
+*.ncl
+*.tmp
+*.jed
+*.hex
diff --git a/examples/tinyfpga_ax/Makefile b/examples/tinyfpga_ax/Makefile
new file mode 100644
index 0000000..140e6e4
--- /dev/null
+++ b/examples/tinyfpga_ax/Makefile
@@ -0,0 +1,48 @@
+PROJ ?= blinky
+TRELLIS_ROOT ?= ../..
+export DEV_PACKAGE ?= QFN32
+export JEDEC_BITSTREAM ?= 1
+export COMPRESSED_BITSTREAM ?= 1
+
+all: ${PROJ}.bit ${PROJ}-nextpnr.bit ${PROJ}.txt ${PROJ}-nextpnr.txt
+
+# Get proportion of known bits.
+stats:
+ @python3 -c "import sys; print(\"{:.3f}\".format(int(sys.argv[1]) / int(sys.argv[2])))" \
+ `grep -e arc -e word -e enum ${PROJ}.txt | wc -l` \
+ `grep -e arc -e word -e enum -e unknown ${PROJ}.txt | wc -l`
+
+# Avoid intermediate files from being deleted.
+.PRECIOUS: %.txt %.bit %-roundtrip.txt %-roundtrip.bit %-comp.txt %-comp-roundtrip.bit
+
+# Test that a bitstream from Diamond survives a round-trip from .bit to .txt
+# back to .bit and .txt again.
+%-roundtrip.bit: %.txt
+ ecppack --db ${TRELLIS_ROOT}/database $< $@
+
+%-comp-roundtrip.bit: %-comp.txt
+ ecppack --db ${TRELLIS_ROOT}/database --compress $< $@
+
+%.txt: %.bit
+ ecpunpack --db ${TRELLIS_ROOT}/database --input $< --textcfg $@
+
+# Diamond rules.
+%.bit: %.v %.lpf
+ ${TRELLIS_ROOT}/diamond.sh LCMXO2-1200HC ${PROJ}.v
+
+# FOSS rules.
+# yosys
+%.json: %.v %.lpf
+ @true
+
+# ecppack --db ${TRELLIS_ROOT}/database --input $< $@
+%-nextpnr.bit: %-nextpnr.txt
+ @true
+
+# nextpnr-generic
+${PROJ}-nextpnr.txt: ${PROJ}.json
+ @true
+
+clean:
+ rm -rf ${PROJ}.tmp ${PROJ}_out.ncl ${PROJ}*.bit ${PROJ}.jed ${PROJ}.dump \
+ ${PROJ}.twr ${PROJ}*.txt ${PROJ}.json ${PROJ}-nextpnr.* ${PROJ}*.hex
diff --git a/examples/tinyfpga_ax/blinky.lpf b/examples/tinyfpga_ax/blinky.lpf
new file mode 100644
index 0000000..18782c5
--- /dev/null
+++ b/examples/tinyfpga_ax/blinky.lpf
@@ -0,0 +1,3 @@
+BLOCK RESETPATHS ;
+BLOCK ASYNCPATHS ;
+LOCATE COMP "pin1" SITE "13" ;
diff --git a/examples/tinyfpga_ax/blinky.v b/examples/tinyfpga_ax/blinky.v
new file mode 100644
index 0000000..49ed054
--- /dev/null
+++ b/examples/tinyfpga_ax/blinky.v
@@ -0,0 +1,26 @@
+// Modified from:
+// https://github.com/tinyfpga/TinyFPGA-A-Series/tree/master/template_a2
+
+module TinyFPGA_A2 (
+ inout pin1
+);
+
+
+ wire clk;
+
+ OSCH #(
+ .NOM_FREQ("2.08")
+ ) internal_oscillator_inst (
+ .STDBY(1'b0),
+ .OSC(clk)
+ );
+
+ reg [23:0] led_timer;
+
+ always @(posedge clk) begin
+ led_timer <= led_timer + 1;
+ end
+
+ // left side of board
+ assign pin1 = led_timer[23];
+endmodule
diff --git a/examples/tinyfpga_ax/uart.lpf b/examples/tinyfpga_ax/uart.lpf
new file mode 100644
index 0000000..48e84d4
--- /dev/null
+++ b/examples/tinyfpga_ax/uart.lpf
@@ -0,0 +1,10 @@
+BLOCK RESETPATHS ;
+BLOCK ASYNCPATHS ;
+LOCATE COMP "serial_rx" SITE "13" ;
+LOCATE COMP "serial_tx" SITE "14" ;
+LOCATE COMP "user_led" SITE "16" ;
+LOCATE COMP "user_led_1" SITE "17" ;
+LOCATE COMP "user_led_2" SITE "20" ;
+LOCATE COMP "user_led_3" SITE "21" ;
+LOCATE COMP "user_led_4" SITE "23" ;
+LOCATE COMP "clk12" SITE "25" ;
diff --git a/examples/tinyfpga_ax/uart.v b/examples/tinyfpga_ax/uart.v
new file mode 100644
index 0000000..0d76baa
--- /dev/null
+++ b/examples/tinyfpga_ax/uart.v
@@ -0,0 +1,207 @@
+/* Example UART derived from: https://github.com/cr1901/migen_uart.
+ Requires 12MHz clock and runs at 19,200 baud. */
+
+/* Machine-generated using Migen */
+module top(
+ input serial_rx,
+ output serial_tx,
+ output user_led,
+ output user_led_1,
+ output user_led_2,
+ output user_led_3,
+ output user_led_4,
+ input clk12
+);
+
+wire [7:0] out_data;
+wire [7:0] in_data;
+wire tx;
+wire rx;
+reg wr = 1'd0;
+reg rd = 1'd0;
+wire tx_empty;
+wire rx_empty;
+wire tx_ov;
+wire rx_ov;
+wire sout_load;
+wire [7:0] sout_out_data;
+wire sout_shift;
+reg sout_empty = 1'd1;
+reg sout_overrun = 1'd0;
+reg [3:0] sout_count = 4'd0;
+reg [9:0] sout_reg = 10'd0;
+reg sout_tx;
+wire sin_rx;
+wire sin_shift;
+wire sin_take;
+reg [7:0] sin_in_data = 8'd0;
+wire sin_edge;
+reg sin_empty = 1'd1;
+reg sin_busy = 1'd0;
+reg sin_overrun = 1'd0;
+reg sin_sync_rx = 1'd0;
+reg [8:0] sin_reg = 9'd0;
+reg sin_rx_prev = 1'd0;
+reg [3:0] sin_count = 4'd0;
+wire out_active;
+wire in_active;
+reg shift_out_strobe = 1'd0;
+reg shift_in_strobe = 1'd0;
+reg [9:0] in_counter = 10'd0;
+reg [9:0] out_counter = 10'd0;
+wire sys_clk;
+wire sys_rst;
+wire por_clk;
+reg int_rst = 1'd1;
+
+
+// Adding a dummy event (using a dummy signal 'dummy_s') to get the simulator
+// to run the combinatorial process once at the beginning.
+// synthesis translate_off
+reg dummy_s;
+initial dummy_s <= 1'd0;
+// synthesis translate_on
+
+assign user_led_1 = (~serial_tx);
+assign user_led = (~serial_rx);
+assign user_led_2 = sout_load;
+assign user_led_3 = sin_take;
+assign user_led_4 = sin_empty;
+assign serial_tx = tx;
+assign rx = serial_rx;
+assign out_data = in_data;
+assign in_data = sin_in_data;
+assign sout_out_data = out_data;
+assign sin_take = rd;
+assign sout_load = wr;
+assign tx = sout_tx;
+assign sin_rx = rx;
+assign tx_empty = sout_empty;
+assign rx_empty = sin_empty;
+assign tx_ov = sout_overrun;
+assign rx_ov = sin_overrun;
+assign sout_shift = shift_out_strobe;
+assign sin_shift = shift_in_strobe;
+assign out_active = (~sout_empty);
+assign in_active = sin_busy;
+
+// synthesis translate_off
+reg dummy_d;
+// synthesis translate_on
+always @(*) begin
+ sout_tx <= 1'd0;
+ if (sout_empty) begin
+ sout_tx <= 1'd1;
+ end else begin
+ sout_tx <= sout_reg[0];
+ end
+// synthesis translate_off
+ dummy_d <= dummy_s;
+// synthesis translate_on
+end
+assign sin_edge = ((sin_rx_prev == 1'd1) & (sin_sync_rx == 1'd0));
+assign sys_clk = clk12;
+assign por_clk = clk12;
+assign sys_rst = int_rst;
+
+always @(posedge por_clk) begin
+ int_rst <= 1'd0;
+end
+
+always @(posedge sys_clk) begin
+ wr <= 1'd0;
+ rd <= 1'd0;
+ if ((~sin_empty)) begin
+ wr <= 1'd1;
+ rd <= 1'd1;
+ end
+ if (sout_load) begin
+ if (sout_empty) begin
+ sout_reg[0] <= 1'd0;
+ sout_reg[8:1] <= sout_out_data;
+ sout_reg[9] <= 1'd1;
+ sout_empty <= 1'd0;
+ sout_overrun <= 1'd0;
+ sout_count <= 1'd0;
+ end else begin
+ sout_overrun <= 1'd1;
+ end
+ end
+ if (((~sout_empty) & sout_shift)) begin
+ sout_reg[8:0] <= sout_reg[9:1];
+ sout_reg[9] <= 1'd0;
+ if ((sout_count == 4'd9)) begin
+ sout_empty <= 1'd1;
+ sout_count <= 1'd0;
+ end else begin
+ sout_count <= (sout_count + 1'd1);
+ end
+ end
+ sin_sync_rx <= sin_rx;
+ sin_rx_prev <= sin_sync_rx;
+ if (sin_take) begin
+ sin_empty <= 1'd1;
+ sin_overrun <= 1'd0;
+ end
+ if (((~sin_busy) & sin_edge)) begin
+ sin_busy <= 1'd1;
+ end
+ if ((sin_shift & sin_busy)) begin
+ sin_reg[8] <= sin_sync_rx;
+ sin_reg[7:0] <= sin_reg[8:1];
+ if ((sin_count == 4'd9)) begin
+ sin_in_data <= sin_reg[8:1];
+ sin_count <= 1'd0;
+ sin_busy <= 1'd0;
+ if ((~sin_empty)) begin
+ sin_overrun <= 1'd1;
+ end else begin
+ sin_empty <= 1'd0;
+ end
+ end else begin
+ sin_count <= (sin_count + 1'd1);
+ end
+ end
+ out_counter <= 1'd0;
+ in_counter <= 1'd0;
+ if (in_active) begin
+ shift_in_strobe <= 1'd0;
+ in_counter <= (in_counter + 1'd1);
+ if ((in_counter == 9'd311)) begin
+ shift_in_strobe <= 1'd1;
+ end
+ if ((in_counter == 10'd623)) begin
+ in_counter <= 1'd0;
+ end
+ end
+ if (out_active) begin
+ shift_out_strobe <= 1'd0;
+ out_counter <= (out_counter + 1'd1);
+ if ((out_counter == 10'd623)) begin
+ out_counter <= 1'd0;
+ shift_out_strobe <= 1'd1;
+ end
+ end
+ if (sys_rst) begin
+ wr <= 1'd0;
+ rd <= 1'd0;
+ sout_empty <= 1'd1;
+ sout_overrun <= 1'd0;
+ sout_count <= 4'd0;
+ sout_reg <= 10'd0;
+ sin_in_data <= 8'd0;
+ sin_empty <= 1'd1;
+ sin_busy <= 1'd0;
+ sin_overrun <= 1'd0;
+ sin_sync_rx <= 1'd0;
+ sin_reg <= 9'd0;
+ sin_rx_prev <= 1'd0;
+ sin_count <= 4'd0;
+ shift_out_strobe <= 1'd0;
+ shift_in_strobe <= 1'd0;
+ in_counter <= 10'd0;
+ out_counter <= 10'd0;
+ end
+end
+
+endmodule
diff --git a/experiments/machxo2/center_mux/center_mux.py b/experiments/machxo2/center_mux/center_mux.py
new file mode 100644
index 0000000..8f33455
--- /dev/null
+++ b/experiments/machxo2/center_mux/center_mux.py
@@ -0,0 +1,68 @@
+import diamond
+from string import Template
+import pytrellis
+import shutil
+import os
+
+device = "LCMXO2-1200HC"
+
+routes = [
+ ("R1C13_JCLK0", "R6C13_JPCLKCIBVIQT0"),
+ ("R6C13_JPCLKCIBVIQT0", "R6C13_PCLKCIBVIQT0"),
+ ("R6C13_PCLKCIBVIQT0", "R6C13_VPRXCLKI0"),
+ ("R6C13_VPRXCLKI0", "R6C13_CLKI0_DCC"),
+ ("R6C13_CLKI0_DCC", "R6C13_CLKO0_DCC"),
+ ("R6C13_CLKO0_DCC", "R6C13_VPRX0000"),
+ ("R6C13_VPRX0000", "R6C8_HPSX0000"),
+ ("R6C13_VPRX0000", "R6C18_HPSX0000"),
+ ("R6C13_JLPLLCLK1", "R6C13_VPRXCLKI0"),
+ ("R6C8_HPSX0000", "R6C10_CLKI0B_DCC"),
+ ("R6C10_CLKI0B_DCC", "R6C10_CLKO0B_DCC"),
+ ("R6C14_CLKI0B_DCC", "R6C14_CLKO0B_DCC"),
+ ("R6C13_JTCDIVX1", "R6C13_VPRXCLKI5"),
+ ("R6C13_PCLKCIBMID2", "R6C13_VPRXCLK60"),
+ ("R6C13_PCLKCIBMID3", "R6C13_VPRXCLK61"),
+ ("R6C13_PCLKCIBMID2", "R6C13_VPRXCLK71"),
+ ("R6C13_PCLKCIBMID3", "R6C13_VPRXCLK70")
+]
+
+def run_get_tiles(mux_driver, sink):
+ route = ""
+ if mux_driver != "":
+ route = "route\n\t\t\t" + mux_driver + "." + sink + ";"
+
+ with open("center_mux_template.ncl", "r") as inf:
+ with open("work/center_mux.ncl", "w") as ouf:
+ ouf.write(Template(inf.read()).substitute(route=route))
+ diamond.run(device, "work/center_mux.ncl")
+ bs = pytrellis.Bitstream.read_bit("work/center_mux.bit")
+ chip = bs.deserialise_chip()
+ return chip.tiles
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ shutil.rmtree("work", ignore_errors=True)
+ os.mkdir("work")
+ baseline = run_get_tiles("", "")
+
+ with open("center_mux_diff.txt", "w") as f:
+ for r in routes:
+ modified = run_get_tiles(r[0], r[1])
+
+ tile_keys = []
+ for t in modified:
+ tile_keys.append(t.key())
+
+ print("{0} -> {1}".format(r[0], r[1]), file=f)
+ for k in tile_keys:
+ diff = modified[k].cram - baseline[k].cram
+ diff_str = ["{}F{}B{}".format("!" if b.delta < 0 else "", b.frame, b.bit) for b in diff]
+ if not diff_str:
+ continue
+ print("{0: <30}{1}".format(k, " ".join(diff_str)), file=f)
+ f.flush()
+ print("", file=f)
+
+if __name__ == "__main__":
+ main()
diff --git a/experiments/machxo2/center_mux/center_mux_diff.txt b/experiments/machxo2/center_mux/center_mux_diff.txt
new file mode 100644
index 0000000..8adfd23
--- /dev/null
+++ b/experiments/machxo2/center_mux/center_mux_diff.txt
@@ -0,0 +1,47 @@
+R1C13_JCLK0 -> R6C13_JPCLKCIBVIQT0
+
+R6C13_JPCLKCIBVIQT0 -> R6C13_PCLKCIBVIQT0
+
+R6C13_PCLKCIBVIQT0 -> R6C13_VPRXCLKI0
+CENTER8:CENTER7 F25B0
+CENTER9:CENTER8 F0B0 F0B1 F1B1
+
+R6C13_VPRXCLKI0 -> R6C13_CLKI0_DCC
+
+R6C13_CLKI0_DCC -> R6C13_CLKO0_DCC
+
+R6C13_CLKO0_DCC -> R6C13_VPRX0000
+
+R6C13_VPRX0000 -> R6C8_HPSX0000
+CENTER6:CENTER_EBR_CIB F23B0
+
+R6C13_VPRX0000 -> R6C18_HPSX0000
+CENTER6:CENTER_EBR_CIB F23B1
+
+R6C13_JLPLLCLK1 -> R6C13_VPRXCLKI0
+CENTER8:CENTER7 F28B1
+CENTER9:CENTER8 F1B1
+
+R6C8_HPSX0000 -> R6C10_CLKI0B_DCC
+
+R6C10_CLKI0B_DCC -> R6C10_CLKO0B_DCC
+CIB_R6C10:CIB_EBR0 F26B31
+
+R6C14_CLKI0B_DCC -> R6C14_CLKO0B_DCC
+CIB_R6C14:CIB_EBR0 F26B31
+
+R6C13_JTCDIVX1 -> R6C13_VPRXCLKI5
+CENTER5:CENTER5 F25B0 F27B0
+
+R6C13_PCLKCIBMID2 -> R6C13_VPRXCLK60
+CENTER5:CENTER5 F25B0 F27B0
+
+R6C13_PCLKCIBMID3 -> R6C13_VPRXCLK61
+CENTER5:CENTER5 F25B0 F27B0
+
+R6C13_PCLKCIBMID2 -> R6C13_VPRXCLK71
+CENTER5:CENTER5 F25B0 F27B0
+
+R6C13_PCLKCIBMID3 -> R6C13_VPRXCLK70
+CENTER5:CENTER5 F25B0 F27B0
+
diff --git a/experiments/machxo2/center_mux/center_mux_template.ncl b/experiments/machxo2/center_mux/center_mux_template.ncl
new file mode 100644
index 0000000..3f9d75c
--- /dev/null
+++ b/experiments/machxo2/center_mux/center_mux_template.ncl
@@ -0,0 +1,35 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ [,,,,A0,B0,D0,C0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,]
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "K0::H0=0 "
+ "F0:F ";
+ primitive K0 i3_4_lut;
+ }
+ site R2C2A;
+ }
+
+ signal q_c
+ {
+ signal-pins
+ // drivers
+ (SLICE_0, F0),
+ // loads
+ (SLICE_0, CLK);
+ ${route}
+ }
+}
diff --git a/experiments/machxo2/findnets/findnets.py b/experiments/machxo2/findnets/findnets.py
new file mode 100644
index 0000000..e8d51ae
--- /dev/null
+++ b/experiments/machxo2/findnets/findnets.py
@@ -0,0 +1,75 @@
+import sys
+from collections import defaultdict
+
+from fuzzconfig import FuzzConfig
+import pytrellis
+import isptcl
+import argparse
+
+
+def net_mode(args):
+ pytrellis.load_database("../../../database")
+
+ cfg = FuzzConfig(job="FINDNETS_NETS_{}".format(args.nets[0]), family="MachXO2", device="LCMXO2-1200HC", ncl="plc2route.ncl", tiles=[])
+ cfg.setup()
+
+ arcs = isptcl.get_arcs_on_wires(cfg.ncd_prf, args.nets, False, defaultdict(lambda : str("mark")))
+
+ with open("{}_out.txt".format(args.nets[0]), "w") as fp:
+ for (k, v) in arcs.items():
+ print("{}:".format(k), file=fp)
+ for c in v:
+ if isinstance(c, isptcl.AmbiguousArc):
+ print(str(c), file=fp)
+ else:
+ print("{} --> {}".format(c[0], c[1]), file=fp)
+
+ fp.flush()
+ print("", file=fp)
+
+def pos_mode(args):
+ pytrellis.load_database("../../../database")
+
+ cfg = FuzzConfig(job="FINDNETS_R{}C{}".format(args.row, args.col), family="MachXO2", device="LCMXO2-1200HC", ncl="plc2route.ncl", tiles=[])
+ cfg.setup()
+
+ netdata = isptcl.get_wires_at_position(cfg.ncd_prf, (args.row, args.col))
+ netnames = [x[0] for x in netdata]
+ arcs = isptcl.get_arcs_on_wires(cfg.ncd_prf, netnames, False, defaultdict(lambda : str("mark")))
+
+ with open("r{}c{}_{}out.txt".format(args.row, args.col, "a_" if args.a else ""), "w") as fp:
+ for (k, v) in arcs.items():
+ print("{}:".format(k), file=fp)
+ for c in v:
+ if isinstance(c, isptcl.AmbiguousArc):
+ print(str(c), file=fp)
+ else:
+ if not args.a:
+ print("{} --> {}".format(c[0], c[1]), file=fp)
+
+ fp.flush()
+ print("", file=fp)
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Find which nets IspTcl returns in various ways.")
+ subparsers = parser.add_subparsers()
+
+ parser_pos = subparsers.add_parser("pos", help="Return all nets based on position.")
+ parser_net = subparsers.add_parser("net", help="Return connections to one (or more) nets.")
+
+ parser_pos.add_argument("-a", action="store_true", help="Return arcs with ambiguous direction only.")
+ parser_pos.add_argument("row", type=int, help="Tile row.")
+ parser_pos.add_argument("col", type=int, help="Tile column.")
+ parser_pos.set_defaults(func=pos_mode)
+
+ parser_net.add_argument("nets", type=str, nargs="+", help="List of nets to find connections.")
+ parser_net.set_defaults(func=net_mode)
+ args = parser.parse_args()
+
+ if len(args.__dict__) <= 1:
+ # No arguments or subcommands were given.
+ parser.print_help()
+ parser.exit()
+
+ args.func(args)
diff --git a/experiments/machxo2/findnets/plc2route.ncl b/experiments/machxo2/findnets/plc2route.ncl
new file mode 100644
index 0000000..7e7370b
--- /dev/null
+++ b/experiments/machxo2/findnets/plc2route.ncl
@@ -0,0 +1,35 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ [,,,,A0,B0,D0,C0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,]
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "K0::H0=0 "
+ "F0:F ";
+ primitive K0 i3_4_lut;
+ }
+ site R2C2A;
+ }
+
+ signal q_c
+ {
+ signal-pins
+ // drivers
+ (SLICE_0, F0),
+ // loads
+ (SLICE_0, A0);
+ ${route}
+ }
+}
diff --git a/experiments/machxo2/interconnect_poc/fuzz_single_mux.py b/experiments/machxo2/interconnect_poc/fuzz_single_mux.py
new file mode 100644
index 0000000..af81853
--- /dev/null
+++ b/experiments/machxo2/interconnect_poc/fuzz_single_mux.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python3
+
+import os
+from os import path
+import shutil
+
+import diamond
+from string import Template
+import pytrellis
+
+device = "LCMXO2-1200HC"
+sink = "R2C2_A0"
+# Drivers found using ispTcl
+drivers = [
+ "R1C2_V02S0501",
+ # "R2C2_H02W0501",
+ # "R2C2_H01E0001",
+ # "R2C3_H02W0701",
+ # "R2C3_H02W0501",
+ # "R2C2_H02W0701",
+ # "R2C2_H02E0501",
+ # "R3C2_V02N0501",
+ # "R1C2_V02S0701",
+ # "R2C2_F5",
+ # "R2C2_H00L0000",
+ # "R2C2_F7",
+ # "R2C2_H02E0701",
+ # "R2C2_V02N0701",
+ # "R2C1_H02E0701",
+ # "R2C3_H01E0001",
+ # "R2C2_V02S0501",
+ # "R3C2_V02N0701",
+ # "R2C2_V02S0701",
+ # "R2C2_V01N0101",
+ # "R2C2_V02N0501",
+ # "R2C1_H02E0501",
+ # "R2C2_H00L0100",
+ # "R2C2_H00R0000"
+]
+
+
+def run_get_bits(mux_driver):
+ route = ""
+ if mux_driver != "":
+ route = "route\n\t\t\t" + mux_driver + "." + sink + ";"
+ with open("mux_template.ncl", "r") as inf:
+ with open("work/mux.ncl", "w") as ouf:
+ ouf.write(Template(inf.read()).substitute(route=route))
+ diamond.run(device, "work/mux.ncl")
+ bs = pytrellis.Bitstream.read_bit("work/mux.bit")
+ chip = bs.deserialise_chip()
+ tile = chip.tiles["R2C2:PLC"]
+ return tile.cram
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ shutil.rmtree("work", ignore_errors=True)
+ os.mkdir("work")
+ baseline = run_get_bits("")
+ with open("a0_mux_out.txt", "w") as f:
+ for d in drivers:
+ bits = run_get_bits(d)
+ diff = bits - baseline
+ diff_str = ["{}F{}B{}".format("!" if b.delta < 0 else "", b.frame, b.bit) for b in diff]
+ print("{0: <18}{1}".format(d, " ".join(diff_str)), file=f)
+ f.flush()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/experiments/machxo2/interconnect_poc/mux_template.ncl b/experiments/machxo2/interconnect_poc/mux_template.ncl
new file mode 100644
index 0000000..7e7370b
--- /dev/null
+++ b/experiments/machxo2/interconnect_poc/mux_template.ncl
@@ -0,0 +1,35 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ [,,,,A0,B0,D0,C0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,]
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "K0::H0=0 "
+ "F0:F ";
+ primitive K0 i3_4_lut;
+ }
+ site R2C2A;
+ }
+
+ signal q_c
+ {
+ signal-pins
+ // drivers
+ (SLICE_0, F0),
+ // loads
+ (SLICE_0, A0);
+ ${route}
+ }
+}
diff --git a/experiments/machxo2/io_params/.gitignore b/experiments/machxo2/io_params/.gitignore
new file mode 100644
index 0000000..90d4bad
--- /dev/null
+++ b/experiments/machxo2/io_params/.gitignore
@@ -0,0 +1 @@
+*_diff.txt
diff --git a/experiments/machxo2/io_params/io_params.py b/experiments/machxo2/io_params/io_params.py
new file mode 100644
index 0000000..e865ef5
--- /dev/null
+++ b/experiments/machxo2/io_params/io_params.py
@@ -0,0 +1,65 @@
+import diamond
+from string import Template
+import pytrellis
+import shutil
+import os
+import argparse
+
+device = "LCMXO2-1200HC"
+
+def run_get_tiles(dir, io_type="LVCMOS33", loc="PB11D"):
+ with open("io_params_template.v", "r") as inf:
+ with open("work/io_params.v", "w") as ouf:
+ ouf.write(Template(inf.read()).substitute(dir=dir,
+ io_type="\"" + io_type + "\"", loc= "\"" + loc + "\""))
+ diamond.run(device, "work/io_params.v")
+ bs = pytrellis.Bitstream.read_bit("work/io_params.bit")
+ chip = bs.deserialise_chip()
+ return chip.tiles
+
+
+def main(args):
+ pytrellis.load_database("../../../database")
+ shutil.rmtree("work", ignore_errors=True)
+ os.mkdir("work")
+ os.environ['DEV_PACKAGE'] = args.p
+ baseline = run_get_tiles("NONE", args.io_type, args.loc)
+
+ dirs = []
+
+ if args.b:
+ dirs.append("BIDIR")
+ if args.i:
+ dirs.append("INPUT")
+ if args.o:
+ dirs.append("OUTPUT")
+
+ with open("io_params_diff.txt", "w") as f:
+ for d in dirs:
+ modified = run_get_tiles(d, args.io_type, args.loc)
+
+ tile_keys = []
+ for t in modified:
+ tile_keys.append(t.key())
+
+ print("{0}".format(d), file=f)
+ for k in tile_keys:
+ diff = modified[k].cram - baseline[k].cram
+ diff_str = ["{}F{}B{}".format("!" if b.delta < 0 else "", b.frame, b.bit) for b in diff]
+ if not diff_str:
+ continue
+ print("{0: <30}{1}".format(k, " ".join(diff_str)), file=f)
+ f.flush()
+ print("", file=f)
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Test I/O Sites.")
+ parser.add_argument("-b", help="Test bidirectional.", action="store_true")
+ parser.add_argument("-i", help="Test input.", action="store_true")
+ parser.add_argument("-o", help="Test output.", action="store_true")
+ parser.add_argument("-p", type=str, default="QFN32", help="Device package to test.")
+ parser.add_argument(dest="io_type", type=str, default="LVCMOS33", help="I/O standard to test.")
+ parser.add_argument(dest="loc", type=str, default="PB11D", help="Site to test.")
+ args = parser.parse_args()
+
+ main(args)
diff --git a/experiments/machxo2/io_params/io_params_template.v b/experiments/machxo2/io_params/io_params_template.v
new file mode 100644
index 0000000..e71f205
--- /dev/null
+++ b/experiments/machxo2/io_params/io_params_template.v
@@ -0,0 +1,68 @@
+`define ${dir}
+
+`ifdef NONE
+
+module top(input x);
+
+// Minimum legal empty module
+wire dummy;
+
+// Dummy load
+GSR gsr_i(.GSR(dummy));
+
+// Dummy source
+OSCH osc_i(.OSC(dummy));
+
+
+endmodule
+
+`else
+
+module top(inout pad);
+
+`ifdef BIDIR
+
+wire dummyo, dummyi;
+
+(* keep *)
+(* LOC=${loc} *)
+(* IO_TYPE=${io_type} *)
+
+BB b_b(.B(pad), .O(dummyo), .I(1'b1), .T(dummyi));
+
+// Dummy load
+GSR gsr_i(.GSR(dummyo));
+
+// Dummy source
+OSCH osc_i(.OSC(dummyi));
+
+`endif
+
+`ifdef INPUT
+
+wire dummyo;
+
+(* keep *)
+(* LOC=${loc} *)
+(* IO_TYPE=${io_type} *)
+
+IB i_b(.I(pad), .O(dummyo));
+
+// Dummy load
+GSR gsr_i(.GSR(dummyo));
+
+`endif
+
+`ifdef OUTPUT
+
+(* keep *)
+(* LOC=${loc} *)
+(* IO_TYPE=${io_type} *)
+
+OB o_b(.O(pad), .I(1'b1));
+
+`endif
+
+endmodule
+
+`endif
diff --git a/fuzzers/machxo2/001-plc2_routing/fuzzer.py b/fuzzers/machxo2/001-plc2_routing/fuzzer.py
new file mode 100644
index 0000000..b3f86cd
--- /dev/null
+++ b/fuzzers/machxo2/001-plc2_routing/fuzzer.py
@@ -0,0 +1,28 @@
+from fuzzconfig import FuzzConfig
+import interconnect
+import nets
+import pytrellis
+import re
+
+cfg = FuzzConfig(job="PLC2ROUTE", family="MachXO2", device="LCMXO2-1200HC", ncl="plc2route.ncl", tiles=["R5C10:PLC"])
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+
+ span1_re = re.compile(r'R\d+C\d+_[VH]01[NESWTLBR]\d{4}')
+
+ def nn_filter(net, netnames):
+ """ Match nets that are: in the tile according to Tcl, global nets, or span-1 nets that are accidentally
+ left out by Tcl"""
+ return net in netnames or nets.is_global(net) or span1_re.match(net)
+
+ interconnect.fuzz_interconnect(config=cfg, location=(5, 10),
+ netname_predicate=nn_filter,
+ netname_filter_union=True,
+ enable_span1_fix=True,
+ bias=1)
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/001-plc2_routing/plc2route.ncl b/fuzzers/machxo2/001-plc2_routing/plc2route.ncl
new file mode 100644
index 0000000..7e7370b
--- /dev/null
+++ b/fuzzers/machxo2/001-plc2_routing/plc2route.ncl
@@ -0,0 +1,35 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ [,,,,A0,B0,D0,C0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,]
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "K0::H0=0 "
+ "F0:F ";
+ primitive K0 i3_4_lut;
+ }
+ site R2C2A;
+ }
+
+ signal q_c
+ {
+ signal-pins
+ // drivers
+ (SLICE_0, F0),
+ // loads
+ (SLICE_0, A0);
+ ${route}
+ }
+}
diff --git a/fuzzers/machxo2/003-lut_init/empty.ncl b/fuzzers/machxo2/003-lut_init/empty.ncl
new file mode 100644
index 0000000..11b72ab
--- /dev/null
+++ b/fuzzers/machxo2/003-lut_init/empty.ncl
@@ -0,0 +1,12 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+}
diff --git a/fuzzers/machxo2/003-lut_init/fuzzer.py b/fuzzers/machxo2/003-lut_init/fuzzer.py
new file mode 100644
index 0000000..96d9983
--- /dev/null
+++ b/fuzzers/machxo2/003-lut_init/fuzzer.py
@@ -0,0 +1,46 @@
+from fuzzconfig import FuzzConfig
+import nonrouting
+import fuzzloops
+import nets
+import pytrellis
+import re
+
+cfg = FuzzConfig(job="PLC2INIT", family="MachXO2", device="LCMXO2-1200HC", ncl="empty.ncl", tiles=["R10C11:PLC"])
+
+
+def get_lut_function(init_bits):
+ sop_terms = []
+ lut_inputs = ["A", "B", "C", "D"]
+ for i in range(16):
+ if init_bits[i]:
+ p_terms = []
+ for j in range(4):
+ if i & (1 << j) != 0:
+ p_terms.append(lut_inputs[j])
+ else:
+ p_terms.append("~" + lut_inputs[j])
+ sop_terms.append("({})".format("*".join(p_terms)))
+ if len(sop_terms) == 0:
+ lut_func = "0"
+ else:
+ lut_func = "+".join(sop_terms)
+ return lut_func
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+ empty_bitfile = cfg.build_design(cfg.ncl, {})
+ cfg.ncl = "lut.ncl"
+
+ def per_slice(slicen):
+ for k in range(2):
+ def get_substs(bits):
+ return dict(slice=slicen, k=str(k), lut_func=get_lut_function(bits))
+ nonrouting.fuzz_word_setting(cfg, "SLICE{}.K{}.INIT".format(slicen, k), 16, get_substs, empty_bitfile)
+
+ fuzzloops.parallel_foreach(["A", "B", "C", "D"], per_slice)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/003-lut_init/lut.ncl b/fuzzers/machxo2/003-lut_init/lut.ncl
new file mode 100644
index 0000000..3f9fa20
--- /dev/null
+++ b/fuzzers/machxo2/003-lut_init/lut.ncl
@@ -0,0 +1,25 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "K${k}::H${k}=${lut_func} "
+ "F${k}:F ";
+ primitive K${k} i3_4_lut;
+ }
+ site R10C11${slice};
+ }
+
+}
diff --git a/fuzzers/machxo2/005-reg_config/empty.ncl b/fuzzers/machxo2/005-reg_config/empty.ncl
new file mode 100644
index 0000000..11b72ab
--- /dev/null
+++ b/fuzzers/machxo2/005-reg_config/empty.ncl
@@ -0,0 +1,12 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+}
diff --git a/fuzzers/machxo2/005-reg_config/fuzzer.py b/fuzzers/machxo2/005-reg_config/fuzzer.py
new file mode 100644
index 0000000..c332b6f
--- /dev/null
+++ b/fuzzers/machxo2/005-reg_config/fuzzer.py
@@ -0,0 +1,38 @@
+from fuzzconfig import FuzzConfig
+import nonrouting
+import fuzzloops
+import nets
+import pytrellis
+import re
+
+cfg = FuzzConfig(job="PLC2REG", family="MachXO2", device="LCMXO2-1200HC", ncl="empty.ncl", tiles=["R10C11:PLC"])
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+ empty_bitfile = cfg.build_design(cfg.ncl, {})
+ cfg.ncl = "reg.ncl"
+
+ def per_slice(slicen):
+ r = 0
+
+ def get_substs(regset="RESET", sd="0", gsr="DISABLED"):
+ return dict(slice=slicen, r=str(r), regset=regset, sd=sd, gsr=gsr)
+
+ for r in range(2):
+ nonrouting.fuzz_enum_setting(cfg, "SLICE{}.REG{}.REGSET".format(slicen, r), ["RESET", "SET"],
+ lambda x: get_substs(regset=x),
+ empty_bitfile)
+ nonrouting.fuzz_enum_setting(cfg, "SLICE{}.REG{}.SD".format(slicen, r), ["0", "1"],
+ lambda x: get_substs(sd=x),
+ empty_bitfile)
+ nonrouting.fuzz_enum_setting(cfg, "SLICE{}.GSR".format(slicen), ["DISABLED", "ENABLED"],
+ lambda x: get_substs(gsr=x),
+ empty_bitfile)
+
+ fuzzloops.parallel_foreach(["A", "B", "C", "D"], per_slice)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/005-reg_config/reg.ncl b/fuzzers/machxo2/005-reg_config/reg.ncl
new file mode 100644
index 0000000..a59a8b9
--- /dev/null
+++ b/fuzzers/machxo2/005-reg_config/reg.ncl
@@ -0,0 +1,31 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "REG${r}:::REGSET=${regset}:SD=${sd} "
+ "Q${r}:Q "
+ "GSR:${gsr} "
+ "CLKMUX:CLK "
+ "CEMUX:1 "
+ "LSRMUX:LSR "
+ "SRMODE:LSR_OVER_CE "
+ "M0MUX:M0 ";
+ primitive REG${r} q_6;
+ }
+ site R10C11${slice};
+ }
+
+}
diff --git a/fuzzers/machxo2/007-plc2_cemux/cemux.ncl b/fuzzers/machxo2/007-plc2_cemux/cemux.ncl
new file mode 100644
index 0000000..5619b2b
--- /dev/null
+++ b/fuzzers/machxo2/007-plc2_cemux/cemux.ncl
@@ -0,0 +1,31 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "REG0:::REGSET=RESET:SD=0 "
+ "Q0:Q "
+ "GSR:DISABLED "
+ "CLKMUX:CLK "
+ "CEMUX:${cemux} "
+ "LSRMUX:LSR "
+ "SRMODE:LSR_OVER_CE "
+ "M0MUX:M0 ";
+ primitive REG0 q_6;
+ }
+ site R10C11${slice};
+ }
+
+}
diff --git a/fuzzers/machxo2/007-plc2_cemux/empty.ncl b/fuzzers/machxo2/007-plc2_cemux/empty.ncl
new file mode 100644
index 0000000..11b72ab
--- /dev/null
+++ b/fuzzers/machxo2/007-plc2_cemux/empty.ncl
@@ -0,0 +1,12 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+}
diff --git a/fuzzers/machxo2/007-plc2_cemux/fuzzer.py b/fuzzers/machxo2/007-plc2_cemux/fuzzer.py
new file mode 100644
index 0000000..0916add
--- /dev/null
+++ b/fuzzers/machxo2/007-plc2_cemux/fuzzer.py
@@ -0,0 +1,32 @@
+from fuzzconfig import FuzzConfig
+import nonrouting
+import fuzzloops
+import nets
+import pytrellis
+import re
+
+cfg = FuzzConfig(job="PLC2REG", family="MachXO2", device="LCMXO2-1200HC", ncl="empty.ncl", tiles=["R10C11:PLC"])
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+ empty_bitfile = cfg.build_design(cfg.ncl, {})
+ cfg.ncl = "cemux.ncl"
+
+ def per_slice(slicen):
+ def get_substs(cemux):
+ if cemux == "INV":
+ cemux = "CE:::CE=#INV"
+ if cemux == "0":
+ cemux = "1:::1=0"
+ return dict(slice=slicen, cemux=cemux)
+ nonrouting.fuzz_enum_setting(cfg, "SLICE{}.CEMUX".format(slicen), ["0", "1", "CE", "INV"],
+ lambda x: get_substs(cemux=x),
+ empty_bitfile, False)
+
+ fuzzloops.parallel_foreach(["A", "B", "C", "D"], per_slice)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/008-plc2_clkmux/clkmux.ncl b/fuzzers/machxo2/008-plc2_clkmux/clkmux.ncl
new file mode 100644
index 0000000..7404fa8
--- /dev/null
+++ b/fuzzers/machxo2/008-plc2_clkmux/clkmux.ncl
@@ -0,0 +1,250 @@
+::FROM-WRITER;
+// designname: top
+// Creation time stamp: 01/31/20 05:21:54
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ // Writing 12 properties.
+ property
+ {
+ LSE_CPS_MAP_FILE string "xxx_lse_sign_file";
+ "PINNAME:0" string "clk";
+ "PINNAME:1" string "d";
+ "PINNAME:2" string "r";
+ "PINNAME:3" string "s";
+ "PINNAME:4" string "q";
+ "PINTYPE:0" string "IN";
+ "PINTYPE:1" string "IN";
+ "PINTYPE:2" string "IN";
+ "PINTYPE:3" string "IN";
+ "PINTYPE:4" string "OUT";
+ "SIGNAME:PUR" string "VCC_net";
+ } // End of property list.
+
+ // The Design macro definitions.
+ // The Design macro instances.
+ // The Design Comps.
+ comp SLICE_0
+ {
+
+ // Writing 2 properties.
+ property
+ {
+ LSE_CPS_ID_1 string "REG0";
+ NGID0 long 2;
+ } // End of property list.
+
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "REG0:::REGSET=SET:SD=0 "
+ "Q0:Q "
+ "GSR:ENABLED "
+ "CLKMUX:${clkmux} "
+ "CEMUX:1:::1=0 "
+ "LSRMUX:LSR "
+ "SRMODE:LSR_OVER_CE "
+ "LSRONMUX:LSRMUX "
+ "M0MUX:M0 "
+ "REGMODE:FF ";
+ primitive REG0 ff;
+ }
+ site R10C6${c};
+ }
+ comp d
+ {
+
+ // Writing 3 properties.
+ property
+ {
+ "#%PAD%PINID" long 1;
+ LSE_CPS_ID_2 string "IOBUF";
+ NGID0 long 3;
+ } // End of property list.
+
+ logical
+ {
+ cellmodel-name PIO;
+ program "PADDI:PADDI "
+ "IOBUF:::PULLMODE=DOWN,CLAMP=ON "
+ "VREF:OFF "
+ "PGMUX:INBUF "
+ "INRDMUX:PGMUX ";
+ primitive IOBUF d_pad;
+ primitive PAD d;
+ }
+ site "10";
+ }
+ comp q
+ {
+
+ // Writing 3 properties.
+ property
+ {
+ "#%PAD%PINID" long 4;
+ LSE_CPS_ID_3 string "IOBUF";
+ NGID0 long 4;
+ } // End of property list.
+
+ logical
+ {
+ cellmodel-name PIO;
+ program "TRIMUX:PADDT:::PADDT=0 "
+ "IOBUF:::PULLMODE=DOWN,DRIVE=8, \"
+ "SLEWRATE=SLOW,HYSTERESIS=NA "
+ "DATAMUX:PADDO "
+ "VREF:OFF "
+ "ODMUX:TRIMUX "
+ "LVDSMUX:DATAMUX ";
+ primitive IOBUF q_pad;
+ primitive PAD q;
+ }
+ site "9";
+ }
+ comp r
+ {
+
+ // Writing 3 properties.
+ property
+ {
+ "#%PAD%PINID" long 2;
+ LSE_CPS_ID_5 string "IOBUF";
+ NGID0 long 6;
+ } // End of property list.
+
+ logical
+ {
+ cellmodel-name PIO;
+ program "PADDI:PADDI "
+ "IOBUF:::PULLMODE=DOWN,CLAMP=ON "
+ "VREF:OFF "
+ "PGMUX:INBUF "
+ "INRDMUX:PGMUX ";
+ primitive IOBUF r_pad;
+ primitive PAD r;
+ }
+ site "28";
+ }
+ comp s
+ {
+
+ // Writing 3 properties.
+ property
+ {
+ "#%PAD%PINID" long 3;
+ LSE_CPS_ID_6 string "IOBUF";
+ NGID0 long 7;
+ } // End of property list.
+
+ logical
+ {
+ cellmodel-name PIO;
+ program "PADDI:PADDI "
+ "IOBUF:::PULLMODE=DOWN,CLAMP=ON "
+ "VREF:OFF "
+ "PGMUX:INBUF "
+ "INRDMUX:PGMUX ";
+ primitive IOBUF s_pad;
+ primitive PAD s;
+ }
+ site "8";
+ }
+ comp GSR_INST
+ {
+
+ // Writing 2 properties.
+ property
+ {
+ LSE_CPS_ID_4 string "GSR";
+ NGID0 long 5;
+ } // End of property list.
+
+ logical
+ {
+ cellmodel-name GSR;
+ program "GSRMODE:ACTIVE_LOW "
+ "SYNCMODE:ASYNC ";
+ }
+ site GSR;
+ }
+ // The Design Signals.
+ signal d_c
+ {
+ signal-pins
+ // drivers
+ (d, PADDI),
+ // loads
+ (SLICE_0, M0);
+ route
+ R10C6_H00L0200.R10C6_M0,
+ R10C6_V02N0301.R10C6_H00L0200,
+ R11C6_JQ3.R10C6_V02N0301,
+ R12C6_JDID.R11C6_JQ3,
+ R10C6_M0.R10C6_M0_SLICE,
+ R12C6_JPADDID_PIO.R12C6_JDID;
+ }
+ signal s_c
+ {
+ signal-pins
+ // drivers
+ (s, PADDI),
+ // loads
+ (SLICE_0, LSR);
+ route
+ R10C6_V00T0100.R10C6_LSR0,
+ R10C5_H02E0401.R10C6_V00T0100,
+ R10C4_V01N0101.R10C5_H02E0401,
+ R11C4_JQ2.R10C4_V01N0101,
+ R12C4_JDIC.R11C4_JQ2,
+ R10C6_LSR0.R10C6_LSR0_SLICE,
+ R12C4_JPADDIC_PIO.R12C4_JDIC;
+ }
+ signal q_c
+ {
+
+ // Writing 1 properties.
+ property
+ {
+ TW_IS_CONST_SIG boolean true;
+ } // End of property list.
+
+ signal-pins
+ // drivers
+ (SLICE_0, Q0),
+ // loads
+ (q, PADDO);
+ route
+ R11C6_V02N0701.R11C6_JA2,
+ R11C6_V02N0701.R11C6_V02S0700,
+ R10C6_V01S0100.R11C6_V02S0700,
+ R10C6_Q0.R10C6_V01S0100,
+ R11C6_JA2.R12C6_JPADDOC,
+ R12C6_JPADDOC.R12C6_PADDOC_PIO,
+ R10C6_Q0_SLICE.R10C6_Q0;
+ }
+ signal r_c
+ {
+ signal-pins
+ // drivers
+ (r, PADDI),
+ // loads
+ (GSR_INST, GSR);
+ route
+ R1C6_H00R0300.R1C6_JC4,
+ R1C6_V02S0101.R1C6_H00R0300,
+ R1C6_V02N0100.R1C6_V02S0101,
+ R1C9_H06W0103.R1C6_V02N0100,
+ R1C12_JQ2.R1C9_H06W0103,
+ R0C12_JDIC.R1C12_JQ2,
+ R1C6_JC4.R1C4_JGSR_GSR,
+ R0C12_JPADDIC_PIO.R0C12_JDIC;
+ }
+}
diff --git a/fuzzers/machxo2/008-plc2_clkmux/empty.ncl b/fuzzers/machxo2/008-plc2_clkmux/empty.ncl
new file mode 100644
index 0000000..11b72ab
--- /dev/null
+++ b/fuzzers/machxo2/008-plc2_clkmux/empty.ncl
@@ -0,0 +1,12 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+}
diff --git a/fuzzers/machxo2/008-plc2_clkmux/fuzzer.py b/fuzzers/machxo2/008-plc2_clkmux/fuzzer.py
new file mode 100644
index 0000000..11b998a
--- /dev/null
+++ b/fuzzers/machxo2/008-plc2_clkmux/fuzzer.py
@@ -0,0 +1,38 @@
+from fuzzconfig import FuzzConfig
+import nonrouting
+import fuzzloops
+import nets
+import pytrellis
+import re
+
+cfg = FuzzConfig(job="PLC2REG", family="MachXO2", device="LCMXO2-1200HC", ncl="empty.ncl", tiles=["R10C6:PLC"])
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+ empty_bitfile = cfg.build_design(cfg.ncl, {})
+ cfg.ncl = "clkmux.ncl"
+
+ def per_clk(clkn):
+ slices = { "0" : "A",
+ "1" : "B",
+ "2" : "C",
+ "3" : "D"
+ }
+
+ def get_substs(clkmux):
+ if clkmux == "INV":
+ clkmux = "CLK:::CLK=#INV"
+ if clkmux == "1":
+ clkmux = "0:::0=1"
+ return dict(c=slices[clkn], clkmux=clkmux)
+ nonrouting.fuzz_enum_setting(cfg, "CLK{}.CLKMUX".format(clkn), ["CLK", "INV", "0", "1"],
+ lambda x: get_substs(clkmux=x),
+ empty_bitfile, True)
+
+ fuzzloops.parallel_foreach(["0", "1", "2", "3"], per_clk)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/009-plc2_lsr/empty.ncl b/fuzzers/machxo2/009-plc2_lsr/empty.ncl
new file mode 100644
index 0000000..11b72ab
--- /dev/null
+++ b/fuzzers/machxo2/009-plc2_lsr/empty.ncl
@@ -0,0 +1,12 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+}
diff --git a/fuzzers/machxo2/009-plc2_lsr/fuzzer.py b/fuzzers/machxo2/009-plc2_lsr/fuzzer.py
new file mode 100644
index 0000000..3dd6127
--- /dev/null
+++ b/fuzzers/machxo2/009-plc2_lsr/fuzzer.py
@@ -0,0 +1,41 @@
+from fuzzconfig import FuzzConfig
+import nonrouting
+import fuzzloops
+import nets
+import pytrellis
+import re
+
+cfg = FuzzConfig(job="PLC2REG", family="MachXO2", device="LCMXO2-1200HC", ncl="empty.ncl", tiles=["R10C6:PLC"])
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+ empty_bitfile = cfg.build_design(cfg.ncl, {})
+ cfg.ncl = "lsr.ncl"
+
+ def per_lsr(lsrn):
+ slices = { "0" : "A",
+ "1" : "B",
+ "2" : "C",
+ "3" : "D"
+ }
+
+ def get_substs(lsrmux="LSR", srmode="LSR_OVER_CE", lsronmux="0"):
+ if lsrmux == "INV":
+ lsrmux = "LSR:::LSR=#INV"
+ return dict(s=slices[lsrn], l=lsrn, lsrmux=lsrmux, srmode=srmode, lsronmux=lsronmux)
+ nonrouting.fuzz_enum_setting(cfg, "LSR{}.LSRMUX".format(lsrn), ["LSR", "INV"],
+ lambda x: get_substs(lsrmux=x),
+ empty_bitfile, True)
+ nonrouting.fuzz_enum_setting(cfg, "LSR{}.SRMODE".format(lsrn), ["LSR_OVER_CE", "ASYNC"],
+ lambda x: get_substs(srmode=x),
+ empty_bitfile, True)
+ nonrouting.fuzz_enum_setting(cfg, "LSR{}.LSRONMUX".format(lsrn), ["0", "LSRMUX"],
+ lambda x: get_substs(lsronmux=x),
+ empty_bitfile, True)
+ fuzzloops.parallel_foreach(["0", "1", "2", "3"], per_lsr)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/009-plc2_lsr/lsr.ncl b/fuzzers/machxo2/009-plc2_lsr/lsr.ncl
new file mode 100644
index 0000000..8bd295a
--- /dev/null
+++ b/fuzzers/machxo2/009-plc2_lsr/lsr.ncl
@@ -0,0 +1,58 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "REG0:::REGSET=RESET:SD=0 "
+ "Q0:Q "
+ "GSR:DISABLED "
+ "CLKMUX:CLK "
+ "CEMUX:CE "
+ "LSRMUX:${lsrmux} "
+ "SRMODE:${srmode} "
+ "LSRONMUX:${lsronmux} "
+ "M0MUX:M0 ";
+ primitive REG0 q_6;
+ }
+ site R10C6${s};
+ }
+
+ comp lsr
+ {
+ logical
+ {
+ cellmodel-name PIO;
+ program "PADDI:PADDI "
+ "IOBUF:::PULLMODE=DOWN,CLAMP=ON "
+ "VREF:OFF "
+ "PGMUX:INBUF "
+ "INRDMUX:PGMUX ";
+ primitive IOBUF lsr_pad;
+ primitive PAD lsr;
+ }
+ site "13";
+ }
+
+ signal lsrc_c
+ {
+ signal-pins
+ // drivers
+ (lsr, PADDI),
+ // loads
+ (SLICE_0, LSR);
+ route
+ R10C6_LSR${l}.R10C6_LSR${l}_SLICE;
+ }
+}
diff --git a/fuzzers/machxo2/010-plc2_modes/empty.ncl b/fuzzers/machxo2/010-plc2_modes/empty.ncl
new file mode 100644
index 0000000..11b72ab
--- /dev/null
+++ b/fuzzers/machxo2/010-plc2_modes/empty.ncl
@@ -0,0 +1,12 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+}
diff --git a/fuzzers/machxo2/010-plc2_modes/fuzzer.py b/fuzzers/machxo2/010-plc2_modes/fuzzer.py
new file mode 100644
index 0000000..0eabba4
--- /dev/null
+++ b/fuzzers/machxo2/010-plc2_modes/fuzzer.py
@@ -0,0 +1,34 @@
+from fuzzconfig import FuzzConfig
+import nonrouting
+import fuzzloops
+import nets
+import pytrellis
+import re
+
+cfg = FuzzConfig(job="PLC2MODE", family="MachXO2", device="LCMXO2-1200HC", ncl="empty.ncl", tiles=["R10C11:PLC"])
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+ empty_bitfile = cfg.build_design(cfg.ncl, {})
+ cfg.ncl = "modes.ncl"
+
+ def per_slice(slicen):
+ def get_substs(mode):
+ return dict(slice=slicen, mode=mode)
+ if slicen == "A" or slicen == "B":
+ modes = ["LOGIC", "CCU2", "DPRAM"]
+ elif slicen == "C":
+ modes = ["LOGIC", "CCU2", "RAMW"]
+ else:
+ modes = ["LOGIC", "CCU2"]
+ nonrouting.fuzz_enum_setting(cfg, "SLICE{}.MODE".format(slicen), modes,
+ lambda x: get_substs(mode=x),
+ empty_bitfile, False)
+
+ fuzzloops.parallel_foreach(["A", "B", "C", "D"], per_slice)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/010-plc2_modes/modes.ncl b/fuzzers/machxo2/010-plc2_modes/modes.ncl
new file mode 100644
index 0000000..8780d07
--- /dev/null
+++ b/fuzzers/machxo2/010-plc2_modes/modes.ncl
@@ -0,0 +1,23 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:${mode} ";
+ primitive REG0 q_6;
+ }
+ site R10C11${slice};
+ }
+
+}
diff --git a/fuzzers/machxo2/011-ccu2_inject/ccu2.ncl b/fuzzers/machxo2/011-ccu2_inject/ccu2.ncl
new file mode 100644
index 0000000..bbb520f
--- /dev/null
+++ b/fuzzers/machxo2/011-ccu2_inject/ccu2.ncl
@@ -0,0 +1,26 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:CCU2 "
+ "CCU2::S0=0x9009,S1=0x9009:INJECT1_0=${ij1_0}, \"
+ "INJECT1_1=${ij1_1} "
+ "FCO:FCO ";
+ primitive CCU2 "CCU";
+ }
+ site R10C11${slice};
+ }
+
+}
diff --git a/fuzzers/machxo2/011-ccu2_inject/empty.ncl b/fuzzers/machxo2/011-ccu2_inject/empty.ncl
new file mode 100644
index 0000000..11b72ab
--- /dev/null
+++ b/fuzzers/machxo2/011-ccu2_inject/empty.ncl
@@ -0,0 +1,12 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+}
diff --git a/fuzzers/machxo2/011-ccu2_inject/fuzzer.py b/fuzzers/machxo2/011-ccu2_inject/fuzzer.py
new file mode 100644
index 0000000..2b68724
--- /dev/null
+++ b/fuzzers/machxo2/011-ccu2_inject/fuzzer.py
@@ -0,0 +1,30 @@
+from fuzzconfig import FuzzConfig
+import nonrouting
+import fuzzloops
+import nets
+import pytrellis
+import re
+
+cfg = FuzzConfig(job="PLC2MODE", family="MachXO2", device="LCMXO2-1200HC", ncl="empty.ncl", tiles=["R10C11:PLC"])
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+ empty_bitfile = cfg.build_design(cfg.ncl, {})
+ cfg.ncl = "ccu2.ncl"
+
+ def per_slice(slicen):
+ def get_substs(ij1_0="YES", ij1_1="YES"):
+ return dict(slice=slicen, ij1_0=ij1_0, ij1_1=ij1_1)
+ nonrouting.fuzz_enum_setting(cfg, "SLICE{}.CCU2.INJECT1_0".format(slicen), ["YES", "NO"],
+ lambda x: get_substs(ij1_0=x),
+ empty_bitfile, True)
+ nonrouting.fuzz_enum_setting(cfg, "SLICE{}.CCU2.INJECT1_1".format(slicen), ["YES", "NO"],
+ lambda x: get_substs(ij1_1=x),
+ empty_bitfile, True)
+ fuzzloops.parallel_foreach(["A", "B", "C", "D"], per_slice)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/012-ccu2_nmux/ccu2.ncl b/fuzzers/machxo2/012-ccu2_nmux/ccu2.ncl
new file mode 100644
index 0000000..12a8af9
--- /dev/null
+++ b/fuzzers/machxo2/012-ccu2_nmux/ccu2.ncl
@@ -0,0 +1,25 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:CCU2 "
+ "CCU2::S0=0xfaaa,S1=0xfaaa${muxcfg}"
+ "FCO:FCO ";
+ primitive CCU2 "CCU";
+ }
+ site R10C11${slice};
+ }
+
+}
diff --git a/fuzzers/machxo2/012-ccu2_nmux/empty.ncl b/fuzzers/machxo2/012-ccu2_nmux/empty.ncl
new file mode 100644
index 0000000..11b72ab
--- /dev/null
+++ b/fuzzers/machxo2/012-ccu2_nmux/empty.ncl
@@ -0,0 +1,12 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+}
diff --git a/fuzzers/machxo2/012-ccu2_nmux/fuzzer.py b/fuzzers/machxo2/012-ccu2_nmux/fuzzer.py
new file mode 100644
index 0000000..dedfc85
--- /dev/null
+++ b/fuzzers/machxo2/012-ccu2_nmux/fuzzer.py
@@ -0,0 +1,39 @@
+from fuzzconfig import FuzzConfig
+import nonrouting
+import fuzzloops
+import nets
+import pytrellis
+import re
+
+# At present, I don't believe this affects any bits. Keeping this around
+# just in case I figure out I'm wrong...
+
+cfg = FuzzConfig(job="PLC2NMUX", family="MachXO2", device="LCMXO2-1200HC", ncl="empty.ncl", tiles=["R10C11:PLC"])
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+ empty_bitfile = cfg.build_design(cfg.ncl, {})
+ cfg.ncl = "ccu2.ncl"
+
+ def per_slice(slicen):
+ def get_substs(sig="A0", conn="A0"):
+ subs = {"slice": slicen}
+ if conn == "0":
+ # subs["muxcfg"] = "::{}=0".format(sig)
+ subs["muxcfg"] = "::A0=0,A1=0,B0=0,B1=0,C0=0,C1=0,D0=0,D1=0"
+ else:
+ subs["muxcfg"] = ""
+ return subs
+ # for sig in ["A0", "A1", "B0", "B1", "C0", "C1", "D0", "D1"]:
+ for sig in ["A0"]:
+ nonrouting.fuzz_enum_setting(cfg, "SLICE{}.{}MUX".format(slicen, sig), [sig, "0"],
+ lambda x: get_substs(sig=sig, conn=x),
+ empty_bitfile, False)
+ # fuzzloops.parallel_foreach(["A", "B", "C", "D"], per_slice)
+ fuzzloops.parallel_foreach(["A"], per_slice)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/013-plc2_mkmux/empty.ncl b/fuzzers/machxo2/013-plc2_mkmux/empty.ncl
new file mode 100644
index 0000000..11b72ab
--- /dev/null
+++ b/fuzzers/machxo2/013-plc2_mkmux/empty.ncl
@@ -0,0 +1,12 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+}
diff --git a/fuzzers/machxo2/013-plc2_mkmux/fuzzer.py b/fuzzers/machxo2/013-plc2_mkmux/fuzzer.py
new file mode 100644
index 0000000..9db7f55
--- /dev/null
+++ b/fuzzers/machxo2/013-plc2_mkmux/fuzzer.py
@@ -0,0 +1,32 @@
+from fuzzconfig import FuzzConfig
+import nonrouting
+import fuzzloops
+import nets
+import pytrellis
+import re
+
+# No evidence this affects any bits.
+
+cfg = FuzzConfig(job="PLC2MKMUX", family="MachXO2", device="LCMXO2-1200HC", ncl="empty.ncl", tiles=["R10C11:PLC"])
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+ empty_bitfile = cfg.build_design(cfg.ncl, {})
+ cfg.ncl = "mkmux.ncl"
+
+ def per_slice(slicen):
+ def get_substs(m0mux="M0", m1mux="M1"):
+ return dict(slice=slicen, m0mux=m0mux, m1mux=m1mux)
+ nonrouting.fuzz_enum_setting(cfg, "SLICE{}.M0MUX".format(slicen), ["M0", "0"],
+ lambda x: get_substs(m0mux=x),
+ empty_bitfile, False)
+ nonrouting.fuzz_enum_setting(cfg, "SLICE{}.M1MUX".format(slicen), ["M1", "0"],
+ lambda x: get_substs(m1mux=x),
+ empty_bitfile, False)
+ fuzzloops.parallel_foreach(["A", "B", "C", "D"], per_slice)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/013-plc2_mkmux/mkmux.ncl b/fuzzers/machxo2/013-plc2_mkmux/mkmux.ncl
new file mode 100644
index 0000000..c553eb0
--- /dev/null
+++ b/fuzzers/machxo2/013-plc2_mkmux/mkmux.ncl
@@ -0,0 +1,32 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "REG0:::REGSET=RESET:SD=0 "
+ "Q0:Q "
+ "GSR:DISABLED "
+ "CLKMUX:CLK "
+ "CEMUX:1 "
+ "LSRMUX:LSR "
+ "SRMODE:LSR_OVER_CE "
+ "M0MUX:${m0mux} "
+ "M1MUX:${m1mux} ";
+ primitive REG0 q_6;
+ }
+ site R10C11${slice};
+ }
+
+}
diff --git a/fuzzers/machxo2/014-plc2_wremux/empty.ncl b/fuzzers/machxo2/014-plc2_wremux/empty.ncl
new file mode 100644
index 0000000..11b72ab
--- /dev/null
+++ b/fuzzers/machxo2/014-plc2_wremux/empty.ncl
@@ -0,0 +1,12 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+}
diff --git a/fuzzers/machxo2/014-plc2_wremux/fuzzer.py b/fuzzers/machxo2/014-plc2_wremux/fuzzer.py
new file mode 100644
index 0000000..cff8b36
--- /dev/null
+++ b/fuzzers/machxo2/014-plc2_wremux/fuzzer.py
@@ -0,0 +1,33 @@
+from fuzzconfig import FuzzConfig
+import nonrouting
+import fuzzloops
+import nets
+import pytrellis
+import re
+
+cfg = FuzzConfig(job="PLC2WRE", family="MachXO2", device="LCMXO2-1200HC", ncl="empty.ncl", tiles=["R10C11:PLC"])
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+ empty_bitfile = cfg.build_design(cfg.ncl, {})
+ cfg.ncl = "wremux.ncl"
+
+ def per_slice(slicen):
+ def get_substs(wremux):
+ if wremux == "INV":
+ wremux = "WRE:::WRE=#INV"
+ if wremux == "1":
+ wremux = "0:::0=1"
+ return dict(slice=slicen, wremux=wremux)
+ nonrouting.fuzz_enum_setting(cfg, "SLICE{}.WREMUX".format(slicen), ["0", "1", "WRE", "INV"],
+ lambda x: get_substs(wremux=x),
+ empty_bitfile, False)
+
+ # B also has a WREMUX signal, but the same bit as A controls it.
+ fuzzloops.parallel_foreach(["A"], per_slice)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/014-plc2_wremux/wremux.ncl b/fuzzers/machxo2/014-plc2_wremux/wremux.ncl
new file mode 100644
index 0000000..3eedbb6
--- /dev/null
+++ b/fuzzers/machxo2/014-plc2_wremux/wremux.ncl
@@ -0,0 +1,25 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:DPRAM "
+ "DPRAM::DO0=0x0000,DO1=0x0000 "
+ "WREMUX:${wremux} ";
+ primitive DPRAM q_6;
+ }
+ site R10C11${slice};
+ }
+
+}
diff --git a/fuzzers/machxo2/020-center-mux/center-mux.ncl b/fuzzers/machxo2/020-center-mux/center-mux.ncl
new file mode 100644
index 0000000..3f9d75c
--- /dev/null
+++ b/fuzzers/machxo2/020-center-mux/center-mux.ncl
@@ -0,0 +1,35 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ [,,,,A0,B0,D0,C0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,]
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "K0::H0=0 "
+ "F0:F ";
+ primitive K0 i3_4_lut;
+ }
+ site R2C2A;
+ }
+
+ signal q_c
+ {
+ signal-pins
+ // drivers
+ (SLICE_0, F0),
+ // loads
+ (SLICE_0, CLK);
+ ${route}
+ }
+}
diff --git a/fuzzers/machxo2/020-center-mux/fuzzer.py b/fuzzers/machxo2/020-center-mux/fuzzer.py
new file mode 100644
index 0000000..6b44032
--- /dev/null
+++ b/fuzzers/machxo2/020-center-mux/fuzzer.py
@@ -0,0 +1,54 @@
+from collections import defaultdict
+
+from fuzzconfig import FuzzConfig
+import interconnect
+import nets
+import pytrellis
+import re
+import mk_nets
+
+jobs = [
+ # Global mux connections. The relevant tiles were inferred from the
+ # center_mux experiment.
+ ("fixed", FuzzConfig(job="GLOBAL_MUX", family="MachXO2", device="LCMXO2-1200HC", ncl="center-mux.ncl",
+ tiles=["CENTER9:CENTER8", "CENTER8:CENTER7", "CENTER7:CENTER6",
+ "CENTER6:CENTER_EBR_CIB", "CENTER5:CENTER5"])),
+
+ # ("ignored", FuzzConfig(job="GLOBAL_MUX", family="MachXO2", device="LCMXO2-1200HC", ncl="center-mux.ncl",
+ # tiles=["CENTER6:CENTER_EBR_CIB", "CENTER5:CENTER5", "CENTER4:CENTER4"])),
+
+ # Fixed connections within the global mux (as well as
+ # direction select).
+ ("muxed", FuzzConfig(job="GLOBAL_FIXED", family="MachXO2", device="LCMXO2-1200HC", ncl="center-mux.ncl",
+ tiles=["CENTER6:CENTER_EBR_CIB"])),
+]
+
+
+def main():
+ pytrellis.load_database("../../../database")
+
+ for job in jobs:
+ net_id, cfg = job
+ cfg.setup()
+
+ netnames = mk_nets.nets[net_id]
+ interconnect.fuzz_interconnect_with_netnames(config=cfg, netnames=netnames,
+ netname_filter_union=False,
+ netdir_override=defaultdict(lambda : str("sink")),
+ bias=1)
+
+ # TODO: R6C13_JA0 --> R6C13_JCE0_DCC. But TCL also claims
+ # R6C13_CLKI0_DCC --> R6C13_CLKO0_DCC (pseudo = 1). Contradiction?
+ # From talking to Dave: No it's not a contradiction. A
+ # config bit controls whether JCE0 has any effect.
+ # interconnect.fuzz_interconnect_with_netnames(config=cfg, netnames=["R6C13_CLKI0_DCC", "R6C13_CLKO0_DCC", "R6C13_JCE0_DCC"],
+ # netname_filter_union=False,
+ # netdir_override = {
+ # "R6C13_JCE0_DCC" : "sink",
+ # },
+ # full_mux_style=True,
+ # bias=1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/020-center-mux/mk_nets.py b/fuzzers/machxo2/020-center-mux/mk_nets.py
new file mode 100644
index 0000000..b7d0119
--- /dev/null
+++ b/fuzzers/machxo2/020-center-mux/mk_nets.py
@@ -0,0 +1,114 @@
+from nets import net_product
+
+templates = {
+ "fixed": [
+ # Some inputs to the center MUX are two nets concatenated together; the
+ # "first" net is a sink from locations throughout the FPGA, the
+ # "second" is the actual input to the center MUX. They should all
+ # become fixed connections, but fuzz _just_ in case.
+ (["R6C13_JPCLKCIBLLQ{0}",
+ "R6C13_JPCLKCIBLRQ{0}",
+ "R6C13_JPCLKCIBVIQB{0}",
+ "R6C13_JECLKCIBB{0}",
+ "R6C13_JECLKCIBT{0}",
+ "R6C13_JPCLKCIBVIQT{0}"], range(2)),
+ (["R6C13_JPCLKCIBMID{0}"], range(2, 4)),
+
+ # The "second" net of the concatenated inputs.
+ (["R6C13_PCLKCIBLLQ{0}",
+ "R6C13_PCLKCIBLRQ{0}",
+ "R6C13_PCLKCIBVIQB{0}",
+ "R6C13_ECLKCIBB{0}",
+ "R6C13_ECLKCIBT{0}",
+ "R6C13_PCLKCIBVIQT{0}"], range(2)),
+ (["R6C13_PCLKCIBMID{0}"], range(2, 4)),
+
+ # All other inputs which are _not_ concatenations of two nets.
+ (["R6C13_JSNETCIBMID{0}"], range(8)),
+ (["R6C13_JPCLKT2{0}",
+ "R6C13_JBCDIVX{0}",
+ "R6C13_JBCDIV1{0}",
+ "R6C13_JTCDIVX{0}",
+ "R6C13_JTCDIV1{0}",
+ "R6C13_JPCLKT0{0}",
+ "R6C13_JSNETCIBL{0}",
+ "R6C13_JSNETCIBT{0}",
+ "R6C13_JSNETCIBR{0}",
+ "R6C13_JSNETCIBB{0}"], range(2)),
+ (["R6C13_JLPLLCLK{0}"], range(4)),
+ (["R6C13_JPCLKT3{0}"], range(3)),
+ (["R6C13_JPCLKT10"], range(1)),
+
+ # Mux selects on the outputs.
+ (["R6C13_JCE{0}_DCC"], range(8)),
+ (["R6C13_JSEL{0}_DCM"], range(6, 8)),
+
+ # Unfortunately, same deal w/ concatenated nets also applies to the
+ # output.
+ # "second" is kinda a misnomer here- clock nets go through tristates,
+ # although TCL claims a fixed connection. There are multiple layers of
+ # fixed connections where the net names change on the outputs, so we
+ # just take care of all suspected fixed connections in one fell swoop.
+ #
+ # All the initial output connections are attached to muxes controlled
+ # by config bits, and thus are _not_ fixed.
+
+ # Global nets 6 and 7 are "MUX"ed twice- once to choose between two
+ # connections, another for clock enable (CEN). First net.
+ (["R6C13_CLK{0}_6_DCM",
+ "R6C13_CLK{0}_7_DCM"], range(2)),
+ (["R6C13_CLK{0}_0_ECLKBRIDGECS",
+ "R6C13_CLK{0}_1_ECLKBRIDGECS"], range(2)),
+
+ # Second net. Connects to R6C13_CLKI{6,7}_DCC.
+ (["R6C13_DCMOUT{0}_DCM"], range(6, 8)),
+ (["R6C13_JECSOUT{0}_ECLKBRIDGECS"], range(2)),
+
+ # All CLKO connections are gated by a MUX connected to fabric; defaults
+ # to pass-through in configuration bits.
+ (["R6C13_CLKI{0}_DCC"], range(8)),
+ (["R6C13_CLKO{0}_DCC"], range(8)),
+ ],
+
+ "muxed": [
+ # And also include muxed connections.
+ (["R6C13_VSRX0{0}00"], range(8)),
+ (["R6C13_VPRXCLKI{0}"], range(6)),
+ (["R6C13_VPRXCLKI6{0}",
+ "R6C13_VPRXCLKI7{0}"], range(2)),
+ (["R6C13_EBRG0CLK{0}",
+ "R6C13_EBRG1CLK{0}"], range(2))
+ ],
+
+ "ignore": [
+ # CLK{0,1}_{0,1}_ECLKBRIDGECS do not in fact drive
+ # R6C13_JSEL{0}_ECLKBRIDGECS. R6C13_JSEL{0}_ECLKBRIDGECS is driven from
+ # elsewhere. Ignore for now.
+ (["R6C13_JSEL{0}_ECLKBRIDGECS"], range(2))
+ ],
+}
+
+nets = {k: [] for k in templates.keys()}
+
+for (var, temp) in templates.items():
+ for (n, r) in temp:
+ for p in net_product(n, r):
+ nets[var].append(p)
+
+
+def main():
+ for k, v in nets.items():
+ print("{}: {}".format(k, v))
+ print("")
+
+ sum = 0
+ for k in nets.keys():
+ s = len(nets[k])
+ print("total {}: {}".format(k, s))
+ sum = sum + s
+
+ print("grand total: {}".format(sum))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/030-cib_cfg0/cibroute.ncl b/fuzzers/machxo2/030-cib_cfg0/cibroute.ncl
new file mode 100644
index 0000000..7e7370b
--- /dev/null
+++ b/fuzzers/machxo2/030-cib_cfg0/cibroute.ncl
@@ -0,0 +1,35 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ [,,,,A0,B0,D0,C0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,]
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "K0::H0=0 "
+ "F0:F ";
+ primitive K0 i3_4_lut;
+ }
+ site R2C2A;
+ }
+
+ signal q_c
+ {
+ signal-pins
+ // drivers
+ (SLICE_0, F0),
+ // loads
+ (SLICE_0, A0);
+ ${route}
+ }
+}
diff --git a/fuzzers/machxo2/030-cib_cfg0/fuzzer.py b/fuzzers/machxo2/030-cib_cfg0/fuzzer.py
new file mode 100644
index 0000000..0175fa0
--- /dev/null
+++ b/fuzzers/machxo2/030-cib_cfg0/fuzzer.py
@@ -0,0 +1,38 @@
+from collections import defaultdict
+
+from fuzzconfig import FuzzConfig
+import interconnect
+import nets
+import pytrellis
+import re
+
+cfg = FuzzConfig(job="CIBCFG0ROUTE", family="MachXO2", device="LCMXO2-1200HC", ncl="cibroute.ncl", tiles=["CIB_R1C4:CIB_CFG0"])
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+
+ span1_re = re.compile(r'R\d+C\d+_[VH]01[NESWTLBR]\d{4}')
+
+ def nn_filter(net, netnames):
+ """ Match nets that are: in the tile according to Tcl, global nets, or span-1 nets that are accidentally
+ left out by Tcl"""
+ return ((net in netnames or span1_re.match(net)) and nets.is_cib(net)) or nets.is_global(net)
+
+ def fc_filter(arc, netnames):
+ """ Ignore connections between two general routing nets. These are edge buffers which vary based on location
+ and must be excluded from the CIB database.
+ """
+ return not (nets.general_routing_re.match(arc[0]) and nets.general_routing_re.match(arc[1]))
+ interconnect.fuzz_interconnect(config=cfg, location=(1, 4),
+ netname_predicate=nn_filter,
+ fc_predicate=fc_filter,
+ netname_filter_union=True,
+ enable_span1_fix=True,
+ netdir_override=defaultdict(lambda : str("ignore")),
+ bias=1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/031-cib_cfg1/cibroute.ncl b/fuzzers/machxo2/031-cib_cfg1/cibroute.ncl
new file mode 100644
index 0000000..7e7370b
--- /dev/null
+++ b/fuzzers/machxo2/031-cib_cfg1/cibroute.ncl
@@ -0,0 +1,35 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ [,,,,A0,B0,D0,C0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,]
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "K0::H0=0 "
+ "F0:F ";
+ primitive K0 i3_4_lut;
+ }
+ site R2C2A;
+ }
+
+ signal q_c
+ {
+ signal-pins
+ // drivers
+ (SLICE_0, F0),
+ // loads
+ (SLICE_0, A0);
+ ${route}
+ }
+}
diff --git a/fuzzers/machxo2/031-cib_cfg1/fuzzer.py b/fuzzers/machxo2/031-cib_cfg1/fuzzer.py
new file mode 100644
index 0000000..5e70b6e
--- /dev/null
+++ b/fuzzers/machxo2/031-cib_cfg1/fuzzer.py
@@ -0,0 +1,38 @@
+from collections import defaultdict
+
+from fuzzconfig import FuzzConfig
+import interconnect
+import nets
+import pytrellis
+import re
+
+cfg = FuzzConfig(job="CIBCFG1ROUTE", family="MachXO2", device="LCMXO2-1200HC", ncl="cibroute.ncl", tiles=["CIB_R1C5:CIB_CFG1"])
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+
+ span1_re = re.compile(r'R\d+C\d+_[VH]01[NESWTLBR]\d{4}')
+
+ def nn_filter(net, netnames):
+ """ Match nets that are: in the tile according to Tcl, global nets, or span-1 nets that are accidentally
+ left out by Tcl"""
+ return ((net in netnames or span1_re.match(net)) and nets.is_cib(net)) or nets.is_global(net)
+
+ def fc_filter(arc, netnames):
+ """ Ignore connections between two general routing nets. These are edge buffers which vary based on location
+ and must be excluded from the CIB database.
+ """
+ return not (nets.general_routing_re.match(arc[0]) and nets.general_routing_re.match(arc[1]))
+ interconnect.fuzz_interconnect(config=cfg, location=(1, 5),
+ netname_predicate=nn_filter,
+ fc_predicate=fc_filter,
+ netname_filter_union=True,
+ enable_span1_fix=True,
+ netdir_override=defaultdict(lambda : str("ignore")),
+ bias=1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/032-copy-cib_cfg0/fuzzer.py b/fuzzers/machxo2/032-copy-cib_cfg0/fuzzer.py
new file mode 100644
index 0000000..1c1cdeb
--- /dev/null
+++ b/fuzzers/machxo2/032-copy-cib_cfg0/fuzzer.py
@@ -0,0 +1,12 @@
+import dbcopy
+import pytrellis
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ # dbcopy.dbcopy("MachXO2", "LCMXO2-1200HC", "CIB_CFG0", "CIB_PIC_T0")
+ dbcopy.dbcopy("MachXO2", "LCMXO2-1200HC", "CIB_CFG0", "CIB_PIC_T_DUMMY")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/034-cib_ebrn/cibroute.ncl b/fuzzers/machxo2/034-cib_ebrn/cibroute.ncl
new file mode 100644
index 0000000..7e7370b
--- /dev/null
+++ b/fuzzers/machxo2/034-cib_ebrn/cibroute.ncl
@@ -0,0 +1,35 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp SLICE_0
+ [,,,,A0,B0,D0,C0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,]
+ {
+ logical
+ {
+ cellmodel-name SLICE;
+ program "MODE:LOGIC "
+ "K0::H0=0 "
+ "F0:F ";
+ primitive K0 i3_4_lut;
+ }
+ site R2C2A;
+ }
+
+ signal q_c
+ {
+ signal-pins
+ // drivers
+ (SLICE_0, F0),
+ // loads
+ (SLICE_0, A0);
+ ${route}
+ }
+}
diff --git a/fuzzers/machxo2/034-cib_ebrn/fuzzer.py b/fuzzers/machxo2/034-cib_ebrn/fuzzer.py
new file mode 100644
index 0000000..d763463
--- /dev/null
+++ b/fuzzers/machxo2/034-cib_ebrn/fuzzer.py
@@ -0,0 +1,68 @@
+from collections import defaultdict
+
+from fuzzconfig import FuzzConfig
+import interconnect
+import nets
+import pytrellis
+import re
+import argparse
+
+jobs = [
+ {
+ "cfg": FuzzConfig(job="CIBEBR0ROUTE", family="MachXO2", device="LCMXO2-1200HC",
+ ncl="cibroute.ncl", tiles=["CIB_R6C10:CIB_EBR0"]),
+ "location": (6, 10),
+ "nn_filter_extra": []
+ },
+ {
+ "cfg": FuzzConfig(job="CIBEBR0END0ROUTE", family="MachXO2", device="LCMXO2-1200HC",
+ ncl="cibroute.ncl", tiles=["CIB_R6C1:CIB_EBR0_END0"]),
+ "location": (6, 1),
+ "nn_filter_extra": ["G_HPBX0100", "G_HPBX0500"]
+ },
+ {
+ "cfg": FuzzConfig(job="CIBEBR2END0ROUTE", family="MachXO2", device="LCMXO2-1200HC",
+ ncl="cibroute.ncl", tiles=["CIB_R6C22:CIB_EBR2_END0"]),
+ "location": (6, 22),
+ "nn_filter_extra": []
+ },
+]
+
+
+def main(args):
+ pytrellis.load_database("../../../database")
+ for job in [jobs[i] for i in args.ids]:
+ cfg = job["cfg"]
+ cfg.setup()
+
+ span1_re = re.compile(r'R\d+C\d+_[VH]01[NESWTLBR]\d{4}')
+
+ def nn_filter(net, netnames):
+ """I want to handle global nets that are associated with this
+ tile manually; any matching nets are filtered out."""
+ if net in job["nn_filter_extra"]:
+ return False
+
+ """ Match nets that are: in the tile according to Tcl, global nets, or span-1 nets that are accidentally
+ left out by Tcl"""
+ return ((net in netnames or span1_re.match(net)) and nets.is_cib(net)) or nets.is_global(net)
+
+ def fc_filter(arc, netnames):
+ """ Ignore connections between two general routing nets. These are edge buffers which vary based on location
+ and must be excluded from the CIB database.
+ """
+ return not (nets.general_routing_re.match(arc[0]) and nets.general_routing_re.match(arc[1]))
+ interconnect.fuzz_interconnect(config=cfg, location=job["location"],
+ netname_predicate=nn_filter,
+ fc_predicate=fc_filter,
+ netname_filter_union=True,
+ enable_span1_fix=True,
+ netdir_override=defaultdict(lambda : str("ignore")),
+ bias=1)
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="CIB_EBRn Fuzzer.")
+ parser.add_argument(dest="ids", metavar="N", type=int, nargs="*",
+ default=range(0, len(jobs)), help="Job (indices) to run.")
+ args = parser.parse_args()
+ main(args)
diff --git a/fuzzers/machxo2/035-copy-cib_ebr0/fuzzer.py b/fuzzers/machxo2/035-copy-cib_ebr0/fuzzer.py
new file mode 100644
index 0000000..43b9f60
--- /dev/null
+++ b/fuzzers/machxo2/035-copy-cib_ebr0/fuzzer.py
@@ -0,0 +1,15 @@
+import dbcopy
+import pytrellis
+
+# Based on prior fuzzing that wasn't committed, conjecture that CIB_EBR
+# 0,1,2, and DUMMY have the same layout.
+
+def main():
+ pytrellis.load_database("../../../database")
+ dbcopy.dbcopy("MachXO2", "LCMXO2-1200HC", "CIB_EBR0", "CIB_EBR1")
+ dbcopy.dbcopy("MachXO2", "LCMXO2-1200HC", "CIB_EBR0", "CIB_EBR2")
+ dbcopy.dbcopy("MachXO2", "LCMXO2-1200HC", "CIB_EBR0", "CIB_EBR_DUMMY")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/050-pio_routing/fuzzer.py b/fuzzers/machxo2/050-pio_routing/fuzzer.py
new file mode 100644
index 0000000..56e2552
--- /dev/null
+++ b/fuzzers/machxo2/050-pio_routing/fuzzer.py
@@ -0,0 +1,139 @@
+from collections import defaultdict
+from itertools import product
+
+from fuzzconfig import FuzzConfig
+import interconnect
+import nets
+import pytrellis
+import re
+import argparse
+
+import isptcl
+import mk_nets
+
+span1_re = re.compile(r'R\d+C\d+_[VH]01[NESWTLBR]\d{4}')
+jofx_re = re.compile(r'R\d+C\d+_JOFX\d')
+def nn_filter(net, netnames):
+ """ Match nets that are: in the tile according to Tcl, global nets, or span-1 nets that are accidentally
+ left out by Tcl"""
+ return net in netnames or nets.is_global(net) or span1_re.match(net)
+
+# JOFX source connections are conjectured to not go to anything.
+def fc_filter(arc, netnames):
+ return not jofx_re.match(arc[0])
+
+# Bank of None means that the I/O connections are in another tile.
+jobs = [
+ {
+ "pos" : [(12, 11)],
+ "cfg" : FuzzConfig(job="PIOROUTEB", family="MachXO2", device="LCMXO2-1200HC", ncl="pioroute.ncl",
+ tiles=["PB11:PIC_B0"]),
+ "missing_nets" : None,
+ "bank" : "B",
+ },
+ {
+ "pos" : [(11, 11)],
+ "cfg" : FuzzConfig(job="PIOROUTEB_CIB", family="MachXO2", device="LCMXO2-1200HC", ncl="pioroute.ncl",
+ tiles=["CIB_R11C11:CIB_PIC_B0"]),
+ # A bug in the span1 fix prevents span1 nets from being included.
+ # Just fuzz manually for now.
+ "missing_nets" : ["R10C11_V01N0001", "R10C11_V01N0101"],
+ "bank" : None,
+ },
+ {
+ "pos" : [(10, 1)],
+ "cfg" : FuzzConfig(job="PIOROUTEL", family="MachXO2", device="LCMXO2-1200HC", ncl="pioroute.ncl",
+ tiles=["PL10:PIC_L0"]),
+ "missing_nets" : None,
+ "bank" : "L"
+ },
+
+ # Probably the same thing as PIC_L0 plus some additional fixed connections?
+ {
+ "pos" : [(11, 1)],
+ "cfg" : FuzzConfig(job="PIOROUTELLC0", family="MachXO2", device="LCMXO2-1200HC", ncl="pioroute.ncl",
+ tiles=["PL11:LLC0"]),
+ "missing_nets" : None,
+ "bank" : "L"
+ },
+ {
+ "pos" : [(10, 22)],
+ "cfg" : FuzzConfig(job="PIOROUTER", family="MachXO2", device="LCMXO2-1200HC", ncl="pioroute.ncl",
+ tiles=["PR10:PIC_R0"]),
+ "missing_nets" : None,
+ "bank" : "R"
+ },
+ {
+ "pos" : [(0, 12)],
+ "cfg" : FuzzConfig(job="PIOROUTET", family="MachXO2", device="LCMXO2-1200HC", ncl="pioroute.ncl",
+ tiles=["PT12:PIC_T0"]),
+ "missing_nets" : None,
+ "bank" : "T",
+ },
+ {
+ "pos" : [(1, 12)],
+ "cfg" : FuzzConfig(job="PIOROUTET_CIB", family="MachXO2", device="LCMXO2-1200HC", ncl="pioroute.ncl",
+ tiles=["CIB_R1C12:CIB_PIC_T0"]),
+ "missing_nets" : None,
+ "bank" : None,
+ },
+]
+
+def main(args):
+ pytrellis.load_database("../../../database")
+ for job in [jobs[i] for i in args.ids]:
+ cfg = job["cfg"]
+ cfg.setup()
+
+ if args.i:
+ # Fuzz basic routing, ignore fixed connections to/from I/O pads.
+ interconnect.fuzz_interconnect(config=cfg, location=pos,
+ netname_predicate=nn_filter,
+ netdir_override=defaultdict(lambda : str("ignore")),
+ fc_predicate=fc_filter,
+ netname_filter_union=False,
+ enable_span1_fix=True,
+ bias=1)
+
+ if args.m and job["missing_nets"]:
+ interconnect.fuzz_interconnect_with_netnames(config=cfg,
+ netnames=job["missing_nets"],
+ fc_predicate=fc_filter,
+ netname_filter_union=False,
+ bidir=True,
+ netdir_override=defaultdict(lambda : str("ignore")),
+ bias=1)
+
+
+ if args.p and job["bank"]:
+ # I/O connections in the left/right tiles exist as-if a column "0"
+ # or one past maximum is physically present.
+ if job["bank"] == "R":
+ io_nets = mk_nets.io_conns((job["pos"][0][0], job["pos"][0][1] + 1), job["bank"])
+ elif job["bank"] == "L":
+ io_nets = mk_nets.io_conns((job["pos"][0][0], job["pos"][0][1] - 1), job["bank"])
+ else:
+ io_nets = mk_nets.io_conns(job["pos"][0], job["bank"])
+
+ io_list = [io[0] for io in io_nets]
+ override_dict = {io[0]: io[1] for io in io_nets}
+ print(override_dict)
+
+ interconnect.fuzz_interconnect_with_netnames(config=cfg,
+ netnames=io_list,
+ fc_predicate=fc_filter,
+ netname_filter_union=False,
+ bidir=True,
+ netdir_override=override_dict,
+ bias=1)
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="PIO Routing Fuzzer.")
+ parser.add_argument("-i", action="store_true", help="Fuzz interconnect.")
+ parser.add_argument("-m", action="store_true", help="Fuzz missing nets.")
+ parser.add_argument("-p", action="store_true", help="Fuzz I/O pad connections.")
+ parser.add_argument(dest="ids", metavar="N", type=int, nargs="*",
+ default=range(0, len(jobs)), help="Job (indices) to run.")
+ args = parser.parse_args()
+ main(args)
diff --git a/fuzzers/machxo2/050-pio_routing/mk_nets.py b/fuzzers/machxo2/050-pio_routing/mk_nets.py
new file mode 100644
index 0000000..308b667
--- /dev/null
+++ b/fuzzers/machxo2/050-pio_routing/mk_nets.py
@@ -0,0 +1,137 @@
+from nets import net_product, char_range
+from itertools import product, starmap
+from collections import defaultdict
+import re
+
+def io_conns(tile, bank):
+ # All I/O connections on the left bank are contained in the other banks.
+ all_template = [
+ ("JPADDO{}", "sink"),
+ ("JPADDT{}", "sink"),
+ ("PADDO{}_PIO", "sink"),
+ ("PADDT{}_PIO", "sink"),
+ ("IOLDO{}_PIO","sink"),
+ ("IOLDO{}_{}IOLOGIC","sink"),
+ ("IOLTO{}_PIO","sink"),
+ ("IOLTO{}_{}IOLOGIC","sink"),
+ ("JPADDI{}_PIO", "driver"),
+ ("PADDI{}_{}IOLOGIC", "driver"),
+ ("JDI{}", "driver"),
+ ("INDD{}_{}IOLOGIC", "driver"),
+ ("DI{}_{}IOLOGIC", "sink"),
+ ("JONEG{}_{}IOLOGIC", "sink"),
+ ("JOPOS{}_{}IOLOGIC", "sink"),
+ ("JTS{}_{}IOLOGIC", "sink"),
+ ("JCE{}_{}IOLOGIC", "sink"),
+ ("JLSR{}_{}IOLOGIC", "sink"),
+ ("JCLK{}_{}IOLOGIC", "sink"),
+ ("JIN{}_{}IOLOGIC", "driver"),
+ ("JIP{}_{}IOLOGIC", "driver"),
+ ("INRD{}_PIO", "sink"),
+ ("PG{}_PIO", "sink")
+ ]
+
+ right = [
+ ("DQSW90{}_RIOLOGIC", "sink"),
+ ("DQSR90{}_RIOLOGIC", "sink"),
+ ("DDRCLKPOL{}_RIOLOGIC", "sink")
+ ]
+
+ bottom = [
+ ("JRXDA{2}_{1}IOLOGIC", "driver"),
+ ("JRXD{2}{0}_{1}IOLOGIC", "driver"),
+ ("JDEL{2}{0}_{1}IOLOGIC", "sink"),
+ ("JLIP{}_{}IOLOGIC", "sink"),
+ ("ECLK{}_{}IOLOGIC", "sink"),
+ ]
+
+ top = [
+ ("JTXD{2}{0}_{1}IOLOGIC", "sink"),
+ ("ECLK{}_{}IOLOGIC", "sink"),
+ ("LVDS{}_PIO", "sink"),
+ ]
+
+ if bank == "B":
+ bank_template = bottom
+ elif bank == "T":
+ bank_template = top
+ elif bank == "R":
+ bank_template = right
+ else:
+ bank_template = []
+
+ # Nets which come in 0-3/0-7 and 0-4, respectively.
+ rxda_re = re.compile("JRXDA\{2\}*")
+ rxd_re = re.compile("JRXD\{2\}\{0\}*")
+ txda_re = re.compile("JTXD\{2\}A*")
+ txd_re = re.compile("JTXD\{2\}\{0\}*")
+ del_re = re.compile("JDEL*")
+ eclk_re = re.compile("ECLKC*")
+
+ netlist = []
+ for pad in ("A", "B", "C", "D"):
+ # B/BS/T/TSIOLOGIC
+ if bank in ("B", "T"):
+ if pad == "A":
+ io_prefix = bank
+ elif pad == "C":
+ io_prefix = "{}S".format(bank)
+ else:
+ io_prefix = ""
+ # RIOLOGIC
+ elif bank == "R":
+ io_prefix = "R"
+ # Just "LOGIC"
+ else:
+ io_prefix = ""
+
+ for f, d in all_template:
+ suffix = f.format(pad, io_prefix)
+ netlist.append(("R{}C{}_{}".format(tile[0], tile[1], suffix), d))
+
+ if bank == "R":
+ for f, d in bank_template:
+ suffix = f.format(pad, io_prefix)
+ netlist.append(("R{}C{}_{}".format(tile[0], tile[1], suffix), d))
+ elif bank == "B":
+ for f, d in bank_template:
+ if del_re.match(f) and pad in ("A", "C"):
+ for n in range(5):
+ suffix = f.format(pad, io_prefix, n)
+ netlist.append(("R{}C{}_{}".format(tile[0], tile[1], suffix), d))
+ elif rxda_re.match(f) and pad == "A":
+ for n in range(8):
+ suffix = f.format(pad, io_prefix, n)
+ netlist.append(("R{}C{}_{}".format(tile[0], tile[1], suffix), d))
+ elif rxd_re.match(f) and pad in ("A", "C"):
+ for n in range(4):
+ suffix = f.format(pad, io_prefix, n)
+ netlist.append(("R{}C{}_{}".format(tile[0], tile[1], suffix), d))
+ elif pad in ("A", "C") and not rxda_re.match(f):
+ suffix = f.format(pad, io_prefix)
+ netlist.append(("R{}C{}_{}".format(tile[0], tile[1], suffix), d))
+ elif bank == "T":
+ for f, d in bank_template:
+ if txd_re.match(f) and pad in ("A", "C"):
+ netrange = range(8) if pad == "A" else range(4)
+ for n in netrange:
+ suffix = f.format(pad, io_prefix, n)
+ netlist.append(("R{}C{}_{}".format(tile[0], tile[1], suffix), d))
+ elif eclk_re.match(f) and pad in ("A", "C"):
+ suffix = f.format(pad, io_prefix)
+ netlist.append(("R{}C{}_{}".format(tile[0], tile[1], suffix), d))
+ elif not txd_re.match(f) and not eclk_re.match(f):
+ suffix = f.format(pad, io_prefix)
+ netlist.append(("R{}C{}_{}".format(tile[0], tile[1], suffix), d))
+
+ return netlist
+
+def main():
+ for t, b in zip(((10, 0), (12, 11), (10, 23), (1, 11)), ("L", "B", "R", "T")):
+ print("Bank {}:".format(b))
+ for i, n in enumerate(io_conns(t, b)):
+ print(i, n)
+ print("")
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/050-pio_routing/pioroute.ncl b/fuzzers/machxo2/050-pio_routing/pioroute.ncl
new file mode 100644
index 0000000..a7e908a
--- /dev/null
+++ b/fuzzers/machxo2/050-pio_routing/pioroute.ncl
@@ -0,0 +1,39 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ comp PIO
+ {
+ logical
+ {
+ cellmodel-name PIO;
+ program "TRIMUX:PADDT:::PADDT=0 "
+ "IOBUF:::PULLMODE=NONE,DRIVE=8, \"
+ "SLEWRATE=SLOW,HYSTERESIS=NA "
+ "DATAMUX:PADDO "
+ "VREF:OFF "
+ "ODMUX:TRIMUX "
+ "LVDSMUX:DATAMUX ";
+ primitive IOBUF PIO_pad;
+ primitive PAD PIO;
+ }
+ site "11";
+ }
+
+ signal q_c
+ {
+ signal-pins
+ // drivers
+ (PIO, PADDI),
+ // loads
+ (PIO, PADDO);
+ ${route}
+ }
+}
diff --git a/fuzzers/machxo2/051-pio_attrs/empty.ncl b/fuzzers/machxo2/051-pio_attrs/empty.ncl
new file mode 100644
index 0000000..11b72ab
--- /dev/null
+++ b/fuzzers/machxo2/051-pio_attrs/empty.ncl
@@ -0,0 +1,12 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+}
diff --git a/fuzzers/machxo2/051-pio_attrs/fuzzer.py b/fuzzers/machxo2/051-pio_attrs/fuzzer.py
new file mode 100644
index 0000000..dc5af6f
--- /dev/null
+++ b/fuzzers/machxo2/051-pio_attrs/fuzzer.py
@@ -0,0 +1,245 @@
+from collections import defaultdict
+
+from fuzzconfig import FuzzConfig
+import interconnect
+import nets
+import pytrellis
+import re
+import argparse
+import fuzzloops
+import nonrouting
+import os
+
+jobs = [
+ {
+ "cfg": FuzzConfig(job="PICB0_AB", family="MachXO2", device="LCMXO2-1200HC",
+ ncl="empty.ncl", tiles=["PB11:PIC_B0"]),
+ "side": "B",
+ "pins": [("13", "A"), ("14", "B")]
+ },
+
+ # Split into multiple jobs, because Diamond chokes if the I/Os don't
+ # actually physically exist (QFN32 is default).
+ {
+ "cfg": FuzzConfig(job="PICB0_CD", family="MachXO2", device="LCMXO2-1200HC",
+ ncl="empty.ncl", tiles=["PB6:PIC_B0"]),
+ "side": "B",
+ "pins": [("9", "C"), ("10", "D")]
+ },
+
+ {
+ "cfg": FuzzConfig(job="PICL0_IO", family="MachXO2", device="LCMXO2-1200HC",
+ ncl="empty.ncl", tiles=["PL5:PIC_L0"]),
+ "side": "L",
+ "pins": [("12", "A"), ("13", "B"), ("14", "C"), ("15", "D")],
+ "package": "TQFP100"
+ },
+
+ {
+ "cfg": FuzzConfig(job="PICR0_IO", family="MachXO2", device="LCMXO2-1200HC",
+ ncl="empty.ncl", tiles=["PR5:PIC_R0"]),
+ "side": "R",
+ "pins": [("65", "A"), ("64", "B"), ("63", "C"), ("62", "D")],
+ "package": "TQFP100"
+ },
+
+ {
+ "cfg": FuzzConfig(job="PICT0_IO", family="MachXO2", device="LCMXO2-1200HC",
+ ncl="empty.ncl", tiles=["PT10:PIC_T0"]),
+ "side": "T",
+ "pins": [("97", "A"), ("96", "B")],
+ "package": "TQFP100"
+ },
+
+ # FIXME: WARNING - map: In "LOCATE COMP "pad" SITE "PT10{C,D} pin" ;":
+ # Current SYS_CONFIG setting prohibits pin be used as user IO. This
+ # preference has been disabled. Why?
+ {
+ "cfg": FuzzConfig(job="PICT0_IO", family="MachXO2", device="LCMXO2-1200HC",
+ ncl="empty.ncl", tiles=["PT12:PIC_T0"]),
+ "side": "T",
+ "pins": [("28", "C"), ("27", "D")]
+ },
+]
+
+# Function constructed from reading the MachXO2 sysIO Usage Guide.
+# Diamond is very sensitive to invalid I/O combinations, and will happily
+# change the I/O type out from under you if you give it a bad combination.
+# This can lead to further errors when the Diamond-assigned I/O type is
+# invalid for the pin (for the complementary pair, especially).
+def get_io_types(dir, pio, side):
+ # Singled-ended I/O types.
+ types = [
+ "LVTTL33",
+ "LVCMOS33",
+ "LVCMOS25",
+ "LVCMOS18",
+ "LVCMOS15",
+ "LVCMOS12",
+ "SSTL25_I",
+ "SSTL18_I",
+ "HSTL18_I"
+ ]
+
+ if dir == "INPUT":
+ types += [
+ "SSTL25_II",
+ "SSTL18_II",
+ "HSTL18_II",
+ "LVCMOS25R33",
+ "LVCMOS18R33",
+ "LVCMOS18R25",
+ "LVCMOS15R33",
+ "LVCMOS15R25"
+ ]
+
+ if dir in ("INPUT", "BIDIR"):
+ types += [
+ "LVCMOS12R33",
+ "LVCMOS12R25",
+ "LVCMOS10R33",
+ "LVCMOS10R25"
+ ]
+
+ if side == "B":
+ # Only bottom bank supports PCI33.
+ types += [
+ "PCI33"
+ ]
+
+ # Differential I/O types.
+ if pio in ("A", "C"):
+ types += [
+ "SSTL25D_I",
+ "SSTL18D_I",
+ "HSTL18D_I",
+ "MIPI",
+ "LVCMOS33D",
+ "LVCMOS25D",
+ "LVCMOS18D",
+ "LVCMOS15D",
+ "LVCMOS12D",
+ ]
+
+ if dir == "INPUT":
+ # True differential inputs.
+ # FIXME: Also supported in bidir?
+ # map_impl.mrp suggests no (warning: violates legal combination
+ # and is ignored.)
+ types += [
+ "SSTL25D_II",
+ "SSTL18D_II",
+ "HSTL18D_II",
+ "LVDS25",
+ "LVPECL33",
+ "MLVDS25",
+ "BLVDS25",
+ "RSDS25"
+ ]
+
+ if dir == "OUTPUT":
+ # Emulated differential output.
+ # FIXME: Also supported in bidir?
+ types += [
+ "LVDS25E",
+ "LVPECL33E",
+ "MLVDS25E",
+ "BLVDS25E",
+ "RSDS25E"
+ ]
+
+ # True differential output. Only supported on Top and primary pair.
+ if pio == "A" and side == "T":
+ types += [
+ "LVDS25"
+ ]
+ return types
+
+
+def get_cfg_vccio(iotype):
+ m = re.match(r".*(\d)(\d)$", iotype)
+ if not m:
+ return "3.3"
+ return "{}.{}".format(m.group(1), m.group(2))
+
+
+def main(args):
+ pytrellis.load_database("../../../database")
+ for job in [jobs[i] for i in args.ids]:
+ cfg = job["cfg"]
+ side = job["side"]
+ pins = job["pins"]
+
+ os.environ['DEV_PACKAGE'] = job.get("package", "QFN32")
+
+ cfg.setup()
+ empty_bitfile = cfg.build_design(cfg.ncl, {})
+ cfg.ncl = "pio.v"
+
+ def per_pin(pin):
+ loc, pio = pin
+
+ def get_substs(iomode, extracfg=None):
+ if iomode == "NONE":
+ iodir, type = "NONE", ""
+ else:
+ iodir, type = iomode.split("_", 1)
+ substs = {
+ "dir": iodir,
+ "io_type": type,
+ "loc": loc,
+ "extra_attrs": "",
+ "cfg_vio": "3.3"
+ }
+ if extracfg is not None:
+ substs["extra_attrs"] = '(* {}="{}" *)'.format(extracfg[0], extracfg[1])
+ if side == "B":
+ substs["cfg_vio"] = get_cfg_vccio(type)
+ return substs
+
+ modes = ["NONE"]
+ for iodir in ("INPUT", "OUTPUT", "BIDIR"):
+ modes += [iodir + "_" + _ for _ in get_io_types(iodir, pio, side)]
+
+ nonrouting.fuzz_enum_setting(cfg, "PIO{}.BASE_TYPE".format(pio), modes,
+ lambda x: get_substs(iomode=x),
+ empty_bitfile, False)
+
+ nonrouting.fuzz_enum_setting(cfg, "PIO{}.PULLMODE".format(pio), ["UP", "DOWN", "NONE", "KEEPER", "FAILSAFE"],
+ lambda x: get_substs(iomode="INPUT_LVCMOS33", extracfg=("PULLMODE", x)),
+ empty_bitfile)
+ nonrouting.fuzz_enum_setting(cfg, "PIO{}.SLEWRATE".format(pio), ["FAST", "SLOW"],
+ lambda x: get_substs(iomode="OUTPUT_LVCMOS33", extracfg=("SLEWRATE", x)),
+ empty_bitfile)
+ # # FIXME: Do LVCMOS12, which is 2/6mA.
+ nonrouting.fuzz_enum_setting(cfg, "PIO{}.DRIVE".format(pio), ["4", "8", "12", "16", "24"],
+ lambda x: get_substs(iomode="OUTPUT_LVCMOS33", extracfg=("DRIVE", x)),
+ empty_bitfile)
+ nonrouting.fuzz_enum_setting(cfg, "PIO{}.HYSTERESIS".format(pio), ["SMALL", "LARGE"],
+ lambda x: get_substs(iomode="INPUT_LVCMOS33", extracfg=("HYSTERESIS", x)),
+ empty_bitfile)
+ nonrouting.fuzz_enum_setting(cfg, "PIO{}.OPENDRAIN".format(pio), ["ON", "OFF"],
+ lambda x: get_substs(iomode="OUTPUT_LVCMOS33", extracfg=("OPENDRAIN", x)),
+ empty_bitfile)
+ if loc in "B":
+ nonrouting.fuzz_enum_setting(cfg, "PIO{}.CLAMP".format(pio), ["PCI", "OFF"],
+ lambda x: get_substs(iomode="INPUT_LVCMOS33", extracfg=("CLAMP", x)),
+ empty_bitfile)
+ else:
+ nonrouting.fuzz_enum_setting(cfg, "PIO{}.CLAMP".format(pio), ["ON", "OFF"],
+ lambda x: get_substs(iomode="INPUT_LVCMOS33", extracfg=("CLAMP", x)),
+ empty_bitfile)
+ if loc in "T" and pio in "A":
+ nonrouting.fuzz_enum_setting(cfg, "PIO{}.DIFFDRIVE".format(pio), ["1.25", "2.0", "2.5", "3.5"],
+ lambda x: get_substs(iomode="INPUT_LVCMOS33", extracfg=("CLAMP", x)),
+ empty_bitfile)
+
+ fuzzloops.parallel_foreach(pins, per_pin)
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="PIO Attributes Fuzzer.")
+ parser.add_argument(dest="ids", metavar="N", type=int, nargs="*",
+ default=range(0, len(jobs)), help="Job (indices) to run.")
+ args = parser.parse_args()
+ main(args)
diff --git a/fuzzers/machxo2/051-pio_attrs/pio.lpf b/fuzzers/machxo2/051-pio_attrs/pio.lpf
new file mode 100644
index 0000000..0c934b5
--- /dev/null
+++ b/fuzzers/machxo2/051-pio_attrs/pio.lpf
@@ -0,0 +1 @@
+SYSCONFIG CONFIG_IOVOLTAGE = ${cfg_vio};
diff --git a/fuzzers/machxo2/051-pio_attrs/pio.v b/fuzzers/machxo2/051-pio_attrs/pio.v
new file mode 100644
index 0000000..0fa131a
--- /dev/null
+++ b/fuzzers/machxo2/051-pio_attrs/pio.v
@@ -0,0 +1,68 @@
+`define ${dir}
+
+`ifdef NONE
+
+module top(input x);
+
+// Minimum legal empty module
+wire dummy;
+
+// Dummy load
+GSR gsr_i(.GSR(dummy));
+
+// Dummy source
+OSCH osc_i(.OSC(dummy));
+
+
+endmodule
+
+`else
+
+module top(inout pad);
+
+`ifdef BIDIR
+
+wire dummyo, dummyi;
+
+(* keep *)
+(* LOC="${loc}" *)
+(* IO_TYPE="${io_type}" *)
+${extra_attrs}
+BB b_b(.B(pad), .O(dummyo), .I(1'b1), .T(dummyi));
+
+// Dummy load
+GSR gsr_i(.GSR(dummyo));
+
+// Dummy source
+OSCH osc_i(.OSC(dummyi));
+
+`endif
+
+`ifdef INPUT
+
+wire dummyo;
+
+(* keep *)
+(* LOC="${loc}" *)
+(* IO_TYPE="${io_type}" *)
+${extra_attrs}
+IB i_b(.I(pad), .O(dummyo));
+
+// Dummy load
+GSR gsr_i(.GSR(dummyo));
+
+`endif
+
+`ifdef OUTPUT
+
+(* keep *)
+(* LOC="${loc}" *)
+(* IO_TYPE="${io_type}" *)
+${extra_attrs}
+OB o_b(.O(pad), .I(1'b1));
+
+`endif
+
+endmodule
+
+`endif
diff --git a/fuzzers/machxo2/052-pio_fixup/fuzzer.py b/fuzzers/machxo2/052-pio_fixup/fuzzer.py
new file mode 100644
index 0000000..0bdf954
--- /dev/null
+++ b/fuzzers/machxo2/052-pio_fixup/fuzzer.py
@@ -0,0 +1,10 @@
+import dbfixup
+import pytrellis
+
+def main():
+ pytrellis.load_database("../../../database")
+ dbfixup.remove_enum_bits("MachXO2", "LCMXO2-1200HC", "PIC_L0", (29, 11))
+ dbfixup.remove_enum_bits("MachXO2", "LCMXO2-1200HC", "PIC_R0", (29, 59), (0, 48))
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/102-oscg/empty.ncl b/fuzzers/machxo2/102-oscg/empty.ncl
new file mode 100644
index 0000000..7779581
--- /dev/null
+++ b/fuzzers/machxo2/102-oscg/empty.ncl
@@ -0,0 +1,11 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+}
diff --git a/fuzzers/machxo2/102-oscg/fuzzer.py b/fuzzers/machxo2/102-oscg/fuzzer.py
new file mode 100644
index 0000000..98db71f
--- /dev/null
+++ b/fuzzers/machxo2/102-oscg/fuzzer.py
@@ -0,0 +1,78 @@
+import sys
+
+from fuzzconfig import FuzzConfig
+import nonrouting
+import pytrellis
+import fuzzloops
+import interconnect
+
+cfg = FuzzConfig(job="OSCH", family="MachXO2", device="LCMXO2-1200HC", ncl="empty.ncl",
+ tiles=["PT8:PIC_T_DUMMY_OSC",
+ "PT4:CFG0", "PT5:CFG1",
+ "PT6:CFG2", "PT7:CFG3",
+ "CIB_R1C4:CIB_CFG0",
+ "CIB_R1C5:CIB_CFG1"])
+
+
+def get_substs(mode="OSCH", nom_freq="2.08", stdby="0"):
+ if mode == "NONE":
+ comment = "//"
+ else:
+ comment = ""
+
+ if stdby == "1":
+ stdby = ""
+ stdby_0 = "//"
+ else:
+ stdby = "//"
+ stdby_0 = ""
+
+ if nom_freq == "2.08":
+ using_non_default_freq = ""
+ using_default_freq = "//"
+ else:
+ using_non_default_freq = "//"
+ using_default_freq = ""
+
+ return dict(comment=comment,
+ nom_freq=nom_freq,
+ stdby=stdby,
+ stdby_0=stdby_0,
+ using_non_default_freq=using_non_default_freq,
+ using_default_freq=using_default_freq)
+
+def main():
+ pytrellis.load_database("../../../database")
+ cfg.setup()
+ empty_bitfile = cfg.build_design(cfg.ncl, {})
+ cfg.ncl = "osc.ncl"
+
+ nonrouting.fuzz_enum_setting(cfg, "OSCH.STDBY", ["0", "1"],
+ lambda x: get_substs(stdby=x), empty_bitfile)
+ nonrouting.fuzz_enum_setting(cfg, "OSCH.MODE", ["NONE", "OSCH"],
+ lambda x: get_substs(mode=x), empty_bitfile)
+
+ # Takes a long time, so permit opt-out.
+ if "-s" not in sys.argv:
+ nonrouting.fuzz_enum_setting(cfg, "OSCH.NOM_FREQ",
+ ["{}".format(i) for i in [
+ 2.08, 2.15, 2.22, 2.29, 2.38, 2.46, 2.56, 2.66, 2.77, 2.89,
+ 3.02, 3.17, 3.33, 3.50, 3.69, 3.91, 4.16, 4.29, 4.43, 4.59,
+ 4.75, 4.93, 5.12, 5.32, 5.54, 5.78, 6.05, 6.33, 6.65, 7.00,
+ 7.39, 7.82, 8.31, 8.58, 8.87, 9.17, 9.50, 9.85, 10.23, 10.64,
+ 11.08, 11.57, 12.09, 12.67, 13.30, 14.00, 14.78, 15.65, 15.65, 16.63,
+ 17.73, 19.00, 20.46, 22.17, 24.18, 26.60, 29.56, 33.25, 38.00, 44.33,
+ 53.20, 66.50, 88.67, 133.00
+ ]], lambda x: get_substs(nom_freq=x), empty_bitfile)
+
+ cfg.ncl = "osc_routing.ncl"
+ interconnect.fuzz_interconnect_with_netnames(
+ cfg,
+ ["R1C4_JOSC_OSC"],
+ bidir=True,
+ netdir_override={"R1C4_JOSC_OSC" : "driver"},
+ bias=1
+ )
+
+if __name__ == "__main__":
+ main()
diff --git a/fuzzers/machxo2/102-oscg/osc.ncl b/fuzzers/machxo2/102-oscg/osc.ncl
new file mode 100644
index 0000000..1396f62
--- /dev/null
+++ b/fuzzers/machxo2/102-oscg/osc.ncl
@@ -0,0 +1,23 @@
+::FROM-WRITER;
+design top
+{
+ device
+ {
+ architecture xo2c00;
+ device LCMXO2-1200HC;
+ package QFN32;
+ performance "6";
+ }
+
+ ${comment} comp OSC
+ ${comment} {
+ ${comment} logical {
+ ${comment} cellmodel-name OSC;
+ ${comment} program "${program}"
+ ${using_non_default_freq} ${stdby} ${comment} "OSCH:#ON ";
+ ${using_non_default_freq} ${stdby_0} ${comment} "OSCH::::STDBY=0 ";
+ ${using_default_freq} ${comment} "OSCH:::NOM_FREQ=${nom_freq}:STDBY=0 ";
+ ${comment} }
+ ${comment} site OSC;
+ ${comment} }
+}
diff --git a/fuzzers/machxo2/900-db_fixup/fuzzer.py b/fuzzers/machxo2/900-db_fixup/fuzzer.py
new file mode 100644
index 0000000..100a28c
--- /dev/null
+++ b/fuzzers/machxo2/900-db_fixup/fuzzer.py
@@ -0,0 +1,19 @@
+import dbfixup
+import pytrellis
+
+device = "LCMXO2-1200HC"
+
+
+def main():
+ pytrellis.load_database("../../../database")
+ chip = pytrellis.Chip("LCMXO2-1200HC")
+ tiletypes = set()
+ for tile in chip.get_all_tiles():
+ tiletypes.add(tile.info.type)
+
+ for tiletype in sorted(tiletypes):
+ dbfixup.dbfixup("MachXO2", device, tiletype)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/libtrellis/include/Bels.hpp b/libtrellis/include/Bels.hpp
index cb4b5ea..be6ec28 100644
--- a/libtrellis/include/Bels.hpp
+++ b/libtrellis/include/Bels.hpp
@@ -5,7 +5,7 @@
#include "RoutingGraph.hpp"
namespace Trellis {
-namespace Bels {
+namespace Ecp5Bels {
void add_lc(RoutingGraph &graph, int x, int y, int z);
void add_pio(RoutingGraph &graph, int x, int y, int z);
@@ -21,6 +21,14 @@
void add_misc(RoutingGraph &graph, const std::string &name, int x, int y);
void add_ioclk_bel(RoutingGraph &graph, const std::string &name, int x, int y, int i, int bank = -1);
}
+
+namespace MachXO2Bels {
+
+void add_lc(RoutingGraph &graph, int x, int y, int z);
+void add_pio(RoutingGraph &graph, int x, int y, int z);
+}
+
+
}
#endif
diff --git a/libtrellis/include/Chip.hpp b/libtrellis/include/Chip.hpp
index 1c12c3b..5fc1fc5 100644
--- a/libtrellis/include/Chip.hpp
+++ b/libtrellis/include/Chip.hpp
@@ -150,6 +150,11 @@
// Globals data
GlobalsInfo global_data;
+
+private:
+ // Factory functions
+ shared_ptr<RoutingGraph> get_routing_graph_ecp5();
+ shared_ptr<RoutingGraph> get_routing_graph_machxo2();
};
ChipDelta operator-(const Chip &a, const Chip &b);
diff --git a/libtrellis/include/RoutingGraph.hpp b/libtrellis/include/RoutingGraph.hpp
index 9f41187..3110e9e 100644
--- a/libtrellis/include/RoutingGraph.hpp
+++ b/libtrellis/include/RoutingGraph.hpp
@@ -135,6 +135,7 @@
// Must be set up beforehand
std::string chip_name;
+ std::string chip_family;
std::string chip_prefix;
int max_row, max_col;
@@ -157,6 +158,11 @@
// Add a Bel input or output pin
void add_bel_input(RoutingBel &bel, ident_t pin, int wire_x, int wire_y, ident_t wire_name);
void add_bel_output(RoutingBel &bel, ident_t pin, int wire_x, int wire_y, ident_t wire_name);
+
+private:
+ // Factory functions
+ RoutingId globalise_net_ecp5(int row, int col, const std::string &db_name);
+ RoutingId globalise_net_machxo2(int row, int col, const std::string &db_name);
};
}
diff --git a/libtrellis/src/Bels.cpp b/libtrellis/src/Bels.cpp
index bbcd7d8..c11ed64 100644
--- a/libtrellis/src/Bels.cpp
+++ b/libtrellis/src/Bels.cpp
@@ -3,7 +3,7 @@
#include "Database.hpp"
#include "BitDatabase.hpp"
namespace Trellis {
-namespace Bels {
+namespace Ecp5Bels {
void add_lc(RoutingGraph &graph, int x, int y, int z) {
char l = "ABCD"[z];
@@ -634,4 +634,14 @@
}
-}
\ No newline at end of file
+
+namespace MachXO2Bels {
+ void add_lc(RoutingGraph &graph, int x, int y, int z) {
+
+ }
+
+ void add_pio(RoutingGraph &graph, int x, int y, int z) {
+
+ }
+}
+}
diff --git a/libtrellis/src/Bitstream.cpp b/libtrellis/src/Bitstream.cpp
index fb0aa38..1a35e94 100644
--- a/libtrellis/src/Bitstream.cpp
+++ b/libtrellis/src/Bitstream.cpp
@@ -39,8 +39,6 @@
BitstreamOptions(const Chip &chip) {
if (chip.info.family == "MachXO2") {
// Write frames out in order 0 => max or reverse (max => 0).
- // This apparently does NOT apply to compressed bitstreams, which
- // uses reversed_frames = true unconditionally.
reversed_frames = false;
dummy_bytes_after_preamble = 2;
crc_meta = 0xE0; // CRC check (0x80), once at end (0x40), dummy bits
@@ -600,9 +598,7 @@
bytes_per_frame += (7 - ((bytes_per_frame - 1) % 8));
unique_ptr<uint8_t[]> frame_bytes = make_unique<uint8_t[]>(bytes_per_frame);
for (size_t i = 0; i < frame_count; i++) {
- // Apparently when a bitstream is compressed, even on
- // MachXO2, frames are written in reverse order!
- const size_t idx = (chip->info.num_frames - 1) - i;
+ size_t idx = ops.reversed_frames ? (chip->info.num_frames - 1) - i : i;
if (cmd == BitstreamCommand::LSC_PROG_INCR_CMP)
rd.get_compressed_bytes(frame_bytes.get(), bytes_per_frame, compression_dict.get());
else
@@ -798,6 +794,7 @@
size_t bytes_per_frame = (chip.info.bits_per_frame + chip.info.pad_bits_after_frame +
chip.info.pad_bits_before_frame) / 8U;
for (size_t i = 0; i < frames; i++) {
+ const size_t idx = ops.reversed_frames? (chip.info.num_frames - 1) - i : i;
frames_data.emplace_back();
auto &frame_bytes = frames_data.back();
frame_bytes.resize(bytes_per_frame);
@@ -805,7 +802,7 @@
size_t ofs = j + chip.info.pad_bits_after_frame;
assert(((bytes_per_frame - 1) - (ofs / 8)) < bytes_per_frame);
frame_bytes[(bytes_per_frame - 1) - (ofs / 8)] |=
- (chip.cram.bit((chip.info.num_frames - 1) - i, j) & 0x01) << (ofs % 8);
+ (chip.cram.bit(idx, j) & 0x01) << (ofs % 8);
}
}
// Then compress and write
diff --git a/libtrellis/src/Chip.cpp b/libtrellis/src/Chip.cpp
index e983fa4..47fdbec 100644
--- a/libtrellis/src/Chip.cpp
+++ b/libtrellis/src/Chip.cpp
@@ -109,6 +109,16 @@
shared_ptr<RoutingGraph> Chip::get_routing_graph()
{
+ if(info.family == "ECP5") {
+ return get_routing_graph_ecp5();
+ } else if(info.family == "MachXO2") {
+ return get_routing_graph_machxo2();
+ } else
+ throw runtime_error("Unknown chip family: " + info.family);
+}
+
+shared_ptr<RoutingGraph> Chip::get_routing_graph_ecp5()
+{
shared_ptr<RoutingGraph> rg(new RoutingGraph(*this));
//cout << "Building routing graph" << endl;
for (auto tile_entry : tiles) {
@@ -118,145 +128,159 @@
bitdb->add_routing(tile->info, *rg);
int x, y;
tie(y, x) = tile->info.get_row_col();
- // SLICE Bels
+ // SLICE Ecp5Bels
if (tile->info.type == "PLC2") {
for (int z = 0; z < 4; z++)
- Bels::add_lc(*rg, x, y, z);
+ Ecp5Bels::add_lc(*rg, x, y, z);
}
- // PIO Bels
+ // PIO Ecp5Bels
if (tile->info.type.find("PICL0") != string::npos || tile->info.type.find("PICR0") != string::npos)
for (int z = 0; z < 4; z++) {
- Bels::add_pio(*rg, x, y, z);
- Bels::add_iologic(*rg, x, y, z, false);
+ Ecp5Bels::add_pio(*rg, x, y, z);
+ Ecp5Bels::add_iologic(*rg, x, y, z, false);
}
if (tile->info.type.find("PIOT0") != string::npos || (tile->info.type.find("PICB0") != string::npos && tile->info.type != "SPICB0"))
for (int z = 0; z < 2; z++) {
- Bels::add_pio(*rg, x, y, z);
- Bels::add_iologic(*rg, x, y, z, true);
+ Ecp5Bels::add_pio(*rg, x, y, z);
+ Ecp5Bels::add_iologic(*rg, x, y, z, true);
}
if (tile->info.type == "SPICB0") {
- Bels::add_pio(*rg, x, y, 0);
- Bels::add_iologic(*rg, x, y, 0, true);
+ Ecp5Bels::add_pio(*rg, x, y, 0);
+ Ecp5Bels::add_iologic(*rg, x, y, 0, true);
}
- // DCC Bels
+ // DCC Ecp5Bels
if (tile->info.type == "LMID_0")
for (int z = 0; z < 14; z++)
- Bels::add_dcc(*rg, x, y, "L", std::to_string(z));
+ Ecp5Bels::add_dcc(*rg, x, y, "L", std::to_string(z));
if (tile->info.type == "RMID_0")
for (int z = 0; z < 14; z++)
- Bels::add_dcc(*rg, x, y, "R", std::to_string(z));
+ Ecp5Bels::add_dcc(*rg, x, y, "R", std::to_string(z));
if (tile->info.type == "TMID_0")
for (int z = 0; z < 12; z++)
- Bels::add_dcc(*rg, x, y, "T", std::to_string(z));
+ Ecp5Bels::add_dcc(*rg, x, y, "T", std::to_string(z));
if (tile->info.type == "BMID_0V" || tile->info.type == "BMID_0H")
for (int z = 0; z < 16; z++)
- Bels::add_dcc(*rg, x, y, "B", std::to_string(z));
- // RAM Bels
+ Ecp5Bels::add_dcc(*rg, x, y, "B", std::to_string(z));
+ // RAM Ecp5Bels
if (tile->info.type == "MIB_EBR0" || tile->info.type == "EBR_CMUX_UR" || tile->info.type == "EBR_CMUX_LR"
|| tile->info.type == "EBR_CMUX_LR_25K")
- Bels::add_bram(*rg, x, y, 0);
+ Ecp5Bels::add_bram(*rg, x, y, 0);
if (tile->info.type == "MIB_EBR2")
- Bels::add_bram(*rg, x, y, 1);
+ Ecp5Bels::add_bram(*rg, x, y, 1);
if (tile->info.type == "MIB_EBR4")
- Bels::add_bram(*rg, x, y, 2);
+ Ecp5Bels::add_bram(*rg, x, y, 2);
if (tile->info.type == "MIB_EBR6")
- Bels::add_bram(*rg, x, y, 3);
- // DSP Bels
+ Ecp5Bels::add_bram(*rg, x, y, 3);
+ // DSP Ecp5Bels
if (tile->info.type == "MIB_DSP0")
- Bels::add_mult18(*rg, x, y, 0);
+ Ecp5Bels::add_mult18(*rg, x, y, 0);
if (tile->info.type == "MIB_DSP1")
- Bels::add_mult18(*rg, x, y, 1);
+ Ecp5Bels::add_mult18(*rg, x, y, 1);
if (tile->info.type == "MIB_DSP4")
- Bels::add_mult18(*rg, x, y, 4);
+ Ecp5Bels::add_mult18(*rg, x, y, 4);
if (tile->info.type == "MIB_DSP5")
- Bels::add_mult18(*rg, x, y, 5);
+ Ecp5Bels::add_mult18(*rg, x, y, 5);
if (tile->info.type == "MIB_DSP3")
- Bels::add_alu54b(*rg, x, y, 3);
+ Ecp5Bels::add_alu54b(*rg, x, y, 3);
if (tile->info.type == "MIB_DSP7")
- Bels::add_alu54b(*rg, x, y, 7);
- // PLL Bels
+ Ecp5Bels::add_alu54b(*rg, x, y, 7);
+ // PLL Ecp5Bels
if (tile->info.type == "PLL0_UL")
- Bels::add_pll(*rg, "UL", x+1, y);
+ Ecp5Bels::add_pll(*rg, "UL", x+1, y);
if (tile->info.type == "PLL0_LL")
- Bels::add_pll(*rg, "LL", x, y-1);
+ Ecp5Bels::add_pll(*rg, "LL", x, y-1);
if (tile->info.type == "PLL0_LR")
- Bels::add_pll(*rg, "LR", x, y-1);
+ Ecp5Bels::add_pll(*rg, "LR", x, y-1);
if (tile->info.type == "PLL0_UR")
- Bels::add_pll(*rg, "UR", x-1, y);
- // DCU and ancillary Bels
+ Ecp5Bels::add_pll(*rg, "UR", x-1, y);
+ // DCU and ancillary Ecp5Bels
if (tile->info.type == "DCU0") {
- Bels::add_dcu(*rg, x, y);
- Bels::add_extref(*rg, x, y);
+ Ecp5Bels::add_dcu(*rg, x, y);
+ Ecp5Bels::add_extref(*rg, x, y);
}
if (tile->info.type == "BMID_0H")
for (int z = 0; z < 2; z++)
- Bels::add_pcsclkdiv(*rg, x, y-1, z);
- // Config/system Bels
+ Ecp5Bels::add_pcsclkdiv(*rg, x, y-1, z);
+ // Config/system Ecp5Bels
if (tile->info.type == "EFB0_PICB0") {
- Bels::add_misc(*rg, "GSR", x, y-1);
- Bels::add_misc(*rg, "JTAGG", x, y-1);
- Bels::add_misc(*rg, "OSCG", x, y-1);
- Bels::add_misc(*rg, "SEDGA", x, y-1);
+ Ecp5Bels::add_misc(*rg, "GSR", x, y-1);
+ Ecp5Bels::add_misc(*rg, "JTAGG", x, y-1);
+ Ecp5Bels::add_misc(*rg, "OSCG", x, y-1);
+ Ecp5Bels::add_misc(*rg, "SEDGA", x, y-1);
}
if (tile->info.type == "DTR")
- Bels::add_misc(*rg, "DTR", x, y-1);
+ Ecp5Bels::add_misc(*rg, "DTR", x, y-1);
if (tile->info.type == "EFB1_PICB1")
- Bels::add_misc(*rg, "USRMCLK", x-5, y);
+ Ecp5Bels::add_misc(*rg, "USRMCLK", x-5, y);
if (tile->info.type == "ECLK_L") {
- Bels::add_ioclk_bel(*rg, "CLKDIVF", x-2, y, 0, 7);
- Bels::add_ioclk_bel(*rg, "CLKDIVF", x-2, y, 1, 6);
- Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x-2, y, 0, 7);
- Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x-2, y, 1, 7);
- Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x-2, y+1, 0, 6);
- Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x-2, y+1, 1, 6);
- Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x-2, y, 0, 7);
- Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x-2, y, 1, 7);
- Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x-2, y+1, 0, 6);
- Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x-2, y+1, 1, 6);
- Bels::add_ioclk_bel(*rg, "DLLDELD", x-2, y-1, 0);
- Bels::add_ioclk_bel(*rg, "DLLDELD", x-2, y, 0);
- Bels::add_ioclk_bel(*rg, "DLLDELD", x-2, y+1, 0);
- Bels::add_ioclk_bel(*rg, "DLLDELD", x-2, y+2, 0);
- Bels::add_ioclk_bel(*rg, "ECLKBRIDGECS", x-2, y, 1);
- Bels::add_ioclk_bel(*rg, "BRGECLKSYNC", x-2, y, 1);
+ Ecp5Bels::add_ioclk_bel(*rg, "CLKDIVF", x-2, y, 0, 7);
+ Ecp5Bels::add_ioclk_bel(*rg, "CLKDIVF", x-2, y, 1, 6);
+ Ecp5Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x-2, y, 0, 7);
+ Ecp5Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x-2, y, 1, 7);
+ Ecp5Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x-2, y+1, 0, 6);
+ Ecp5Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x-2, y+1, 1, 6);
+ Ecp5Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x-2, y, 0, 7);
+ Ecp5Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x-2, y, 1, 7);
+ Ecp5Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x-2, y+1, 0, 6);
+ Ecp5Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x-2, y+1, 1, 6);
+ Ecp5Bels::add_ioclk_bel(*rg, "DLLDELD", x-2, y-1, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "DLLDELD", x-2, y, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "DLLDELD", x-2, y+1, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "DLLDELD", x-2, y+2, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "ECLKBRIDGECS", x-2, y, 1);
+ Ecp5Bels::add_ioclk_bel(*rg, "BRGECLKSYNC", x-2, y, 1);
}
if (tile->info.type == "ECLK_R") {
- Bels::add_ioclk_bel(*rg, "CLKDIVF", x+2, y, 0);
- Bels::add_ioclk_bel(*rg, "CLKDIVF", x+2, y, 1);
- Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x+2, y, 0, 2);
- Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x+2, y, 1, 2);
- Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x+2, y+1, 0, 3);
- Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x+2, y+1, 1, 3);
- Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x+2, y, 0, 2);
- Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x+2, y, 1, 2);
- Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x+2, y+1, 0, 3);
- Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x+2, y+1, 1, 3);
- Bels::add_ioclk_bel(*rg, "DLLDELD", x+2, y-1, 0);
- Bels::add_ioclk_bel(*rg, "DLLDELD", x+2, y, 0);
- Bels::add_ioclk_bel(*rg, "DLLDELD", x+2, y+1, 0);
- Bels::add_ioclk_bel(*rg, "DLLDELD", x+2, y+2, 0);
- Bels::add_ioclk_bel(*rg, "ECLKBRIDGECS", x+2, y, 0);
- Bels::add_ioclk_bel(*rg, "BRGECLKSYNC", x+2, y, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "CLKDIVF", x+2, y, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "CLKDIVF", x+2, y, 1);
+ Ecp5Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x+2, y, 0, 2);
+ Ecp5Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x+2, y, 1, 2);
+ Ecp5Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x+2, y+1, 0, 3);
+ Ecp5Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x+2, y+1, 1, 3);
+ Ecp5Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x+2, y, 0, 2);
+ Ecp5Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x+2, y, 1, 2);
+ Ecp5Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x+2, y+1, 0, 3);
+ Ecp5Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x+2, y+1, 1, 3);
+ Ecp5Bels::add_ioclk_bel(*rg, "DLLDELD", x+2, y-1, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "DLLDELD", x+2, y, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "DLLDELD", x+2, y+1, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "DLLDELD", x+2, y+2, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "ECLKBRIDGECS", x+2, y, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "BRGECLKSYNC", x+2, y, 0);
}
if (tile->info.type == "DDRDLL_UL")
- Bels::add_ioclk_bel(*rg, "DDRDLL", x-2, y-10, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "DDRDLL", x-2, y-10, 0);
if (tile->info.type == "DDRDLL_ULA")
- Bels::add_ioclk_bel(*rg, "DDRDLL", x-2, y-13, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "DDRDLL", x-2, y-13, 0);
if (tile->info.type == "DDRDLL_UR")
- Bels::add_ioclk_bel(*rg, "DDRDLL", x+2, y-10, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "DDRDLL", x+2, y-10, 0);
if (tile->info.type == "DDRDLL_URA")
- Bels::add_ioclk_bel(*rg, "DDRDLL", x+2, y-13, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "DDRDLL", x+2, y-13, 0);
if (tile->info.type == "DDRDLL_LL")
- Bels::add_ioclk_bel(*rg, "DDRDLL", x-2, y+13, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "DDRDLL", x-2, y+13, 0);
if (tile->info.type == "DDRDLL_LR")
- Bels::add_ioclk_bel(*rg, "DDRDLL", x+2, y+13, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "DDRDLL", x+2, y+13, 0);
if (tile->info.type == "PICL0_DQS2" || tile->info.type == "PICR0_DQS2")
- Bels::add_ioclk_bel(*rg, "DQSBUFM", x, y, 0);
+ Ecp5Bels::add_ioclk_bel(*rg, "DQSBUFM", x, y, 0);
}
return rg;
}
+shared_ptr<RoutingGraph> Chip::get_routing_graph_machxo2()
+{
+ shared_ptr<RoutingGraph> rg(new RoutingGraph(*this));
+
+ for (auto tile_entry : tiles) {
+ shared_ptr<Tile> tile = tile_entry.second;
+ //cout << " Tile " << tile->info.name << endl;
+ shared_ptr<TileBitDatabase> bitdb = get_tile_bitdata(TileLocator{info.family, info.name, tile->info.type});
+ bitdb->add_routing(tile->info, *rg);
+ }
+
+ return rg;
+}
+
// Global network funcs
bool GlobalRegion::matches(int row, int col) const {
diff --git a/libtrellis/src/PyTrellis.cpp b/libtrellis/src/PyTrellis.cpp
index ac07c35..d7ff240 100644
--- a/libtrellis/src/PyTrellis.cpp
+++ b/libtrellis/src/PyTrellis.cpp
@@ -443,6 +443,7 @@
class_<RoutingGraph, shared_ptr<RoutingGraph>>("RoutingGraph", no_init)
.def_readonly("chip_name", &RoutingGraph::chip_name)
+ .def_readonly("chip_family", &RoutingGraph::chip_family)
.def_readonly("max_row", &RoutingGraph::max_row)
.def_readonly("max_col", &RoutingGraph::max_col)
.def("ident", &RoutingGraph::ident)
diff --git a/libtrellis/src/RoutingGraph.cpp b/libtrellis/src/RoutingGraph.cpp
index 728a9bd..6908187 100644
--- a/libtrellis/src/RoutingGraph.cpp
+++ b/libtrellis/src/RoutingGraph.cpp
@@ -6,9 +6,11 @@
namespace Trellis {
+// This is ignored for the MachXO2 family- globals are handled during routing
+// graph creation.
const Location GlobalLoc(-2, -2);
-RoutingGraph::RoutingGraph(const Chip &c) : chip_name(c.info.name), max_row(c.get_max_row()), max_col(c.get_max_col())
+RoutingGraph::RoutingGraph(const Chip &c) : chip_name(c.info.name), chip_family(c.info.family), max_row(c.get_max_row()), max_col(c.get_max_col())
{
tiles[GlobalLoc].loc = GlobalLoc;
for (int y = 0; y <= max_row; y++) {
@@ -23,6 +25,9 @@
chip_prefix = "45K_";
else if (chip_name.find("85F") != string::npos)
chip_prefix = "85K_";
+ else if (chip_name.find("1200HC") != string::npos)
+ // FIXME: Prefix to distinguish XO, XO2, and XO3?
+ chip_prefix = "1200_";
else
assert(false);
}
@@ -53,6 +58,16 @@
RoutingId RoutingGraph::globalise_net(int row, int col, const std::string &db_name)
{
+ if(chip_family == "ECP5") {
+ return globalise_net_ecp5(row, col, db_name);
+ } else if(chip_family == "MachXO2") {
+ return globalise_net_machxo2(row, col, db_name);
+ } else
+ throw runtime_error("Unknown chip family: " + chip_family);
+}
+
+RoutingId RoutingGraph::globalise_net_ecp5(int row, int col, const std::string &db_name)
+{
static const std::regex e(R"(^([NS]\d+)?([EW]\d+)?_(.*))", std::regex::optimize);
std::string stripped_name = db_name;
if (db_name.find("25K_") == 0 || db_name.find("45K_") == 0 || db_name.find("85K_") == 0) {
@@ -111,6 +126,11 @@
}
}
+RoutingId RoutingGraph::globalise_net_machxo2(int row, int col, const std::string &db_name)
+{
+ return RoutingId();
+}
+
void RoutingGraph::add_arc(Location loc, const RoutingArc &arc)
{
RoutingId arcId;
diff --git a/metadata/MachXO2/LCMXO2-1200HC/globals.json b/metadata/MachXO2/LCMXO2-1200HC/globals.json
new file mode 100644
index 0000000..a408e0b
--- /dev/null
+++ b/metadata/MachXO2/LCMXO2-1200HC/globals.json
@@ -0,0 +1,8 @@
+{
+ "quadrants": {
+ },
+ "taps": {
+ },
+ "spines": {
+ }
+}
diff --git a/metadata/MachXO2/LCMXO2-256HC/globals.json b/metadata/MachXO2/LCMXO2-256HC/globals.json
new file mode 100644
index 0000000..a408e0b
--- /dev/null
+++ b/metadata/MachXO2/LCMXO2-256HC/globals.json
@@ -0,0 +1,8 @@
+{
+ "quadrants": {
+ },
+ "taps": {
+ },
+ "spines": {
+ }
+}
diff --git a/minitests/reg/clk_1.v b/minitests/reg/clk_1.v
new file mode 100644
index 0000000..08895ef
--- /dev/null
+++ b/minitests/reg/clk_1.v
@@ -0,0 +1,4 @@
+module top(input clk, input d, input r, input s, output q);
+ GSR gsr(.GSR(r));
+ FD1P3JX ff(.D(d), .SP(1'b0), .PD(s), .CK(1'b1), .Q(q));
+endmodule
diff --git a/misc/basecfgs/empty_machxo2-1200hc.config b/misc/basecfgs/empty_machxo2-1200hc.config
new file mode 100644
index 0000000..3d116fc
--- /dev/null
+++ b/misc/basecfgs/empty_machxo2-1200hc.config
@@ -0,0 +1,30 @@
+.device LCMXO2-1200HC
+
+.tile EBR_R6C11:EBR1
+unknown: F0B12
+
+.tile EBR_R6C15:EBR1
+unknown: F0B12
+
+.tile EBR_R6C18:EBR1
+unknown: F0B12
+
+.tile EBR_R6C21:EBR1
+unknown: F0B12
+
+.tile EBR_R6C2:EBR1
+unknown: F0B12
+
+.tile EBR_R6C5:EBR1
+unknown: F0B12
+
+.tile EBR_R6C8:EBR1
+unknown: F0B12
+
+.tile PT4:CFG0
+unknown: F5B30
+unknown: F5B32
+unknown: F5B36
+
+.tile PT7:CFG3
+unknown: F5B18