remove legacy code, now feature complete with new scripts

This commit is contained in:
Fischer Moseley 2023-02-05 15:49:23 -05:00
parent 030a841f53
commit 566a3624d8
5 changed files with 211 additions and 388 deletions

View File

@ -1,5 +0,0 @@
import os
os.system('echo "#!/usr/bin/python3" > manta')
os.system("cat manta.py >> manta")
os.system("chmod +x manta")

View File

@ -26,21 +26,21 @@ outfile = f"{of}/out.bit"
logfile = f"{of}/build.log"
synthrpt = [
"report_timing",
"report_timing_summary",
"report_utilization",
]
"report_timing",
"report_timing_summary",
"report_utilization",
]
placerpt = synthrpt.copy()
placerpt.extend(['report_clock_utilization'])
placerpt.extend(["report_clock_utilization"])
routerpt = [
'report_drc',
'report_power',
'report_route_status',
'report_timing',
'report_timing_summary',
]
"report_drc",
"report_power",
"report_route_status",
"report_timing",
"report_timing_summary",
]
usagestr = f"""
{progname}: build SystemVerilog code remotely for 2022 6.205 labs
@ -54,190 +54,248 @@ options:
-o: set the output products directory (default is {of})
"""
def debuglog(s):
if verbose: print(s)
if verbose:
print(s)
def usage():
print(usagestr)
sys.exit(1)
print(usagestr)
sys.exit(1)
def getargs():
global diagnostics
global quiet
global machine
global logfile
global outfile
global projectdir
global of
global verbose
global diagnostics
global quiet
global machine
global logfile
global outfile
global projectdir
global of
global verbose
try:
opts, args = getopt.getopt(sys.argv[1:], "dm:o:p:qv")
except getopt.GetoptError as err:
print(err)
usage()
try:
opts, args = getopt.getopt(sys.argv[1:], "dm:o:p:qv")
except getopt.GetoptError as err:
print(err)
usage()
if args: usage()
for o, v in opts:
if o == '-d': diagnostics = True
elif o == '-q': quiet = True
elif o == '-m': machine = v
elif o == '-p': projectdir = v
elif o == '-o': of = v
elif o == '-v': verbose = True
else:
print(f"unrecognized option {o}")
usage()
if args:
usage()
for o, v in opts:
if o == "-d":
diagnostics = True
elif o == "-q":
quiet = True
elif o == "-m":
machine = v
elif o == "-p":
projectdir = v
elif o == "-o":
of = v
elif o == "-v":
verbose = True
else:
print(f"unrecognized option {o}")
usage()
outfile = f"{of}/out.bit"
logfile = f"{of}/build.log"
outfile = f"{of}/out.bit"
logfile = f"{of}/build.log"
def make_posix(path):
return str(pathlib.Path(path).as_posix())
return str(pathlib.Path(path).as_posix())
def regfiles():
ftt = {}
debuglog(f"projectdir is {projectdir}")
for dirpath, subdirs, files in os.walk(projectdir):
if 'src' not in dirpath and 'xdc' not in dirpath and 'data' not in dirpath and 'ip' not in dirpath:
continue
if dirpath.startswith("./"): dirpath = dirpath[2:]
for file in files:
fpath = os.path.join(dirpath, file)
debuglog(f"considering {fpath}")
fpath = make_posix(fpath)
ftt = {}
debuglog(f"projectdir is {projectdir}")
for dirpath, subdirs, files in os.walk(projectdir):
if (
"src" not in dirpath
and "xdc" not in dirpath
and "data" not in dirpath
and "ip" not in dirpath
):
continue
if dirpath.startswith("./"):
dirpath = dirpath[2:]
for file in files:
fpath = os.path.join(dirpath, file)
debuglog(f"considering {fpath}")
fpath = make_posix(fpath)
if file.lower().endswith('.v'): ftt[fpath] = 'source'
elif file.lower().endswith('.sv'): ftt[fpath] = 'source'
elif file.lower().endswith('.vh'): ftt[fpath] = 'source'
elif file.lower().endswith('.svh'): ftt[fpath] = 'source'
elif file.lower().endswith('.xdc'): ftt[fpath] = 'xdc'
elif file.lower().endswith('.mem'): ftt[fpath] = 'mem'
elif file.lower().endswith('.xci'): ftt[fpath] = 'ip'
elif file.lower().endswith('.prj'): ftt[fpath] = 'mig'
if file.lower().endswith(".v"):
ftt[fpath] = "source"
elif file.lower().endswith(".sv"):
ftt[fpath] = "source"
elif file.lower().endswith(".vh"):
ftt[fpath] = "source"
elif file.lower().endswith(".svh"):
ftt[fpath] = "source"
elif file.lower().endswith(".xdc"):
ftt[fpath] = "xdc"
elif file.lower().endswith(".mem"):
ftt[fpath] = "mem"
elif file.lower().endswith(".xci"):
ftt[fpath] = "ip"
elif file.lower().endswith(".prj"):
ftt[fpath] = "mig"
debuglog(f"elaborated file list {ftt}")
return ftt
debuglog(f"elaborated file list {ftt}")
return ftt
# messages are newline delineated per lab-bs.1
# utilize this to cheat a little bit
def spqsend(p, msg):
debuglog(f"writing {len(msg)} bytes over the wire")
debuglog(f"full message: {msg}")
p.stdin.write(msg + b'\n')
p.stdin.flush()
debuglog(f"writing {len(msg)} bytes over the wire")
debuglog(f"full message: {msg}")
p.stdin.write(msg + b"\n")
p.stdin.flush()
def spsend(p, msg):
debuglog(f"running {msg}")
p.stdin.write((msg + '\n').encode())
p.stdin.flush()
debuglog(f"running {msg}")
p.stdin.write((msg + "\n").encode())
p.stdin.flush()
def sprecv(p):
l = p.stdout.readline().decode()
debuglog(f"got {l}")
return l
l = p.stdout.readline().decode()
debuglog(f"got {l}")
return l
def xsprecv(p):
l = sprecv(p)
if (l.startswith("ERR")):
print("received unexpected server error!")
print(l)
sys.exit(1)
return l
l = sprecv(p)
if l.startswith("ERR"):
print("received unexpected server error!")
print(l)
sys.exit(1)
return l
def spstart(xargv):
debuglog(f"spawning {xargv}")
p = subprocess.PIPE
return subprocess.Popen(xargv, stdin=p, stdout=p, stderr=p)
debuglog(f"spawning {xargv}")
p = subprocess.PIPE
return subprocess.Popen(xargv, stdin=p, stdout=p, stderr=p)
def copyfiles(p, ftt):
for f, t in ftt.items():
fsize = os.path.getsize(f)
with open(f, 'rb') as fd:
spsend(p, f"write {f} {fsize}")
time.sleep(0.1) #?
spqsend(p, fd.read())
xsprecv(p)
for f, t in ftt.items():
fsize = os.path.getsize(f)
with open(f, "rb") as fd:
spsend(p, f"write {f} {fsize}")
time.sleep(0.1) # ?
spqsend(p, fd.read())
xsprecv(p)
spsend(p, f"type {f} {t}")
xsprecv(p)
spsend(p, f"type {f} {t}")
xsprecv(p)
# size message returns ... %zu bytes
def readfile(p, file, targetfile):
spsend(p, f"size {file}")
size = int(xsprecv(p).split()[-2])
spsend(p, f"read {file}")
spsend(p, f"size {file}")
size = int(xsprecv(p).split()[-2])
spsend(p, f"read {file}")
with open(targetfile, "wb+") as fd:
fd.write(p.stdout.read(size))
xsprecv(p)
with open(targetfile, 'wb+') as fd:
fd.write(p.stdout.read(size))
xsprecv(p)
def build(p):
cmd = "build"
if diagnostics: cmd += " -d"
if quiet: cmd += " -q"
cmd += f" obj"
cmd = "build"
if diagnostics:
cmd += " -d"
if quiet:
cmd += " -q"
cmd += f" obj"
print(f"Output target will be {outfile}")
print(f"Output target will be {outfile}")
spsend(p, cmd)
print("Building your code ... (this may take a while, be patient)")
result = sprecv(p)
spsend(p, cmd)
print("Building your code ... (this may take a while, be patient)")
result = sprecv(p)
if result.startswith("ERR"): print("Something went wrong!")
else:
readfile(p, "obj/out.bit", outfile)
print(f"Build succeeded, output at {outfile}")
readfile(p, "obj/build.log", logfile)
print(f"Log file available at {logfile}")
if result.startswith("ERR"):
print("Something went wrong!")
else:
readfile(p, "obj/out.bit", outfile)
print(f"Build succeeded, output at {outfile}")
readfile(p, "obj/build.log", logfile)
print(f"Log file available at {logfile}")
if diagnostics:
for rpt in synthrpt:
readfile(p, f"obj/synthrpt_{rpt}.rpt", f"{of}/synthrpt_{rpt}.rpt")
for rpt in placerpt:
readfile(p, f"obj/placerpt_{rpt}.rpt", f"{of}/placerpt_{rpt}.rpt")
for rpt in routerpt:
readfile(p, f"obj/routerpt_{rpt}.rpt", f"{of}/routerpt_{rpt}.rpt")
print(f"Diagnostics available in {of}")
if (diagnostics):
for rpt in synthrpt:
readfile(p, f"obj/synthrpt_{rpt}.rpt", f"{of}/synthrpt_{rpt}.rpt")
for rpt in placerpt:
readfile(p, f"obj/placerpt_{rpt}.rpt", f"{of}/placerpt_{rpt}.rpt")
for rpt in routerpt:
readfile(p, f"obj/routerpt_{rpt}.rpt", f"{of}/routerpt_{rpt}.rpt")
print(f"Diagnostics available in {of}")
def main():
global p
getargs()
ftt = regfiles()
global p
getargs()
ftt = regfiles()
if not os.path.isdir(of):
print(f"output path {of} does not exist! create it or use -o?")
usage()
if platform.system() == 'Darwin' or platform.system() == 'Linux':
xargv = ['ssh', '-p', f"{port}", '-o', "StrictHostKeyChecking=no", '-o', 'UserKnownHostsFile=/dev/null']
if not os.path.isdir(of):
print(f"output path {of} does not exist! create it or use -o?")
usage()
elif platform.system() == 'Windows':
xargv = ['ssh', '-p', f"{port}", '-o', "StrictHostKeyChecking=no", '-o', 'UserKnownHostsFile=nul']
if platform.system() == "Darwin" or platform.system() == "Linux":
xargv = [
"ssh",
"-p",
f"{port}",
"-o",
"StrictHostKeyChecking=no",
"-o",
"UserKnownHostsFile=/dev/null",
]
else:
raise RuntimeError('Your OS is not recognized, unsure of how to format SSH command.')
xargv.append(f"{user}@{machine}")
p = spstart(xargv)
elif platform.system() == "Windows":
xargv = [
"ssh",
"-p",
f"{port}",
"-o",
"StrictHostKeyChecking=no",
"-o",
"UserKnownHostsFile=nul",
]
else:
raise RuntimeError(
"Your OS is not recognized, unsure of how to format SSH command."
)
xargv.append(f"{user}@{machine}")
p = spstart(xargv)
spsend(p, "help")
result = xsprecv(p)
debuglog(result)
copyfiles(p, ftt)
build(p)
spsend(p, "exit")
p.wait()
spsend(p, "help")
result = xsprecv(p)
debuglog(result)
copyfiles(p, ftt)
build(p)
spsend(p, "exit")
p.wait()
if __name__ == "__main__":
try: main()
except (Exception, KeyboardInterrupt) as e:
if p:
debuglog("killing ssh")
os.kill(p.pid, signal.SIGINT)
p.wait()
raise e
try:
main()
except (Exception, KeyboardInterrupt) as e:
if p:
debuglog("killing ssh")
os.kill(p.pid, signal.SIGINT)
p.wait()
raise e

