diff --git a/build.py b/build.py deleted file mode 100644 index 5463561..0000000 --- a/build.py +++ /dev/null @@ -1,5 +0,0 @@ -import os - -os.system('echo "#!/usr/bin/python3" > manta') -os.system("cat manta.py >> manta") -os.system("chmod +x manta") diff --git a/examples/counter/lab-bc.py b/examples/counter/lab-bc.py index 63458a7..d651852 100644 --- a/examples/counter/lab-bc.py +++ b/examples/counter/lab-bc.py @@ -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 diff --git a/gen_ila.py b/gen_ila.py deleted file mode 100644 index 33e60c1..0000000 --- a/gen_ila.py +++ /dev/null @@ -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) \ No newline at end of file diff --git a/manta.py b/manta.py index 9dcb8f9..78d3371 100644 --- a/manta.py +++ b/manta.py @@ -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) diff --git a/run_ila.py b/run_ila.py deleted file mode 100644 index e342e93..0000000 --- a/run_ila.py +++ /dev/null @@ -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() \ No newline at end of file