blob: 2053a43e4a8e7cc56aaffcb71302e347f5390d86 [file]
# Copyright 2020 Project U-Ray Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import numpy as np
import sys
X = 100
root = sys.argv[1]
pins = []
bank_to_pins = {}
bank_to_iotype = {}
site_to_pin = {}
pin_to_iol = {}
with open (root + "/iologic.txt", "r") as iof:
for line in iof:
sl = line.strip().split(",")
if len(sl) < 5:
continue
pin = sl[0]
bank = int(sl[1])
func = sl[2]
site_name = sl[3]
site_type = sl[4]
iol_site = sl[5]
pins.append((pin, bank, func, site_name, site_type, iol_site))
if bank not in bank_to_pins:
bank_to_pins[bank] = []
bank_to_pins[bank].append(pin)
if bank not in bank_to_iotype:
bank_to_iotype[bank] = site_type.split("_")[0]
site_to_pin[site_name] = pin
sr_sig = {
"FDRE": "R", "FDSE": "S", "FDPE": "PRE", "FDCE": "CLR",
}
def make_ioff(name, sig_c, sig_d, sig_r, sig_e, sig_q, f):
fftype = np.random.choice(["FDRE", "FDSE", "FDPE", "FDCE"])
print("""
{t} #(.INIT({init})) {n} (
.C({c}), .{sr}({r}), .CE({e}), .D({d}), .Q({q})
);
""".format(
t=fftype,
init=np.random.randint(0, 2),
n=name,
sr=sr_sig[fftype],
c=sig_c, r=sig_r, e=sig_e, d=sig_d, q=sig_q
), file=f)
def make_iddr(name, allow_inv, sig_c, sig_cb, sig_r, sig_d, sig_q1, sig_q2, f):
print("""
IDDRE1 #(.DDR_CLK_EDGE("{e}"), .IS_C_INVERTED({ci}), .IS_CB_INVERTED({cbi})) {n} (
.C({c}), .CB({cb}), .R({r}), .D({d}), .Q1({q1}), .Q2({q2})
);
""".format(
e=np.random.choice(["OPPOSITE_EDGE", "SAME_EDGE", "SAME_EDGE_PIPELINED"]),
ci=np.random.randint(0, 2) if allow_inv else 0,
cbi=np.random.randint(0, 2) if allow_inv else 1,
n=name,
c=sig_c, cb=sig_cb, r=sig_r, d=sig_d, q1=sig_q1, q2=sig_q2
), file=f)
def make_oddr(name, srval, sig_c, c_inv, sig_d1, sig_d2, sig_sr, sig_q, f):
print("""
ODDRE1 #(.IS_C_INVERTED({ci}), .SRVAL({srv})) {n} (
.C({c}), .D1({d1}), .D2({d2}), .SR({sr}), .Q({q})
);
""".format(
ci=1 if c_inv else 0,
srv=srval,
n=name,
c=sig_c, d1=sig_d1, d2=sig_d2, sr=sig_sr, q=sig_q
), file=f)
def make_iserdes(name, sig_clk, sig_clkdiv, sig_clk_b, sig_d, sig_rst, sig_q, f):
print("""
ISERDESE3 #(
.DATA_WIDTH({dw}),
.IS_CLK_B_INVERTED({cbi}),
.IS_CLK_INVERTED({ci}),
.IS_RST_INVERTED({ri})
) {n} (
.Q({q}),
.CLK({clk}), .CLKDIV({clkdiv}), .CLK_B({clk_b}), .D({d}), .RST({rst})
);
""".format(
dw=np.random.choice([4, 8]),
cbi=np.random.randint(0, 2),
ci=np.random.randint(0, 2),
ri=np.random.randint(0, 2),
n=name,
q=sig_q,
clk=sig_clk, clkdiv=sig_clkdiv, clk_b=sig_clk_b, rst=sig_rst, d=sig_d
), file=f)
def make_oserdes(name, sig_clk, sig_clkdiv, sig_d, sig_rst, sig_t, sig_oq, sig_t_out, f):
print("""
OSERDESE3 #(
.DATA_WIDTH({dw}),
.INIT({init}),
.IS_CLKDIV_INVERTED({cdi}),
.IS_CLK_INVERTED({ci}),
.IS_RST_INVERTED({ri}),
.OSERDES_D_BYPASS("{db}"),
.OSERDES_T_BYPASS("{dt}")
) {n} (
.OQ({oq}), .T_OUT({t_out}),
.CLK({clk}), .CLKDIV({clkdiv}), .D({d}), .RST({rst}), .T({t})
);
""".format(
dw=np.random.choice([4, 8]),
init=np.random.randint(0, 2),
cdi=np.random.randint(0, 2),
ci=np.random.randint(0, 2),
ri=np.random.randint(0, 2),
db=np.random.choice(["TRUE", "FALSE"]),
dt=np.random.choice(["TRUE", "FALSE"]),
n=name,
oq=sig_oq, t_out=sig_t_out,
clk=sig_clk, clkdiv=sig_clkdiv, d=sig_d, rst=sig_rst, t=sig_t,
), file=f)
def make_idelay(name, del_fmt, time_dly, sig_clk, sig_ce, sig_inc, sig_load, sig_rst, sig_en_vtc, sig_datain, sig_idatain, sig_dataout, f):
print("""
IDELAYE3 #(
.DELAY_SRC("{ds}"),
.DELAY_TYPE("{dt}"),
.DELAY_VALUE({dv}),
.DELAY_FORMAT("{df}"),
.UPDATE_MODE("{um}"),
.IS_CLK_INVERTED({ci}),
.IS_RST_INVERTED({ri}),
.LOOPBACK("{lb}"),
.REFCLK_FREQUENCY(300.0)
) {n} (
.CLK({clk}), .CE({ce}), .INC({inc}), .LOAD({load}), .RST({rst}), .EN_VTC({en_vtc}),
.DATAIN({datain}), .IDATAIN({idatain}), .DATAOUT({dataout})
);
""".format(
ds=np.random.choice(["DATAIN", "IDATAIN"]),
dt=np.random.choice(["FIXED", "VAR_LOAD", "VARIABLE"]),
dv=np.random.randint(0, 512) if del_fmt == "COUNT" else time_dly,
df=del_fmt,
um=np.random.choice(["ASYNC", "SYNC", "MANUAL"]),
ci=np.random.randint(0, 2),
ri=np.random.randint(0, 2),
lb=np.random.choice(["FALSE", "TRUE"]),
n=name,
clk=sig_clk, ce=sig_ce, inc=sig_inc, load=sig_load, rst=sig_rst, en_vtc=sig_en_vtc,
datain=sig_datain, idatain=sig_idatain, dataout=sig_dataout
), file=f)
def make_odelay(name, del_fmt, time_dly, sig_clk, sig_ce, sig_inc, sig_load, sig_rst, sig_en_vtc, sig_odatain, sig_dataout, f):
print("""
ODELAYE3 #(
.DELAY_TYPE("{dt}"),
.DELAY_VALUE({dv}),
.DELAY_FORMAT("{df}"),
.UPDATE_MODE("{um}"),
.IS_CLK_INVERTED({ci}),
.IS_RST_INVERTED({ri}),
.REFCLK_FREQUENCY(300.0)
) {n} (
.CLK({clk}), .CE({ce}), .INC({inc}), .LOAD({load}), .RST({rst}), .EN_VTC({en_vtc}),
.ODATAIN({odatain}), .DATAOUT({dataout})
);
""".format(
dt=np.random.choice(["FIXED", "VAR_LOAD", "VARIABLE"]),
dv=np.random.randint(0, 512) if del_fmt == "COUNT" else time_dly,
df=del_fmt,
um=np.random.choice(["ASYNC", "SYNC", "MANUAL"]),
ci=np.random.randint(0, 2),
ri=np.random.randint(0, 2),
n=name,
clk=sig_clk, ce=sig_ce, inc=sig_inc, load=sig_load, rst=sig_rst, en_vtc=sig_en_vtc,
odatain=sig_odatain, dataout=sig_dataout
), file=f)
for x in range(X):
used_pins = []
io_config = []
lut_inputs = []
lut_outputs = []
bank_iref = {}
def inp():
sig = "li[%d]" % len(lut_inputs)
lut_inputs.append(sig)
return sig
def outp():
sig = "lo[%d]" % len(lut_outputs)
lut_outputs.append(sig)
return sig
def maybe_inp():
return inp() if np.random.choice([True, False]) else ""
def maybe_outp():
return outp() if np.random.choice([True, False]) else ""
def clock():
return ("gclk[%d]" % np.random.randint(0, 6))
def maybe_outp_z():
return outp() if np.random.choice([True, False]) else "null"
def maybe(x):
return x if np.random.choice([True, False]) else ""
io_config = []
used_pins = []
for i in range(len(pins)):
if "XIPHY" in pins[i][5]:
prim = np.random.choice([None, None, None, None, None, "IBUF", "OBUF", "OBUFT", "IOBUF"])
else:
prim = np.random.choice([None, None, None, None, None, "IBUF", "OBUF", "OBUFT", "IOBUF", "IOBUFE3"])
if prim is not None:
io_config.append(prim)
used_pins.append(pins[i])
with open(root + "/iologic/iologic%d.v" % x, "w") as f:
print("module top(", file=f);
for i, prim in enumerate(io_config):
if prim == "IBUF":
print("input p%d%s" % (i, "," if i < len(io_config)-1 else ""), file=f)
elif prim in ("OBUF", "OBUFT"):
print("output p%d%s" % (i, "," if i < len(io_config)-1 else ""), file=f)
elif prim in ("IOBUF", "IOBUFE3"):
print("inout p%d%s" % (i, "," if i < len(io_config)-1 else ""), file=f)
print(");", file=f)
print("wire null;", file=f)
print("wire [5:0] gclk;", file=f)
print("BUFG bufg_i[5:0] (.I({%s, %s, %s, %s, %s, %s}), .O(gclk));" % tuple(outp() for i in range(6)), file=f)
del_groups = set()
for i, prim in enumerate(io_config):
print("wire p{i}i, p{i}i_d, p{i}o, p{i}o_d, p{i}t;".format(i=i), file=f)
print("(* KEEP, DONT_TOUCH *)", file=f)
if prim == "IBUF":
print("""
IBUF buf_{i} (
.I(p{i}),
.O(p{i}o)
);
""".format(i=i), file=f)
elif prim == "OBUF":
print("""
OBUF buf_{i} (
.O(p{i}),
.I(p{i}i_d)
);
""".format(i=i), file=f)
elif prim == "OBUFT":
print("""
OBUFT buf_{i} (
.O(p{i}),
.T(p{i}t),
.I(p{i}i_d)
);
""".format(i=i), file=f)
elif prim == "IOBUF":
print("""
IOBUF buf_{i} (
.IO(p{i}),
.T(p{i}t),
.I(p{i}i_d),
.O(p{i}o)
);
""".format(i=i), file=f)
elif prim == "IOBUFE3":
print("""
IOBUFE3 buf_{i} (
.IO(p{i}),
.T(p{i}t),
.I(p{i}i_d),
.O(p{i}o),
.DCITERMDISABLE({dci_dis})
);
""".format(i=i, dci_dis=maybe_outp()), file=f)
iol_site = used_pins[i][5]
idelay_used = False
odelay_used = False
if "BITSLICE" in iol_site:
idelay_used = np.random.choice([False, True])
odelay_used = np.random.choice([False, True])
del_fmt = np.random.choice(["TIME", "COUNT"])
time_dly = int(6666.667/np.random.uniform(7, 666))
slow_clk = clock()
group = "B" + str(used_pins[i][1])
if idelay_used:
print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"IDELAY\", IODELAY_GROUP=\"%s\" *)" % (iol_site, group), file=f)
make_idelay(name="idelay%d" % i, del_fmt=del_fmt, time_dly=time_dly, sig_clk=maybe(slow_clk), sig_ce=maybe_outp(),
sig_inc=maybe_outp(), sig_load=maybe_outp(), sig_rst=maybe_outp(), sig_en_vtc=maybe_outp(),
sig_datain=maybe_outp(), sig_idatain="p%do"%i, sig_dataout="p%do_d"%i, f=f)
del_groups.add(group)
if odelay_used:
print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"ODELAY\", IODELAY_GROUP=\"%s\" *)" % (iol_site, group), file=f)
make_odelay(name="odelay%d" % i, del_fmt=del_fmt, time_dly=time_dly, sig_clk=maybe(slow_clk), sig_ce=maybe_outp(),
sig_inc=maybe_outp(), sig_load=maybe_outp(), sig_rst=maybe_outp(), sig_en_vtc=maybe_outp(),
sig_odatain="p%di"%i, sig_dataout="p%di_d"%i, f=f)
del_groups.add(group)
input_mode = np.random.choice(["NONE", "BYP", "FF", "DDR", "SERDES"])
if input_mode == "BYP":
print("assign %s = p%do%s;" % (inp(), i, "_d" if idelay_used else ""), file=f)
elif input_mode == "FF" and prim in ("IBUF", "IOBUF", "IOBUFE3"):
print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"IN_FF\" *)" % iol_site, file=f)
make_ioff(name="iff%d" % i, sig_c=slow_clk, sig_d="p%do_d" % i if idelay_used else ("p%do" % i),
sig_r=maybe_outp(), sig_e=maybe_outp(), sig_q=maybe_inp(), f=f)
elif input_mode == "DDR" and prim in ("IBUF", "IOBUF", "IOBUFE3"):
print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"ISERDES\" *)" % iol_site, file=f)
make_iddr(name="iddr%d" % i, allow_inv=True, sig_c=slow_clk, sig_cb=clock(),
sig_r=maybe_outp(), sig_d="p%do_d" % i if idelay_used else "p%do" % i,
sig_q1=maybe_inp(), sig_q2=maybe_inp(), f=f)
elif input_mode == "SERDES":
print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"ISERDES\" *)" % iol_site, file=f)
make_iserdes(name="iserdes%d" % i, sig_clk=clock(), sig_clkdiv=slow_clk, sig_clk_b=clock(),
sig_d="p%do_d" % i if idelay_used else "p%do" % i, sig_rst=maybe_outp(),
sig_q="{%s}" % (", ".join([inp() for i in range(8)])), f=f)
output_mode = np.random.choice(["NONE", "BYP", "FF", "DDR", "SERDES"])
if output_mode == "SERDES":
print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"OSERDES\" *)" % iol_site, file=f)
make_oserdes(name="oserdes%d" % i, sig_clk=clock(), sig_clkdiv=slow_clk, sig_d="{%s}" % (", ".join([maybe_outp_z() for i in range(8)])),
sig_rst=maybe_outp(), sig_t=maybe_outp(), sig_oq="p%di" % i, sig_t_out="p%dt" % i, f=f)
else:
if output_mode == "BYP" or odelay_used:
print("assign p%di = %s;" % (i, outp()), file=f)
print("assign p%dt = %s;" % (i, outp()), file=f)
elif output_mode == "FF" and prim in ("OBUF", "OBUFT", "IOBUF", "IOBUFE3"):
print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"OUT_FF\" *)" % iol_site, file=f)
make_ioff(name="off%d" % i, sig_c=slow_clk, sig_d=maybe_inp(),
sig_r=maybe_outp(), sig_e=maybe_outp(), sig_q="p%di" % i, f=f)
elif output_mode == "DDR":
print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"OSERDES\" *)" % iol_site, file=f)
make_oddr(name="oddr%d" % i, srval=np.random.randint(0, 2), sig_c=slow_clk, c_inv=np.random.choice([True, False]),
sig_d1=outp(), sig_d2=outp(), sig_sr=maybe_outp(), sig_q="p%di" % i, f=f)
elif "HDIO" in iol_site:
slow_clk = clock()
reset = maybe_outp()
enable = maybe_outp()
input_mode = np.random.choice(["NONE", "BYP", "FF", "DDR"])
if input_mode == "BYP":
print("assign %s = p%do;" % (inp(), i), file=f)
elif input_mode == "FF" and prim in ("IBUF", "IOBUF"):
print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"IPFF\" *)" % iol_site, file=f)
make_ioff(name="iff%d" % i, sig_c=slow_clk, sig_d="p%do" % i,
sig_r=reset, sig_e=maybe_outp(), sig_q=maybe_inp(), f=f)
elif input_mode == "DDR":
print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"IDDR\" *)" % iol_site, file=f)
make_iddr(name="iddr%d" % i, allow_inv=False, sig_c=slow_clk, sig_cb=clock(),
sig_r=reset, sig_d="p%do" % i,
sig_q1=maybe_inp(), sig_q2=maybe_inp(), f=f)
output_mode = np.random.choice(["NONE", "BYP", "FF", "DDR"])
tristate_mode = np.random.choice(["NONE", "BYP", "FF", "DDR"])
srval = np.random.randint(0, 2)
if output_mode == "BYP":
print("assign p%di = %s;" % (i, outp()), file=f)
elif output_mode == "FF" and prim in ("OBUF", "OBUFT", "IOBUF"):
print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"OPFF\" *)" % iol_site, file=f)
make_ioff(name="off%d" % i, sig_c=slow_clk, sig_d=maybe_inp(),
sig_r=reset, sig_e=enable, sig_q="p%di" % i, f=f)
elif output_mode == "DDR" and prim in ("OBUF", "OBUFT", "IOBUF"):
#print("(* KEEP, DONT_TOUCH, LOC=\"%s\" *)" % iol_site, file=f)
make_oddr(name="oddr%d" % i, srval=srval, sig_c=slow_clk, c_inv=False,
sig_d1=maybe_outp(), sig_d2=maybe_outp(), sig_sr=reset, sig_q="p%di" % i, f=f)
tristate_mode = "DDR"
if tristate_mode == "BYP":
print("assign p%dt = %s;" % (i, outp()), file=f)
elif tristate_mode == "FF" and prim in ("OBUFT", "IOBUF"):
print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"TFF\" *)" % iol_site, file=f)
make_ioff(name="tff%d" % i, sig_c=slow_clk, sig_d=maybe_inp(),
sig_r=reset, sig_e=enable, sig_q="p%dt" % i, f=f)
elif tristate_mode == "DDR" and prim in ("OBUFT", "IOBUF") and output_mode == "DDR":
#print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"OPTFF\" *)" % iol_site, file=f)
make_oddr(name="tddr%d" % i, srval=srval, sig_c=slow_clk, c_inv=False,
sig_d1=maybe_outp(), sig_d2=maybe_outp(), sig_sr=reset, sig_q="p%dt" % i, f=f)
if not odelay_used:
print("assign p%di_d = p%di;" % (i, i), file=f)
print("", file=f)
for group in sorted(del_groups):
print("(* KEEP, DONT_TOUCH, IODELAY_GROUP=\"%s\" *)" % group, file=f)
print(" IDELAYCTRL ctrl_{n} (.REFCLK({c}), .RST({r}), .RDY({rd}));".format(
n=group, c=clock(), r=maybe_outp(), rd=maybe_inp(),
), file=f)
print("wire [%d:0] li;" % (len(lut_inputs)-1), file=f)
print("wire [%d:0] lo;" % (len(lut_outputs)-1), file=f)
for i in range(max(len(lut_inputs)//6 + 1, len(lut_outputs))):
ip = ["1'b0" if (i * 6 + j) >= len(lut_inputs) else "li[%d]" % (i * 6 + j) for j in range(6)]
op = "lo[%d]" % i if i < len(lut_outputs) else ""
print("""
(* KEEP, DONT_TOUCH *)
LUT6 lut{i} (.I0({i0}), .I1({i1}), .I2({i2}), .I3({i3}), .I4({i4}), .I5({i5}), .O({o}));
""".format(
i=i, i0=ip[0], i1=ip[1], i2=ip[2], i3=ip[3], i4=ip[4], i5=ip[5], o=op,
), file=f)
print("endmodule", file=f)
with open(root + "/iologic/iologic%d.xdc" % x, "w") as f:
for i, prim in enumerate(io_config):
pin = used_pins[i][0]
print("set_property PACKAGE_PIN %s [get_ports {p%d}]" % (pin, i), file=f)
print("set_property IOSTANDARD LVCMOS18 [get_ports {p%d}]" % (i), file=f)
with open(root + "/iologic/iologic%d.tcl" % x, "w") as f:
print("add_files %s" % (root + ("/iologic/iologic%d.v" % x)), file=f)
print("add_files %s" % (root + ("/iologic/iologic%d.xdc" % x)), file=f)
print("synth_design -top top -part xczu7ev-ffvf1517-2-e", file=f)
print("set_property SEVERITY {Warning} [get_drc_checks NSTD-1]", file=f)
print("set_property SEVERITY {Warning} [get_drc_checks UCIO-1]", file=f)
print("set_property SEVERITY {Warning} [get_drc_checks AVAL-*]", file=f)
print("set_property SEVERITY {Warning} [get_drc_checks REQP-*]", file=f)
print("set_property SEVERITY {Warning} [get_drc_checks BIVR-*]", file=f)
print("set_property SEVERITY {Warning} [get_drc_checks BSCK-*]", file=f)
print("set_property SEVERITY {Warning} [get_drc_checks PLHDIO-1]", file=f)
print("set_property SEVERITY {Warning} [get_drc_checks PDRC-203]", file=f)
print("set_property SEVERITY {Warning} [get_drc_checks ADEF-911]", file=f)
print("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets]", file=f)
print("opt_design", file=f)
print("place_design", file=f)
print("route_design", file=f)
print("source ../fuzzpins.tcl", file=f)
print("set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]", file=f)
print("write_checkpoint -force %s/specimen_io/iologic%d.dcp" % (root, x), file=f)
print("write_edif -force %s/specimen_io/iologic%d.edf" % (root, x), file=f)
print("write_bitstream -force %s/specimen_io/iologic%d.bit" % (root, x), file=f)
with open(root + "/iologic/run.sh", "w") as f:
print("#/usr/bin/env bash", file=f)
print("set -ex", file=f)
print("vivado -mode batch -nolog -nojournal -source iologic$1.tcl", file=f)
print("if [ $? -eq 0 ]; then", file=f)
print(" ../../ultra/tools/dump_bitstream %s/specimen_io/iologic$1.bit %s/frames.txt > %s/specimen_io/iologic$1.dump" % (root, root, root), file=f)
print(" python3 ../../ultra/tools/bits_to_tiles.py %s/tilebits.json %s/specimen_io/iologic$1.dump > %s/specimen_io/iologic$1.tbits" % (root, root, root), file=f)
#print(" rm %s/specimen_io/iologic$1.bit" % (root, ), file=f)
#print(" rm %s/specimen_io/iologic$1.dump" % (root, ), file=f)
print("else", file=f)
print(" rm %s/specimen_io/iologic$1.dump" % (root, ), file=f)
print(" rm %s/specimen_io/iologic$1.tbits" % (root, ), file=f)
print(" rm %s/specimen_io/iologic$1.dcp" % (root, ), file=f)
print(" rm %s/specimen_io/iologic$1.bit" % (root, ), file=f)
print(" rm %s/specimen_io/iologic$1.features" % (root, ), file=f)
print("fi", file=f)
with open(root + "/iologic/Makefile", "w") as f:
print("all: %s" % " ".join(["%d.done" % i for i in range(X)]), file=f)
print("", file=f)
print("%.done: ", file=f)
print("\tbash run.sh $*", file=f)
print("\ttouch $@", file=f)
print("", file=f)
print("clean: ", file=f)
print("\trm -f *.done", file=f)