View File

@ -1,71 +0,0 @@
import json
import yaml
from datetime import datetime
import os
# this works by taking a template file, parsing it for hooks, and then dropping in our spicy bits of verilog in those hooks.
# might update this later to just properly instantiate an ILA for us and we do this with parameters, but
# the fundamental thing i care about is that systemverilog does not live in this file.
fpath = 'ila.json' # will update for argv soon!
with open(fpath, 'r') as f:
config = json.load(f)
# make sure file is okay
assert config["probes"]
assert config["triggers"]
assert config["uart"] or config["ethernet"] # <- i have ideas hehe
def splice(source, find, replace):
# find all instances of find in the source, and replace with replace
#assert source.count(find) == 1
return source.replace(find, replace)
with open('src/ila_template.sv', 'r') as t:
ila_template = t.read()
# add timestamp and user
timestamp = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
ila_template = splice(ila_template, '@TIMESTAMP', timestamp);
user = os.environ.get('USER', os.environ.get('USERNAME'))
ila_template = splice(ila_template, '@USER', user);
# add trigger
trigger = [f'({trigger})' for trigger in config['triggers']]
trigger = ' || '.join(trigger)
ila_template = splice(ila_template, '@TRIGGER', trigger);
# add concat
concat = [name for name in config['probes']]
concat = ', '.join(concat)
concat = '{' + concat + '};'
ila_template = splice(ila_template, '@CONCAT', concat);
# add probes to ila module definition
probe_verilog = []
for name, width in config['probes'].items():
if width == 1:
probe_verilog.append(f'input wire {name},')
else:
probe_verilog.append(f'input wire [{width-1}:0] {name},')
probe_verilog = '\n\t'.join(probe_verilog)
ila_template = splice(ila_template, '@PROBES', probe_verilog);
# add sample width and depth
sample_width = sum([width for name, width in config['probes'].items()])
ila_template = splice(ila_template, '@SAMPLE_WIDTH', str(sample_width))
ila_template = splice(ila_template, '@SAMPLE_DEPTH', str(config['sample_depth']));
# add UART configuration
ila_template = splice(ila_template, '@DATA_WIDTH', str(int(config['uart']['data'])));
ila_template = splice(ila_template, '@BAUDRATE', str(config['uart']['baudrate']));
ila_template = splice(ila_template, '@CLK_FREQ_HZ', str(int(config['clock_freq'])));
# write output file
with open('src/ila.sv', 'w') as i:
i.write(ila_template)

