def run(code): return toolchain.run( f"module top(input C2, R, output Q); {code} endmodule", { 'C2': pinout['C2'], 'R': pinout['R'], 'Q': pinout[macrocell['pad']], }, f"{device_name}-{package}")
def run_pads(pad_names): ports = [] cells = [] pins = {} used_pads = set(pad_names) for n, pad_name in enumerate(pad_names): for other_macrocell_name, other_macrocell in device[ 'macrocells'].items(): if (other_macrocell['pad'] not in used_pads and other_macrocell['pad'] in pinout): used_pads.add(other_macrocell['pad']) break else: assert False ports += [f"input OE{n}", f"output O{n}"] cells += [ f"wire Q{n}; DFFAS dff{n}(1'b0, O{n}, 1'b0, Q{n}); ", f"TRI t{n}(Q{n}, OE{n}, O{n}); " ] pins.update({ f"O{n}": pinout[other_macrocell['pad']], f"OE{n}": pinout[pad_name], }) return toolchain.run( f"module top({', '.join(ports)}); " f"{' '.join(cells)} " f"endmodule", pins, f"{device_name}-{package}")
def run(nets, probe_macrocell, *, invert=False): pads = [net[:-4] for net in nets if net.endswith("_PAD")] fbs = [net[:-3] for net in nets if net.endswith("_FB")] sigs = pads + fbs ins = [f"input {pad}" for pad in pads] bffs = [ f"wire {fb}; DFF fb_{fb}(1'b0, 1'b0, {fb}); " for fb in fbs ] ands = [] # AND8 is advertised as a primitive but doesn't actually work in EDIF... ands.append(f"wire Y0; BUF b(1'b1, Y0); ") y_wire = "Y0" for n, off in enumerate(range(0, len(sigs), 3)): chunk = sigs[off:off + 3] last = (off + 3 >= len(sigs)) ands.append( f"wire Y{n+1}; AND{len(chunk) + 1}{'I1' if invert and last else ''} " f"a_{n+1}(Y{n}, {', '.join(chunk)}, Y{n+1}); ") y_wire = f"Y{n+1}" return toolchain.run( f"module top(output Q, {', '.join(ins)}); " f"{' '.join(bffs)} " f"{' '.join(ands)} " f"DFF ff(1'b0, {y_wire}, Q); " f"endmodule", { 'Q': pinout[probe_macrocell['pad']], **{pad: pinout[pad] for pad in pads}, **{f"fb_{fb}": str(600 + int(fb[2:])) for fb in fbs}, }, f"{device_name}-{package}")
def run(nets, probe_macrocell): pads = [net[:-4] for net in nets if net.endswith("_PAD")] fbs = [net[:-3] for net in nets if net.endswith("_FB")] sigs = pads + fbs ins = [f"input {pad}" for pad in pads] bffs = [ f"wire {fb}; DFF fb_{fb}(1'b0, 1'b0, {fb}); " for fb in fbs ] ands = [] # We need way too many inputs to rely on existing primitives. ands.append(f"wire Y0; BUF b(1'b1, Y0); ") y_wire = "Y0" for n, off in enumerate(range(0, len(sigs), 3)): chunk = sigs[off:off + 3] last = (off + 3 >= len(sigs)) ands.append(f"wire Y{n+1}; AND{len(chunk) + 1} " f"a_{n+1}(Y{n}, {', '.join(chunk)}, Y{n+1}); ") y_wire = f"Y{n+1}" return toolchain.run( f"module top(output Q, {', '.join(ins)}); " f"{' '.join(bffs)} " f"{' '.join(ands)} " f"DFF ff(1'b0, {y_wire}, Q); " f"endmodule", { 'Q': pinout[probe_macrocell['pad']], **{pad: pinout[pad] for pad in pads}, **{f"fb_{fb}": str(600 + int(fb[2:])) for fb in fbs}, }, f"{device_name}-{package}")
def run(clocks, **kwargs): code = [] outs = [] for index, (pad_n, negedge) in enumerate(clocks): outs.append(f"Q{index}") if negedge: code.append( f"wire N{index}; INV in{index}(C{pad_n}, N{index}); " f"DFFE ff{index}(N{index}, E1, 1'b0, Q{index});") else: code.append( f"DFFE ff{index}(C{pad_n}, E1, 1'b0, Q{index});") return toolchain.run( f"module top(input C1, C2, C3, E1, output QC, {', '.join(outs)}); " f"{' '.join(code)} " f"OR3 o(C1, C2, C3, QC); " f"endmodule", { 'C1': pinout['C1'], 'C2': pinout['C2'], 'C3': pinout[gclk3_pad], 'E1': pinout['E1'], **{ out: pinout[macrocell['pad']] for out, macrocell in zip( outs, device['macrocells'].values()) }, 'QC': pinout[device['macrocells']['MC8']['pad']], }, f"{device_name}-{package}", **kwargs)
def run_pad(code, object, probe_macrocell): return toolchain.run( f"module top(input I, output Q); " f"{code} " f"endmodule", { 'I': pinout[object['pad']], 'Q': pinout[probe_macrocell['pad']], }, f"{device_name}-{package}")
def run_fb(code, macrocell, probe_macrocell): return toolchain.run( f"module top(output Q); " f"wire I; DFF bff(1'b0, 1'b0, I);" f"{code} " f"endmodule", { 'bff': str(600 + int(macrocell['pad'][1:])), 'Q': pinout[probe_macrocell['pad']], }, f"{device_name}-{package}")
def run(code): return toolchain.run( f"module top(input CLK1, CLK2, output O); " f"{code} " f"endmodule", { "CLK1": pinout['C1'], "CLK2": pinout['C2'], "O": pinout[macrocell['pad']], }, f"{device_name}-{package}")
def run(code): return toolchain.run( f"module top(input CLK1); " f"wire Q, X, Y; OR2 o1(Q, X, Y); BUF b1(Y, X);" f"{code} " f"endmodule", { 'CLK1': pinout['C1'], 'ff': str(601 + macrocell_idx), }, f"{device_name}-{package}")
def run_i(**kwargs): return toolchain.run( f"module top(input I1, I2, output O); OR2 o(I1, I2, O); endmodule", { 'I1': pinout[macrocell['pad']], 'I2': pinout[other_macrocell['pad']], }, f"{device_name}-{package}", strategy=kwargs)
def run(code, **kwargs): return toolchain.run( f"module top(input CLK, output O); " f"wire Q; TRI tri(Q, 1'b0, O); " f"{code} " f"endmodule", { 'CLK': pinout['C1'], 'ff': str(601 + macrocell_idx), }, f"{device_name}-{package}", **kwargs)
def run(code): return toolchain.run( f"module top(input CLK1, CLK2, OE1, output Q);" f"{code}" f"endmodule", { 'CLK1': pinout['C1'], 'CLK2': pinout['C2'], 'OE1': pinout['E1'], 'Q': pinout[macrocell['pad']], }, f"{device_name}-{package}")
def run(code="wire A, Q; BUF b(A, Q);", **kwargs): return toolchain.run( f"module top(input C1, C2, C3, A, output Q); " f"{code} " f"endmodule", { 'C1': pinout['C1'], 'C2': pinout['C2'], 'C3': pinout[gclk3_pad], }, f"{device_name}-{package}", **kwargs)
def run(code): return toolchain.run( f"module top(input OE, CLK1, CLK2, CLK3, output O);" f"wire Q; TRI tri(Q, 1'b0, O); " f"{code} " f"endmodule", { 'CLK1': pinout['C1'], 'CLK2': pinout['C2'], 'CLK3': pinout[gclk3_pad], 'ff': str(601 + macrocell_idx), }, f"{device_name}-{package}")
def run(code): return toolchain.run( f"module top(input CLK1, CLK2, output O); " f"{code} " f"endmodule", { "CLK1": pinout['C1'], "CLK2": pinout['C2'], "O": pinout[macrocell['pad']], "dff": str(601 + macrocell_idx), }, f"{device_name}-{package}", strategy={"logic_doubling": "on"})
def run(code, **kwargs): return toolchain.run( f"module top(input CLK1, {', '.join(goe_pads)}, output O); " f"wire Y; OR{len(goe_pads)+1} o({', '.join(goe_pads)}, CLK1, Y); " f"{code} " f"endmodule", { 'O': pinout[macrocell['pad']], 'CLK1': pinout['C1'], **{ goe_pad: pinout[goe_pad[:-4]] for goe_pad in goe_pads }, }, f"{device_name}-{package}", **kwargs)
def run(code): return toolchain.run( f"module top(input C1, C2, E1, R, I, output Q); " f"{code} " f"endmodule", { 'C1': pinout['C1'], 'C2': pinout['C2'], 'E1': pinout['E1'], 'R': pinout['R'], 'I': pinout[other_macrocell['pad']], 'Q': pinout[macrocell['pad']], }, f"{device_name}-{package}", strategy={'xor_synthesis': 'on'})
def run(code): return toolchain.run( f"module top(input CLK1, OE1, ...); " f"{code} " f"endmodule", { 'CLK1': pinout['C1'], 'OE1': pinout['E1'], 'IO': pinout[macrocell['pad']], 'ff': str(601 + macrocell_idx), }, f"{device_name}-{package}", strategy={ "logic_doubling": "on", "fast_inlatch": "on" })
def run(code, **kwargs): return toolchain.run( f"module top(input CLK1, CLK2, output O1, O2); " f"{code} " f"endmodule", { 'CLK1': pinout['C1'], 'CLK2': pinout['C2'], 'O1': pinout[other1_macrocell['pad']], 'O2': pinout[other2_macrocell['pad']], 'dff1': str(601 + macrocell_idx), # Pretty gross to rely on autogenerated names, but the other # netlist/constraint sets I came up were even less reliable. 'Com_Ctrl_13': str(601 + macrocell_idx), }, f"{device_name}-{package}", **kwargs)
def run(code): return toolchain.run( f"module top(input C1, C2, E1, R, output O); " f"wire Q; TRI tri(Q, 1'b0, O); " f"wire Y1, Y2, Y3; " f"AND2 a1(C1, C2, Y1); " f"AND2 a2(C2, E1, Y2); " f"AND2 a3(E1, R, Y3); " f"{code} " f"endmodule", { 'C1': pinout['C1'], 'C2': pinout['C2'], 'E1': pinout['E1'], 'R': pinout['R'], 'ff': str(601 + macrocell_idx), }, f"{device_name}-{package}", strategy={'xor_synthesis': 'on'})
def run(code, **kwargs): return toolchain.run( f"module top(input GCLR, GCLK1, GCLK2, GCLK3, " f" input GOE1, GOE2, GOE3, GOE4, GOE5, GOE6, " f" output Q); " f"{code} " f"endmodule", { 'GCLR': pinout['R'], 'GCLK1': pinout['C1'], 'GCLK2': pinout['C2'], 'GCLK3': pinout[gclk3_pad], **{ f"GOE{1+n}": pinout[pad[:-4]] for n, pad in enumerate(goe_pads) }, 'Q': pinout[device['macrocells']['MC1']['pad']], }, f"{device_name}-{package}", **kwargs)
def run_fb(macrocell_idx, macrocell_name): for other1_macrocell_name, other1_macrocell in device[ 'macrocells'].items(): if other1_macrocell_name != macrocell_name: break else: assert False for other2_macrocell_name, other2_macrocell in device[ 'macrocells'].items(): if (other2_macrocell_name != macrocell_name and other2_macrocell_name != other1_macrocell_name): break else: assert False pins = [ f"OEA+:{pinout['C1']}", f"OEB+:{pinout['C2']}", f"Y0+:{pinout[device['macrocells'][other1_macrocell_name]['pad']]}", f"Y1+:{pinout[device['macrocells'][other2_macrocell_name]['pad']]}" ] return toolchain.run(f""" #$ PINS 4 {' '.join(pins)} #$ PROPERTY ATMEL Global_OE = Y0 #$ PROPERTY ATMEL OE_node = {str(601 + macrocell_idx)} .i 2 .o 4 .type f .ilb OEA OEB .ob Y0 Y0.OE Y1 Y1.OE .phase 1111 .p 2 -- 0000 00 0101 .e """, None, f"{device_name}-{package}", strategy={'logic_doubling': 'on'}, format='tt')
def run_o(**kwargs): return toolchain.run( f"module top(output O); assign O = 1'b0; endmodule", {'O': pinout[macrocell['pad']]}, f"{device_name}-{package}", strategy=kwargs)
for index, macrocell_name in enumerate(device['macrocells']) } tt2 = foldback_tt2(src_nodes=[ macrocell_nodes[macrocell_name] for macrocell_name in other_block['macrocells'] ], dst_nodes=[ macrocell_nodes[macrocell_name] for macrocell_name in block['macrocells'] ]) # The fitter completely disregards any `PINNODE 3xx = net;` constraints, and instead # assigns foldbacks consistently from last to first macrocell in the block. However, # the actual routing is somewhat random, so we have to examine all related pterms. f_prev = toolchain.run(tt2, {}, f"{device_name}-{package}", format='tt') folds = [] seen_pt1s = set() seen_pt4s = set() for index in range(len(block['macrocells'])): folds.append(f"FbY{1+index}") f_curr = toolchain.run( tt2, {}, f"{device_name}-{package}", format='tt', strategy={'Foldback_Logic': ','.join(folds)}) # The macrocell that gained a foldback now had PT1 enabled, find it. new_pt1s = set() for macrocell_name in block['macrocells']: