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