View File

@ -278,7 +278,7 @@ def make_widths(config):
# [12, 1, 3] should produce
# [ (11,0) , (12, 12), (15,13) ]
widths = list(config["probes"].values())
widths = list(config["downlink"]["probes"].values())
parts = []
for i, width in enumerate(widths):
@ -306,7 +306,7 @@ def export_waveform(config, data, path):
) as writer:
# add probes to vcd file
vcd_probes = []
for name, width in config["probes"].items():
for name, width in config["downlink"]["probes"].items():
probe = writer.register_var("ila", name, "wire", size=width)
vcd_probes.append(probe)

View File

@ -1,159 +0,0 @@
from sys import argv
import json
import serial
from vcd import VCDWriter
from datetime import datetime
def check_config(config):
"""Check that configuration is okay"""
assert config["probes"]
assert config["triggers"]
assert config["uart"]
def setup_serial(ser, config):
ser.baudrate = config['uart']['baudrate']
ser.port = config['uart']['port']
ser.timeout = config['uart']['timeout']
# setup number of data bits
if config['uart']['data'] == 8:
ser.bytesize = serial.EIGHTBITS
elif config['uart']['data'] == 7:
ser.bytesize = serial.SEVENBITS
elif config['uart']['data'] == 6:
ser.bytesize = serial.SIXBITS
elif config['uart']['data'] == 5:
ser.bytesize = serial.FIVEBITS
else:
raise ValueError("Invalid number of data bits in UART configuration.")
# setup number of stop bits
if config['uart']['stop'] == 1:
ser.stopbits = serial.STOPBITS_ONE
elif config['uart']['stop'] == 1.5:
ser.stopbits = serial.STOPBITS_ONE_POINT_FIVE
elif config['uart']['stop'] == 2:
ser.stopbits = serial.STOPBITS_TWO
else:
raise ValueError("Invalid number of stop bits in UART configuration.")
# setup parity
if config['uart']['parity'] == 'none':
ser.parity = serial.PARITY_NONE
elif config['uart']['parity'] == 'even':
ser.parity = serial.PARITY_EVEN
elif config['uart']['parity'] == 'odd':
ser.parity = serial.PARITY_ODD
elif config['uart']['parity'] == 'mark':
ser.parity = serial.PARITY_MARK
elif config['uart']['parity'] == 'space':
ser.parity = serial.PARITY_SPACE
else:
raise ValueError("Invalid parity setting in UART configuration.")
def part_select(data, width):
top, bottom = width
assert top >= bottom
mask = 2**(top - bottom + 1) - 1
return (data >> bottom) & mask
def make_widths(config):
# {probe0, probe1, probe2}
# [12, 1, 3] should produce
# [ (11,0) , (12, 12), (15,13) ]
widths = list(config['probes'].values())
parts = []
for i, width in enumerate(widths):
if (i == 0):
parts.append( (width - 1, 0) )
else:
parts.append( ((parts[i-1][1] + width) , (parts[i-1][1] + 1)) )
# reversing this list is a little bit of a hack, should fix/document
return parts[::-1]
## Main Program
# parse args
if len(argv) == 1 or argv[1] == '-h':
print("""
run_ila.py: interface with the ILA on the FPGA, setting triggers and downlinking waveform data.
usage: python3 run_ila.py [config input file] [vcd output file]
options:
-h: print this help menu
-l: list all available serial devices
example: python3 run_ila.py ila.json ila.vcd
""")
exit()
elif argv[1] == '-l':
import serial.tools.list_ports
for info in serial.tools.list_ports.comports():
print(info)
elif len(argv) == 2:
config_fpath = argv[1]
vcd_fpath = 'ila.vcd'
elif len(argv) == 3:
config_fpath = argv[1]
vcd_fpath = argv[2]
else:
exit()
# read config
with open(config_fpath, 'r') as f:
config = json.load(f)
# obtain bytestream from FPGA
with serial.Serial() as ser:
setup_serial(ser, config)
ser.open()
ser.flushInput()
ser.write(b'\x30')
data = ser.read(4096)
# export VCD
vcd_file = open(vcd_fpath, 'w')
timestamp = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
with VCDWriter(vcd_file, timescale='10 ns', date=timestamp, version = 'openILA') as writer:
# add probes to vcd file
vcd_probes = []
for name, width in config['probes'].items():
probe = writer.register_var('ila', name, 'wire', size = width)
vcd_probes.append(probe)
# calculate bit widths for part selecting
widths = make_widths(config)
# slice data, and dump to vcd file
for timestamp, value in enumerate(data):
for probe_num, probe in enumerate(vcd_probes):
val = part_select(value, widths[probe_num])
writer.change(probe, timestamp, val)
vcd_file.close()