Compare commits
10 Commits
346de9cdd4
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58a759e00c | ||
|
|
ce90d68554 | ||
|
|
dc437c99ca | ||
|
|
cc34f33d92 | ||
|
|
7ce84f5637 | ||
|
|
84695d44b4 | ||
|
|
da27f38f0f | ||
|
|
646440493f | ||
|
|
78205b90f2 | ||
|
|
1e8986f8a7 |
2
examples/GW1NSR-4C/.gitignore
vendored
Normal file
2
examples/GW1NSR-4C/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
OUT
|
||||
BUILD
|
||||
8
examples/GW1NSR-4C/CON/io.cst
Normal file
8
examples/GW1NSR-4C/CON/io.cst
Normal file
@@ -0,0 +1,8 @@
|
||||
IO_LOC "led_o" 10;
|
||||
IO_PORT "led_o" PULL_MODE=NONE DRIVE=8;
|
||||
|
||||
IO_LOC "reset_n_i" 15;
|
||||
IO_PORT "reset_n_i" PULL_MODE=UP;
|
||||
|
||||
IO_LOC "clk_i" 45;
|
||||
IO_PORT "clk_i" PULL_MODE=UP;
|
||||
1
examples/GW1NSR-4C/CON/io.sdc
Normal file
1
examples/GW1NSR-4C/CON/io.sdc
Normal file
@@ -0,0 +1 @@
|
||||
create_clock -name CLK_IN -period 37.037 -waveform {0 18.52} [get_ports {clk_i}]
|
||||
23
examples/GW1NSR-4C/RTL/toplevel.v
Normal file
23
examples/GW1NSR-4C/RTL/toplevel.v
Normal file
@@ -0,0 +1,23 @@
|
||||
module led_blink
|
||||
(
|
||||
input clk_i,
|
||||
input reset_n_i,
|
||||
output led_o
|
||||
);
|
||||
|
||||
reg [23:0] counter;
|
||||
reg polarity;
|
||||
|
||||
always@(posedge clk_i) begin
|
||||
if (!reset_n_i)
|
||||
counter <= 24'h00000;
|
||||
else
|
||||
counter <= counter + 1'b1;
|
||||
|
||||
if (counter == 24'hFFFFF)
|
||||
polarity <= ~polarity;
|
||||
end
|
||||
|
||||
assign led_o = polarity;
|
||||
|
||||
endmodule
|
||||
28
examples/GW1NSR-4C/project.cfg
Normal file
28
examples/GW1NSR-4C/project.cfg
Normal file
@@ -0,0 +1,28 @@
|
||||
[project]
|
||||
name = gowin_project
|
||||
version = 0.1
|
||||
out_dir = OUT
|
||||
build_dir = BUILD
|
||||
|
||||
[server]
|
||||
hostname = localhost
|
||||
port = 2020
|
||||
privkey = /home/joppe/.ssh/id_rsa
|
||||
pubkey = /home/joppe/.ssh/id_rsa.pub
|
||||
|
||||
# ######################################
|
||||
# Basic synthesis
|
||||
[target.synth]
|
||||
toolchain = gowin
|
||||
|
||||
# Toolchain settings
|
||||
family = GW1NSR-4C
|
||||
device = GW1NSR-LV4CQN48PC6/I5
|
||||
toplevel = led_blink
|
||||
|
||||
# Fileset
|
||||
# files_vhdl =
|
||||
files_verilog = RTL/toplevel.v
|
||||
files_con = CON/io.cst
|
||||
CON/io.sdc
|
||||
# ######################################
|
||||
@@ -40,7 +40,7 @@ int start_cosim(char * descr){
|
||||
|
||||
void end_cosim(){
|
||||
close(fd);
|
||||
fclose(log);
|
||||
// fclose(log);
|
||||
}
|
||||
|
||||
int wait_cosim(uint32_t * retaddr, uint32_t * time){
|
||||
|
||||
@@ -18,7 +18,7 @@ def print_help():
|
||||
log(" -h Show this help message")
|
||||
log(" -c <file> Configuration file, defaults to project.cfg")
|
||||
|
||||
if __name__=="__main__":
|
||||
def main():
|
||||
# Parse arguments
|
||||
i = 1
|
||||
nextarg = None
|
||||
@@ -73,13 +73,22 @@ if __name__=="__main__":
|
||||
exit(1)
|
||||
|
||||
try:
|
||||
exec(f"from remotesyn.toolchains.{toolchain} import do")
|
||||
print(f'Importing toolchain {toolchain}')
|
||||
namespace = {}
|
||||
exec(f"from remotesyn.toolchains.{toolchain} import do", globals(), namespace)
|
||||
do_func = namespace.get('do')
|
||||
if do_func is None:
|
||||
raise ImportError("Failed to import 'do'")
|
||||
except ImportError:
|
||||
log(f"ERROR: Unknown toolchain '{toolchain}'")
|
||||
exit(1)
|
||||
|
||||
ret = do(config, target, log, subprocesses)
|
||||
ret = do_func(config, target, log, subprocesses)
|
||||
|
||||
if ret!=0:
|
||||
log("ERROR: toolchain returned with", ret)
|
||||
exit(ret)
|
||||
|
||||
|
||||
if __name__=="__main__":
|
||||
main()
|
||||
@@ -69,9 +69,10 @@ def recv_dir(channel, dr):
|
||||
print("<<<", dr)
|
||||
cmd(b'ls'+sstr(dr), channel)
|
||||
while True:
|
||||
status = channel.recv(2)
|
||||
if status != b'\x00\x00':
|
||||
status = channel.recv(1)
|
||||
if status != b'\x00':
|
||||
break
|
||||
status += channel.recv(1)
|
||||
if status!=b'OK':
|
||||
msg = channel.recv(1024)
|
||||
print("Error:", bytes.decode(msg, 'ascii'))
|
||||
@@ -95,7 +96,7 @@ def print_help():
|
||||
print(" -h Show this help message")
|
||||
print(" -c <file> Configuration file, defaults to project.cfg")
|
||||
|
||||
if __name__=="__main__":
|
||||
def main():
|
||||
# Parse arguments
|
||||
i = 1
|
||||
nextarg = None
|
||||
@@ -170,7 +171,7 @@ if __name__=="__main__":
|
||||
# Send config
|
||||
cmd(b'cf' + sstr(json.dumps({s:dict(config.items(s)) for s in config.sections()})), channel)
|
||||
|
||||
print("Target", target)
|
||||
print("LOCAL: Target", target)
|
||||
|
||||
toolchain = config.get(f'target.{target}', 'toolchain', fallback='NONE')
|
||||
if toolchain=='NONE':
|
||||
@@ -190,7 +191,11 @@ if __name__=="__main__":
|
||||
send_file(channel, f)
|
||||
|
||||
cmd(b'do'+sstr(target), channel)
|
||||
status = channel.recv(2)
|
||||
while True:
|
||||
status = channel.recv(1)
|
||||
if status!='b\x00':
|
||||
break
|
||||
status += channel.recv(1)
|
||||
end = -1
|
||||
while end<0:
|
||||
data = channel.recv(8)
|
||||
@@ -200,7 +205,7 @@ if __name__=="__main__":
|
||||
print(str(data, 'utf-8'), end='', flush=True)
|
||||
sys.stdout.flush()
|
||||
|
||||
ret = 0
|
||||
ret = int.from_bytes(channel.recv(4), 'big')
|
||||
|
||||
# Receive output dir
|
||||
recv_dir(channel, config.get('project', 'out_dir', fallback='out'))
|
||||
@@ -216,3 +221,7 @@ if __name__=="__main__":
|
||||
for p in subprocesses:
|
||||
p.kill()
|
||||
exit(0)
|
||||
|
||||
|
||||
if __name__=="__main__":
|
||||
main()
|
||||
@@ -15,6 +15,7 @@ import threading
|
||||
import socket
|
||||
import shutil
|
||||
import fcntl
|
||||
import traceback
|
||||
|
||||
# List of running threads
|
||||
threads = []
|
||||
@@ -209,6 +210,7 @@ class SSHServer(paramiko.ServerInterface):
|
||||
global running
|
||||
if running:
|
||||
print("ERROR: Unknown error:", e)
|
||||
traceback.print_exception(type(e), e, e.__traceback__)
|
||||
return False
|
||||
|
||||
class Connection(threading.Thread):
|
||||
@@ -257,7 +259,9 @@ def print_help():
|
||||
print("Options:")
|
||||
print(" -h Show this help message")
|
||||
|
||||
if __name__=="__main__":
|
||||
def main():
|
||||
global running
|
||||
|
||||
# Parse arguments
|
||||
i = 1
|
||||
host = ''
|
||||
@@ -308,3 +312,7 @@ if __name__=="__main__":
|
||||
for t in threads:
|
||||
t.join()
|
||||
t.clean()
|
||||
|
||||
|
||||
if __name__=="__main__":
|
||||
main()
|
||||
@@ -11,12 +11,18 @@ import shutil
|
||||
def do(config, target, log, subprocesses, prefix='.'):
|
||||
shutil.rmtree(config.get('project', 'build_dir', fallback='build'), True)
|
||||
|
||||
stopafter = config.get(f'target.{target}', 'stopafter', fallback='')
|
||||
|
||||
if config.get(f'target.{target}', 'ngc_in', fallback=None) is None:
|
||||
# Synthesize if no ngc is already given
|
||||
log("Syntesize:")
|
||||
|
||||
res = xst(config, target, log, subprocesses, prefix)
|
||||
if res != 0:
|
||||
log("ERROR: xst returned with", res)
|
||||
return res
|
||||
if stopafter=='synth':
|
||||
return res
|
||||
|
||||
log("Implement")
|
||||
|
||||
@@ -34,6 +40,8 @@ def do(config, target, log, subprocesses, prefix='.'):
|
||||
if res != 0:
|
||||
log("ERROR: par returned with", res)
|
||||
return res
|
||||
if stopafter=='impl':
|
||||
return res
|
||||
|
||||
log("Generate output files")
|
||||
|
||||
|
||||
83
remotesyn/toolchains/cocotb.py
Normal file
83
remotesyn/toolchains/cocotb.py
Normal file
@@ -0,0 +1,83 @@
|
||||
from distutils.command.build import build
|
||||
import shutil
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
def do(config, target, log, subprocesses, prefix='.'):
|
||||
shutil.rmtree(config.get('project', 'build_dir', fallback='build'), True)
|
||||
|
||||
log("Starting cocotb")
|
||||
|
||||
log(" - parsing options")
|
||||
toplevels = config.get(f'target.{target}', 'toplevels', fallback='').split()
|
||||
simulator = config.get(f'target.{target}', 'simulator', fallback='ghdl')
|
||||
files_vhdl = config.get(f'target.{target}', 'files_vhdl', fallback='').split()
|
||||
files_verilog = config.get(f'target.{target}', 'files_verilog', fallback='').split()
|
||||
files_python = config.get(f'target.{target}', 'files_python', fallback='').split()
|
||||
files_python_other = config.get(f'target.{target}', 'files_python_other', fallback='').split()
|
||||
files_other = config.get(f'target.{target}', 'files_other', fallback='').split()
|
||||
toplevel_langs = config.get(f'target.{target}', 'toplevel_langs', fallback='').split()
|
||||
build_dir = config.get(f'project', 'build_dir', fallback='build')
|
||||
out_dir = config.get(f'project', 'out_dir', fallback='out')
|
||||
|
||||
prefix = f'{os.getcwd()}/{prefix}%%'.replace('/.%%', '').replace('%%', '')
|
||||
build_dir = f'{prefix}/{build_dir}'
|
||||
out_dir = f'{prefix}/{out_dir}/{target}'
|
||||
|
||||
log(" - creating output directories")
|
||||
os.makedirs(build_dir, exist_ok=True)
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
|
||||
log(" - copy needed files")
|
||||
for f in files_python_other:
|
||||
shutil.copy(f"{prefix}/{f}", f"{build_dir}/{os.path.basename(f)}")
|
||||
for f in files_other:
|
||||
d = os.path.dirname(f)
|
||||
os.makedirs(f"{build_dir}/{d}", exist_ok=True)
|
||||
shutil.copy(f"{prefix}/{f}", f"{build_dir}/{f}")
|
||||
|
||||
res = 0
|
||||
|
||||
i = 0
|
||||
for pfile in files_python:
|
||||
|
||||
log(" - copy", pfile)
|
||||
shutil.copy(f"{prefix}/{pfile}", build_dir)
|
||||
|
||||
log(" - writing Makefile for", pfile)
|
||||
with open(f'{build_dir}/Makefile', 'w') as f:
|
||||
f.write(f".SILENT:\nSIM ?= {simulator}\nTOPLEVEL_LANG ?= {toplevel_langs[i]}\nWAVES = 1\n")
|
||||
f.write(f"TOPLEVEL = {toplevels[i]}\nMODULE = {'.'.join(os.path.basename(pfile).split('.')[0:-1])}\n")
|
||||
for vfile in files_vhdl:
|
||||
f.write(f"VHDL_SOURCES += {prefix}/{vfile}\n")
|
||||
for vfile in files_verilog:
|
||||
f.write(f"VERILOG_SOURCES += {prefix}/{vfile}\n")
|
||||
|
||||
if simulator=='ghdl':
|
||||
f.write(f"SIM_ARGS += --vcd={os.path.basename(pfile)}.vcd\n")
|
||||
|
||||
f.write("include $(shell cocotb-config --makefiles)/Makefile.sim\n")
|
||||
|
||||
log(" - start cocotb")
|
||||
p = subprocess.Popen(f"make 2>&1 | tee {os.path.basename(pfile)}.log",
|
||||
shell=True, cwd=build_dir,
|
||||
stdin=subprocess.DEVNULL,
|
||||
# stdout=subprocess.DEVNULL,
|
||||
# stderr=subprocess.DEVNULL
|
||||
)
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(1)
|
||||
res |= p.returncode
|
||||
|
||||
shutil.copy(f"{build_dir}/{os.path.basename(pfile)}.log", out_dir)
|
||||
|
||||
if simulator=='ghdl':
|
||||
shutil.copy(f"{build_dir}/{os.path.basename(pfile)}.vcd", out_dir)
|
||||
elif simulator=='questa':
|
||||
os.system(f'wlf2vcd -o {out_dir}/{os.path.basename(pfile)}.vcd {build_dir}/vsim.wlf')
|
||||
|
||||
i += 1
|
||||
|
||||
return res
|
||||
@@ -6,7 +6,10 @@ import subprocess
|
||||
def execp(cmd, subprocesses, cwd):
|
||||
p = subprocess.Popen(cmd,
|
||||
shell=True, cwd=cwd,
|
||||
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
stdin=subprocess.DEVNULL,
|
||||
#stdout=subprocess.DEVNULL,
|
||||
#stderr=subprocess.DEVNULL
|
||||
)
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(1)
|
||||
@@ -25,6 +28,7 @@ def do(config, target, log, subprocesses, prefix='.'):
|
||||
ghdle_opts = config.get(f'target.{target}', 'ghdle_opts', fallback='')
|
||||
ghdlr_opts = config.get(f'target.{target}', 'ghdlr_opts', fallback='')
|
||||
files_vhdl = config.get(f'target.{target}', 'files_vhdl', fallback='').split()
|
||||
files_other = config.get(f'target.{target}', 'files_other', fallback='').split()
|
||||
build_dir = config.get(f'project', 'build_dir', fallback='build')
|
||||
out_dir = config.get(f'project', 'out_dir', fallback='out')
|
||||
|
||||
@@ -36,6 +40,12 @@ def do(config, target, log, subprocesses, prefix='.'):
|
||||
os.makedirs(build_dir, exist_ok=True)
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
|
||||
log(" - copy needed files")
|
||||
for f in files_other:
|
||||
d = os.path.dirname(f)
|
||||
os.makedirs(f"{build_dir}/{d}", exist_ok=True)
|
||||
shutil.copy(f"{prefix}/{f}", f"{build_dir}/{f}")
|
||||
|
||||
log(" - analyze files")
|
||||
res = 0
|
||||
for f in files_vhdl:
|
||||
@@ -60,7 +70,8 @@ def do(config, target, log, subprocesses, prefix='.'):
|
||||
extra = ''
|
||||
if runtime!='all':
|
||||
extra = f'--stop-time={runtime.replace(" ", "")}'
|
||||
res = execp(f"echo {toplevel} >> r.log && ghdl -r {ghdlr_opts} {extra} {toplevel} --vcd=out.vcd 2>&1 1>> r.log", subprocesses, build_dir)
|
||||
# res = execp(f"echo {toplevel} >> r.log && ghdl -r {ghdlr_opts} {toplevel} {extra} --vcd=out.vcd --wave=out.ghw 2>&1 | tee r.log", subprocesses, build_dir)
|
||||
res = execp(f"echo {toplevel} >> r.log && ./{toplevel} {ghdlr_opts} {extra} --vcd=out.vcd --wave=out.ghw 2>&1 | tee r.log", subprocesses, build_dir)
|
||||
log(" - copy logs")
|
||||
shutil.copy(f'{build_dir}/r.log', f'{out_dir}/r.log')
|
||||
# Ignore simulation errors: vhdl stopping with failure results in returned with 1
|
||||
@@ -70,5 +81,6 @@ def do(config, target, log, subprocesses, prefix='.'):
|
||||
|
||||
log(" - copy output files")
|
||||
shutil.copy(f'{build_dir}/out.vcd', f'{out_dir}/out.vcd')
|
||||
shutil.copy(f'{build_dir}/out.ghw', f'{out_dir}/out.ghw')
|
||||
|
||||
return 0
|
||||
135
remotesyn/toolchains/gowin.py
Normal file
135
remotesyn/toolchains/gowin.py
Normal file
@@ -0,0 +1,135 @@
|
||||
import shutil
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
import html2text
|
||||
|
||||
def do(config, target, log, subprocesses, prefix='.'):
|
||||
shutil.rmtree(config.get('project', 'build_dir', fallback='build'), True)
|
||||
shutil.rmtree(config.get('project', 'out_dir', fallback='out'), True)
|
||||
|
||||
log(" - parsing options")
|
||||
family = config.get(f'target.{target}', 'family', fallback='')
|
||||
device = config.get(f'target.{target}', 'device', fallback='')
|
||||
toplevel = config.get(f'target.{target}', 'toplevel', fallback='toplevel')
|
||||
files_vhdl = config.get(f'target.{target}', 'files_vhdl', fallback='').split()
|
||||
files_verilog = config.get(f'target.{target}', 'files_verilog', fallback='').split()
|
||||
files_con= config.get(f'target.{target}', 'files_con', fallback='').split()
|
||||
build_dir = config.get(f'project', 'build_dir', fallback='build')
|
||||
out_dir = config.get(f'project', 'out_dir', fallback='out')
|
||||
|
||||
prefix = f'{os.getcwd()}/{prefix}'
|
||||
build_dir = f'{prefix}/{build_dir}'
|
||||
out_dir = f'{prefix}/{out_dir}/{target}'
|
||||
|
||||
log(" - creating output directories")
|
||||
os.makedirs(build_dir, exist_ok=True)
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
|
||||
log(" - writing scripts")
|
||||
with open(f'{build_dir}/synth.tcl', 'w') as f:
|
||||
f.write(f'set_device {device} -name {family}\n')
|
||||
|
||||
for s in files_vhdl:
|
||||
if s=='':
|
||||
continue
|
||||
f.write(f'add_file {prefix}/{s}\n')
|
||||
for s in files_verilog:
|
||||
if s=='':
|
||||
continue
|
||||
f.write(f'add_file {prefix}/{s}\n')
|
||||
for s in files_con:
|
||||
if s=='':
|
||||
continue
|
||||
f.write(f'add_file {prefix}/{s}\n')
|
||||
|
||||
f.write('set_option -synthesis_tool gowinsynthesis\n')
|
||||
f.write(f'set_option -output_base_name {toplevel}\n')
|
||||
f.write(f'set_option -top_module {toplevel}\n')
|
||||
f.write('run syn\n')
|
||||
|
||||
with open(f'{build_dir}/pnr.tcl', 'w') as f:
|
||||
f.write(f'set_device {device} -name {family}\n')
|
||||
f.write('set_option -synthesis_tool gowinsynthesis\n')
|
||||
f.write(f'set_option -output_base_name {toplevel}\n')
|
||||
f.write(f'set_option -top_module {toplevel}\n')
|
||||
for s in files_con:
|
||||
if s=='':
|
||||
continue
|
||||
f.write(f'add_file {prefix}/{s}\n')
|
||||
f.write(f'add_file {build_dir}/impl/gwsynthesis/{toplevel}.vg\n')
|
||||
|
||||
f.write('run pnr\n')
|
||||
|
||||
log(' - run syntesis')
|
||||
p = subprocess.Popen(f"gw_sh synth.tcl",
|
||||
shell = True,
|
||||
cwd = build_dir,
|
||||
stdin = subprocess.DEVNULL,
|
||||
# stdout = subprocess.DEVNULL,
|
||||
# stderr = subprocess.DEVNULL,
|
||||
)
|
||||
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(1)
|
||||
res = p.returncode
|
||||
|
||||
shutil.copy(f'{build_dir}/impl/gwsynthesis/{toplevel}.log', f'{out_dir}/synth.log')
|
||||
if res!=0:
|
||||
log("ERROR: synthesis failed with:", res)
|
||||
return res
|
||||
shutil.copy(f'{build_dir}/impl/gwsynthesis/{toplevel}.vg', f'{out_dir}/synth_netlist.vg')
|
||||
with open(f'{build_dir}/impl/gwsynthesis/{toplevel}_syn.rpt.html', 'r') as fin, open(f'{out_dir}/synth_rpt.md', 'w') as fout:
|
||||
text_maker = html2text.HTML2Text()
|
||||
text_maker.bypass_tables = False
|
||||
text_maker.ignore_links = True
|
||||
text_maker.body_width = 500
|
||||
fout.write(text_maker.handle(fin.read()))
|
||||
|
||||
log(' - run PnR')
|
||||
p = subprocess.Popen(f"gw_sh pnr.tcl",
|
||||
shell = True,
|
||||
cwd = build_dir,
|
||||
stdin = subprocess.DEVNULL,
|
||||
# stdout = subprocess.DEVNULL,
|
||||
# stderr = subprocess.DEVNULL,
|
||||
)
|
||||
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(1)
|
||||
res = p.returncode
|
||||
|
||||
shutil.copy(f'{build_dir}/impl/pnr/{toplevel}.log', f'{out_dir}/pnr.log')
|
||||
if res!=0:
|
||||
log("ERROR: pnr failed with:", res)
|
||||
return res
|
||||
shutil.copy(f'{build_dir}/impl/pnr/{toplevel}.fs', f'{out_dir}/{toplevel}.fs')
|
||||
shutil.copy(f'{build_dir}/impl/pnr/{toplevel}.bin', f'{out_dir}/{toplevel}.bin')
|
||||
with open(f'{build_dir}/impl/pnr/{toplevel}.rpt.html', 'r') as fin, open(f'{out_dir}/rpt.md', 'w') as fout:
|
||||
text_maker = html2text.HTML2Text()
|
||||
text_maker.bypass_tables = False
|
||||
text_maker.ignore_links = True
|
||||
text_maker.body_width = 500
|
||||
fout.write(text_maker.handle(fin.read()))
|
||||
with open(f'{build_dir}/impl/pnr/{toplevel}.power.html', 'r') as fin, open(f'{out_dir}/power.md', 'w') as fout:
|
||||
text_maker = html2text.HTML2Text()
|
||||
text_maker.bypass_tables = False
|
||||
text_maker.ignore_links = True
|
||||
text_maker.body_width = 500
|
||||
fout.write(text_maker.handle(fin.read()))
|
||||
with open(f'{build_dir}/impl/pnr/{toplevel}.pin.html', 'r') as fin, open(f'{out_dir}/pin.md', 'w') as fout:
|
||||
text_maker = html2text.HTML2Text()
|
||||
text_maker.bypass_tables = False
|
||||
text_maker.ignore_links = True
|
||||
text_maker.body_width = 500
|
||||
fout.write(text_maker.handle(fin.read()))
|
||||
with open(f'{build_dir}/impl/pnr/{toplevel}_tr_content.html', 'r') as fin, open(f'{out_dir}/timing.md', 'w') as fout:
|
||||
text_maker = html2text.HTML2Text()
|
||||
text_maker.bypass_tables = False
|
||||
text_maker.ignore_links = True
|
||||
text_maker.body_width = 500
|
||||
fout.write(text_maker.handle(fin.read()))
|
||||
|
||||
return res
|
||||
@@ -10,12 +10,13 @@ def do(config, target, log, subprocesses, prefix='.'):
|
||||
|
||||
log(" - parsing options")
|
||||
toplevel = config.get(f'target.{target}', 'toplevel', fallback='toplevel')
|
||||
vcdlevels = config.get(f'target.{target}', 'vcdlevels', fallback='1')
|
||||
vcdlevels = config.get(f'target.{target}', 'vcdlevels', fallback='10')
|
||||
runtime = config.get(f'target.{target}', 'runtime', fallback='100 ns')
|
||||
fuse_opts = config.get(f'target.{target}', 'fuse_opts', fallback='')
|
||||
isim_opts = config.get(f'target.{target}', 'isim_opts', fallback='')
|
||||
files_vhdl = config.get(f'target.{target}', 'files_vhdl', fallback='').split()
|
||||
files_verilog = config.get(f'target.{target}', 'files_verilog', fallback='').split()
|
||||
files_other = config.get(f'target.{target}', 'files_other', fallback='').split()
|
||||
build_dir = config.get(f'project', 'build_dir', fallback='build')
|
||||
out_dir = config.get(f'project', 'out_dir', fallback='out')
|
||||
|
||||
@@ -30,6 +31,12 @@ def do(config, target, log, subprocesses, prefix='.'):
|
||||
os.makedirs(build_dir, exist_ok=True)
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
|
||||
log(" - copy needed files")
|
||||
for f in files_other:
|
||||
d = os.path.dirname(f)
|
||||
os.makedirs(f"{build_dir}/{d}", exist_ok=True)
|
||||
shutil.copy(f"{prefix}/{f}", f"{build_dir}/{f}")
|
||||
|
||||
log(" - writing project file")
|
||||
with open(f'{build_dir}/sim.prj', 'w') as f:
|
||||
for s in files_vhdl:
|
||||
@@ -51,7 +58,7 @@ def do(config, target, log, subprocesses, prefix='.'):
|
||||
res = p.returncode
|
||||
|
||||
log(" - copy logs")
|
||||
shutil.copy(f'{build_dir}/ffuse.log', f'{out_dir}/fuse.log')
|
||||
shutil.copy(f'{build_dir}/fuse.log', f'{out_dir}/fuse.log')
|
||||
|
||||
if res!=0:
|
||||
log("ERROR: fuse returned with:", res)
|
||||
@@ -61,15 +68,18 @@ def do(config, target, log, subprocesses, prefix='.'):
|
||||
with open(f'{build_dir}/sim.tcl', 'w') as f:
|
||||
f.write("onerror {resume}\n")
|
||||
f.write("vcd dumpfile sim.vcd\n")
|
||||
f.write(f"vcd dumpvars -m {toplevel} -l {vcdlevels}\n")
|
||||
f.write(f"vcd dumpvars -m {toplevel.split()[0]} -l {vcdlevels}\n")
|
||||
f.write("vcd dumpon\n")
|
||||
f.write(f"run {runtime}\n")
|
||||
f.write("vcd dumpflush\nquit\n")
|
||||
|
||||
log(" - run sim")
|
||||
p = subprocess.Popen(f"./sim {isim_opts} -tclbatch sim.tcl > sim.log",
|
||||
p = subprocess.Popen(f"./sim {isim_opts} -tclbatch sim.tcl | tee sim.log",
|
||||
shell=True, cwd=build_dir,
|
||||
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
stdin=subprocess.DEVNULL,
|
||||
# stdout=subprocess.DEVNULL,
|
||||
# stderr=subprocess.DEVNULL
|
||||
)
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(1)
|
||||
|
||||
122
remotesyn/toolchains/iverilog.py
Normal file
122
remotesyn/toolchains/iverilog.py
Normal file
@@ -0,0 +1,122 @@
|
||||
# iverilog.py
|
||||
import shutil
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
def _execp(cmd, subprocesses, cwd):
|
||||
p = subprocess.Popen(
|
||||
cmd,
|
||||
shell=True,
|
||||
cwd=cwd,
|
||||
stdin=subprocess.DEVNULL,
|
||||
# stdout/stderr visible so tee can capture; keep quiet if you prefer:
|
||||
# stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
|
||||
)
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(0.2)
|
||||
return p.returncode
|
||||
|
||||
def do(config, target, log, subprocesses, prefix='.'):
|
||||
# fresh build dir
|
||||
shutil.rmtree(config.get('project', 'build_dir', fallback='build'), True)
|
||||
|
||||
log("Starting simulation (iverilog)")
|
||||
|
||||
# --- parse options (keep names consistent with your other toolchains) ---
|
||||
toplevel = config.get(f'target.{target}', 'toplevel', fallback='toplevel')
|
||||
ivl_opts = config.get(f'target.{target}', 'ivl_opts', fallback='')
|
||||
vvp_opts = config.get(f'target.{target}', 'vvp_opts', fallback='')
|
||||
runtime = config.get(f'target.{target}', 'runtime', fallback='') # optional; TB can honor +stop_time
|
||||
files_verilog = config.get(f'target.{target}', 'files_verilog', fallback='').split()
|
||||
files_sysverilog= config.get(f'target.{target}', 'files_sysverilog', fallback='').split()
|
||||
files_vhdl = config.get(f'target.{target}', 'files_vhdl', fallback='').split()
|
||||
files_other = config.get(f'target.{target}', 'files_other', fallback='').split()
|
||||
build_dir = config.get('project', 'build_dir', fallback='build')
|
||||
out_dir_root = config.get('project', 'out_dir', fallback='out')
|
||||
|
||||
# normalize paths
|
||||
prefix = f'{os.getcwd()}/{prefix}'
|
||||
build_dir= f'{prefix}/{build_dir}'
|
||||
out_dir = f'{prefix}/{out_dir_root}/{target}'
|
||||
|
||||
# minor sanitization
|
||||
ivl_opts = ivl_opts.replace('\n', ' ')
|
||||
vvp_opts = vvp_opts.replace('\n', ' ')
|
||||
|
||||
# --- create dirs ---
|
||||
log(" - creating output directories")
|
||||
os.makedirs(build_dir, exist_ok=True)
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
|
||||
# --- copy extra needed files into build dir (keeping tree) ---
|
||||
if files_other:
|
||||
log(" - copy needed files")
|
||||
for f in files_other:
|
||||
if not f: continue
|
||||
d = os.path.dirname(f)
|
||||
if d:
|
||||
os.makedirs(f"{build_dir}/{d}", exist_ok=True)
|
||||
shutil.copy(f"{prefix}/{f}", f"{build_dir}/{f}")
|
||||
|
||||
# --- guard: VHDL not supported by Icarus ---
|
||||
if any(s for s in files_vhdl if s.strip()):
|
||||
log("WARNING: VHDL files listed but iverilog does not support VHDL — ignoring them")
|
||||
|
||||
# --- build source list (order as provided) ---
|
||||
sources = []
|
||||
for s in files_verilog:
|
||||
if s: sources.append(f'"{prefix}/{s}"')
|
||||
for s in files_sysverilog:
|
||||
if s: sources.append(f'"{prefix}/{s}"')
|
||||
|
||||
if not sources:
|
||||
log("ERROR: no Verilog/SystemVerilog sources provided")
|
||||
return 1
|
||||
|
||||
# --- decide standard (enable SV if any sysverilog files or if user asked) ---
|
||||
needs_sv = len([1 for _ in files_sysverilog if _]) > 0
|
||||
std_flag = "-g2012" if needs_sv and "-g" not in ivl_opts and "-g2012" not in ivl_opts else ""
|
||||
|
||||
# --- compile ---
|
||||
log(" - compile (iverilog)")
|
||||
# -s <top> sets the toplevel; produce sim.vvp; tee compile log
|
||||
# You can add include dirs/defines via ivl_opts (e.g., -Iinc -DNAME=VALUE)
|
||||
cmd_compile = f'iverilog -o sim.vvp -s {toplevel} {std_flag} {ivl_opts} ' + " ".join(sources) + ' 2>&1 | tee comp.log'
|
||||
res = _execp(cmd_compile, subprocesses, build_dir)
|
||||
|
||||
# logs
|
||||
shutil.copy(f'{build_dir}/comp.log', f'{out_dir}/compile.log')
|
||||
if res != 0:
|
||||
log("ERROR: iverilog returned with", res)
|
||||
return res
|
||||
|
||||
# --- simulate ---
|
||||
log(" - simulate (vvp)")
|
||||
# If your TB supports +stop_time=<time>, we pass it from 'runtime' (e.g., "1000us" -> +stop_time=1000us)
|
||||
plusargs = []
|
||||
if runtime and runtime.strip().lower() != 'all':
|
||||
rt = runtime.replace(" ", "")
|
||||
plusargs.append(f'+stop_time={rt}') # your TB can $value$plusargs("stop_time=%s", str)
|
||||
|
||||
cmd_run = f'vvp {vvp_opts} sim.vvp ' + " ".join(plusargs) + ' 2>&1 | tee sim.log'
|
||||
res = _execp(cmd_run, subprocesses, build_dir)
|
||||
|
||||
# copy sim log
|
||||
shutil.copy(f'{build_dir}/sim.log', f'{out_dir}/simulate.log')
|
||||
|
||||
# --- copy outputs if present ---
|
||||
# Expect the TB to do $dumpfile("out.vcd"); $dumpvars; (or use your own filename)
|
||||
vcd_candidates = ["out.vcd", f"{toplevel}.vcd", "sim.vcd"]
|
||||
copied = False
|
||||
for vcd in vcd_candidates:
|
||||
src = f'{build_dir}/{vcd}'
|
||||
if os.path.exists(src):
|
||||
shutil.copy(src, f'{out_dir}/out.vcd')
|
||||
copied = True
|
||||
break
|
||||
if not copied:
|
||||
log("NOTE: no VCD found (ensure your TB calls $dumpfile(\"out.vcd\") and $dumpvars)")
|
||||
|
||||
return res
|
||||
@@ -29,7 +29,10 @@ def do(config, target, log, subprocesses, prefix='.'):
|
||||
log(" - run make")
|
||||
p = subprocess.Popen(f"BUILDROOT={prefix}/{buildroot} make 2>make.log",
|
||||
shell=True, cwd=build_dir,
|
||||
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
stdin=subprocess.DEVNULL,
|
||||
# stdout=subprocess.DEVNULL,
|
||||
# stderr=subprocess.DEVNULL
|
||||
)
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(1)
|
||||
|
||||
@@ -12,6 +12,9 @@ def do(config, target, log, subprocesses, prefix='.'):
|
||||
log(" - parsing options")
|
||||
toplevel = config.get(f'target.{target}', 'toplevel', fallback='toplevel')
|
||||
runtime = config.get(f'target.{target}', 'runtime', fallback='100 ns')
|
||||
vsim_opts = config.get(f'target.{target}', 'vsim_opts', fallback='')
|
||||
vcom_opts = config.get(f'target.{target}', 'vcom_opts', fallback='')
|
||||
vlog_opts = config.get(f'target.{target}', 'vlog_opts', fallback='')
|
||||
files_vhdl = config.get(f'target.{target}', 'files_vhdl', fallback='').split()
|
||||
files_verilog = config.get(f'target.{target}', 'files_verilog', fallback='').split()
|
||||
files_sysverilog = config.get(f'target.{target}', 'files_sysverilog', fallback='').split()
|
||||
@@ -28,31 +31,44 @@ def do(config, target, log, subprocesses, prefix='.'):
|
||||
os.makedirs(build_dir, exist_ok=True)
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
|
||||
log(" - copy needed files")
|
||||
for f in files_other:
|
||||
d = os.path.dirname(f)
|
||||
os.makedirs(f"{build_dir}/{d}", exist_ok=True)
|
||||
shutil.copy(f"{prefix}/{f}", f"{build_dir}/{f}")
|
||||
|
||||
files_c_wp = {f'{prefix}/{f}' for f in files_c}
|
||||
|
||||
log(" - writing compile file")
|
||||
with open(f'{build_dir}/do.sh', 'w') as f:
|
||||
f.write(f'vlib work\nvmap work work\n')
|
||||
for s in files_vhdl:
|
||||
f.write(f"vcom {prefix}/{s}\n")
|
||||
for s in files_verilog:
|
||||
f.write(f"vlog {prefix}/{s}\n")
|
||||
f.write(f"vlog {vlog_opts} {prefix}/{s}\n")
|
||||
for s in files_vhdl:
|
||||
f.write(f"vcom {vcom_opts} {prefix}/{s}\n")
|
||||
for s in files_sysverilog:
|
||||
f.write(f"vlog -sv {prefix}/{s}\n")
|
||||
f.write(f"vlog -sv {vlog_opts} {prefix}/{s}\n")
|
||||
f.write(f"gcc -g -fPIC -shared -Bsymbolic -o import.so {' '.join(files_c_wp)}\n")
|
||||
extra = ''
|
||||
extra = vsim_opts
|
||||
if len(files_c_wp)>0:
|
||||
extra = ' -sv_lib import'
|
||||
f.write(f"vsim -c -do do.do {extra} {toplevel}")
|
||||
f.write(f"vsim -c -do do.do {extra} -vcd=+multid+vhvar -vcddump=out.vcd {toplevel}")
|
||||
|
||||
log(" - writing do file")
|
||||
rtime = "-all"
|
||||
if runtime != "all":
|
||||
rtime = runtime
|
||||
with open(f'{build_dir}/do.do', 'w') as f:
|
||||
f.write("vcd file out.vcd\n vcd add *\nrun -all\nquit\n");
|
||||
# f.write(f"vcd file out.vcd\n vcd add -r -in -out -inout -internal -ports *\nrun {rtime}\nquit\n");
|
||||
f.write(f"\nrun {rtime}\nquit\n");
|
||||
|
||||
log(" - run vsim")
|
||||
p = subprocess.Popen(f"bash ./do.sh 2>&1 | tee do.log",
|
||||
shell=True, cwd=build_dir,
|
||||
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
stdin=subprocess.DEVNULL,
|
||||
#stdout=subprocess.DEVNULL,
|
||||
#stderr=subprocess.DEVNULL
|
||||
)
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(1)
|
||||
|
||||
@@ -6,7 +6,9 @@ import subprocess
|
||||
def execp(cmd, subprocesses, cwd):
|
||||
p = subprocess.Popen(cmd,
|
||||
shell=True, cwd=cwd,
|
||||
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
stdin=subprocess.DEVNULL,
|
||||
# stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(1)
|
||||
@@ -55,7 +57,10 @@ def do(config, target, log, subprocesses, prefix='.'):
|
||||
for d in os.listdir(f'{build_dir}'):
|
||||
if os.path.isdir(f'{build_dir}/{d}') and d.startswith(oname):
|
||||
shutil.copy(f'{build_dir}/{d}/logfile.txt', f'{out_dir}/{d}.log')
|
||||
try:
|
||||
shutil.copytree(f'{build_dir}/{d}/engine_0', f'{out_dir}/{d}', dirs_exist_ok=True)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
if res!=0:
|
||||
log(" - [-]")
|
||||
|
||||
@@ -20,7 +20,10 @@ def bitgen(config, target, log, subprocesses, prefix='.') -> int:
|
||||
log(" - run bitgen")
|
||||
p = subprocess.Popen(f"bitgen -intstyle xflow {bitgen_opts} -g Binary:Yes -w {out_dir}/{target}.ncd {target}.bit {out_dir}/{target}.pcf 2> bitgen.log",
|
||||
shell=True, cwd=build_dir,
|
||||
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
stdin=subprocess.DEVNULL,
|
||||
# stdout=subprocess.DEVNULL,
|
||||
# stderr=subprocess.DEVNULL
|
||||
)
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(1)
|
||||
|
||||
@@ -10,7 +10,7 @@ def coregen(config, target, log, subprocesses, prefix='.') -> int:
|
||||
package = config.get(f'target.{target}', 'package', fallback='')
|
||||
speedgrade = config.get(f'target.{target}', 'speedgrade', fallback='')
|
||||
coregen_opts = config.get(f'target.{target}', 'coregen_opts', fallback='')
|
||||
files_xco = config.get(f'target.{target}', 'files_xco', fallback='').split()
|
||||
files_def = config.get(f'target.{target}', 'files_xco', fallback='').split()
|
||||
build_dir = config.get(f'project', 'build_dir', fallback='build')
|
||||
out_dir = config.get(f'project', 'out_dir', fallback='out')
|
||||
|
||||
@@ -24,7 +24,7 @@ def coregen(config, target, log, subprocesses, prefix='.') -> int:
|
||||
|
||||
res = 0
|
||||
|
||||
for fxco in files_xco:
|
||||
for fxco in files_def:
|
||||
cname = fxco.split('/')[-1].split('.')[0]
|
||||
|
||||
log(" - Generating", cname, "...")
|
||||
@@ -40,6 +40,7 @@ def coregen(config, target, log, subprocesses, prefix='.') -> int:
|
||||
f.write(f'SET flowvendor = Other\n')
|
||||
f.write(f'SET verilogsim = true\n')
|
||||
f.write(f'SET vhdlsim = true\n')
|
||||
f.write(f'SET implementationfiletype = ngc\n')
|
||||
|
||||
log(" - run coregen")
|
||||
p = subprocess.Popen(f"coregen {coregen_opts} -p coregen_{cname}.cgp -b {prefix}/{fxco}",
|
||||
@@ -55,9 +56,26 @@ def coregen(config, target, log, subprocesses, prefix='.') -> int:
|
||||
|
||||
if res==0:
|
||||
log(" - copy output files")
|
||||
try:
|
||||
shutil.copy(f'{build_dir}/{cname}.vhd', f'{out_dir}/{cname}.vhd')
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
try:
|
||||
shutil.copy(f'{build_dir}/{cname}.v', f'{out_dir}/{cname}.v')
|
||||
# shutil.copy(f'{build_dir}/{cname}.ngc', f'{out_dir}/{cname}.ngc')
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
try:
|
||||
shutil.copy(f'{build_dir}/{cname}.ngc', f'{out_dir}/{cname}.ngc')
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
try:
|
||||
shutil.copy(f'{build_dir}/{cname}.xco', f'{out_dir}/{cname}.xco')
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
try:
|
||||
shutil.copy(f'{build_dir}/{cname}.ucf', f'{out_dir}/{cname}.ucf')
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
else:
|
||||
return res
|
||||
|
||||
|
||||
@@ -24,7 +24,10 @@ def map(config, target, log, subprocesses, prefix='.') -> int:
|
||||
log(" - run map")
|
||||
p = subprocess.Popen(f"map -intstyle xflow -p {devstring} -detail {map_opts} -ol high -xe n -w {out_dir}/{target}.ngd -o impl.map.ncd impl.pcf",
|
||||
shell=True, cwd=build_dir,
|
||||
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
stdin=subprocess.DEVNULL,
|
||||
# stdout=subprocess.DEVNULL,
|
||||
# stderr=subprocess.DEVNULL
|
||||
)
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(1)
|
||||
|
||||
@@ -22,10 +22,23 @@ def ngdbuild(config, target, log, subprocesses, prefix='.') -> int:
|
||||
os.makedirs(build_dir, exist_ok=True)
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
|
||||
if config.get(f'target.{target}', 'ngc_in', fallback=None) is None:
|
||||
ngcfile = f'{out_dir}/{target}.ngc'
|
||||
else:
|
||||
log(" - Synthesized design already given, start from there")
|
||||
ngcfile = config.get(f'target.{target}', 'ngc_in', fallback='')
|
||||
d = os.path.dirname(ngcfile)
|
||||
if d:
|
||||
os.makedirs(f"{build_dir}/{d}", exist_ok=True)
|
||||
shutil.copy(ngcfile, f'{build_dir}/{ngcfile}')
|
||||
|
||||
log(" - run ngdbuild")
|
||||
p = subprocess.Popen(f"ngdbuild -intstyle xflow -p {devstring} -uc {prefix}/{files_con[0]} {ngdbuild_opts} {out_dir}/{target}.ngc impl.ngd",
|
||||
p = subprocess.Popen(f"ngdbuild -intstyle xflow -p {devstring} -uc {prefix}/{files_con[0]} {ngdbuild_opts} {ngcfile} impl.ngd",
|
||||
shell=True, cwd=build_dir,
|
||||
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
stdin=subprocess.DEVNULL,
|
||||
# stdout=subprocess.DEVNULL,
|
||||
# stderr=subprocess.DEVNULL
|
||||
)
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(1)
|
||||
|
||||
@@ -28,5 +28,6 @@ def trce(config, target, log, subprocesses, prefix='.') -> int:
|
||||
|
||||
log(" - copy logs")
|
||||
shutil.copy(f'{build_dir}/{target}.twr', f'{out_dir}/timing.log')
|
||||
shutil.copy(f'{build_dir}/{target}.twx', f'{out_dir}/timing.twx')
|
||||
|
||||
return res
|
||||
@@ -10,8 +10,11 @@ def xst(config, target, log, subprocesses, prefix='.') -> int:
|
||||
speedgrade = config.get(f'target.{target}', 'speedgrade', fallback='')
|
||||
toplevel = config.get(f'target.{target}', 'toplevel', fallback='toplevel')
|
||||
xst_opts = config.get(f'target.{target}', 'xst_opts', fallback='')
|
||||
netgensynth_opts = config.get(f'target.{target}', 'netgensynth_opts', fallback='-ofmt verilog')
|
||||
netgensynth_type = config.get(f'target.{target}', 'netgensynth_type', fallback='-sim')
|
||||
files_vhdl = config.get(f'target.{target}', 'files_vhdl', fallback='').split()
|
||||
files_verilog = config.get(f'target.{target}', 'files_verilog', fallback='').split()
|
||||
files_other = config.get(f'target.{target}', 'files_other', fallback='').split()
|
||||
build_dir = config.get(f'project', 'build_dir', fallback='build')
|
||||
out_dir = config.get(f'project', 'out_dir', fallback='out')
|
||||
|
||||
@@ -34,27 +37,64 @@ def xst(config, target, log, subprocesses, prefix='.') -> int:
|
||||
if s=='':
|
||||
continue
|
||||
f.write(f"verilog work {prefix}/{s}\n")
|
||||
for f in files_other:
|
||||
if not f: continue
|
||||
d = os.path.dirname(f)
|
||||
if d:
|
||||
os.makedirs(f"{build_dir}/{d}", exist_ok=True)
|
||||
shutil.copy(f"{prefix}/{f}", f"{build_dir}/{f}")
|
||||
|
||||
log(" - writing project generation file")
|
||||
with open(f'{build_dir}/prj.scr', 'w') as f:
|
||||
f.write(f'run\n-ifn syn.prj\n-ofn syn.ngc\n-ifmt mixed\n')
|
||||
f.write(f'-top {toplevel}\n')
|
||||
f.write(f'-p {devstring}\n-glob_opt max_delay -opt_mode speed')
|
||||
f.write(f'-p {devstring}\n-glob_opt max_delay -opt_mode speed\n')
|
||||
f.write(xst_opts)
|
||||
f.write(f'\n-read_cores YES')
|
||||
|
||||
log(" - run xst")
|
||||
p = subprocess.Popen(f"xst -intstyle xflow {xst_opts} -ifn prj.scr",
|
||||
p = subprocess.Popen(f"xst -intstyle xflow -ifn prj.scr",
|
||||
shell=True, cwd=build_dir,
|
||||
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
stdin=subprocess.DEVNULL,
|
||||
# stdout=subprocess.DEVNULL,
|
||||
# stderr=subprocess.DEVNULL
|
||||
)
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(1)
|
||||
res = p.returncode
|
||||
|
||||
if res==0:
|
||||
log(" - copy output files")
|
||||
shutil.copy(f'{build_dir}/syn.ngc', f'{out_dir}/{target}.ngc')
|
||||
|
||||
log(" - run netgen")
|
||||
extra = ""
|
||||
if netgensynth_type=="-sim" and not netgensynth_opts.__contains__("-ofmt vhdl"):
|
||||
extra = "-insert_glbl true -ism"
|
||||
p = subprocess.Popen(f"netgen -intstyle xflow {netgensynth_type} -w {extra} {netgensynth_opts} {out_dir}/{target}.ngc 2>&1 >> prj.srp",
|
||||
shell=True, cwd=build_dir,
|
||||
stdin=subprocess.DEVNULL,
|
||||
# stdout=subprocess.DEVNULL,
|
||||
# stderr=subprocess.DEVNULL
|
||||
)
|
||||
subprocesses.append(p)
|
||||
while p.poll() is None:
|
||||
time.sleep(1)
|
||||
res |= p.returncode
|
||||
|
||||
log(" - copy logs")
|
||||
shutil.copy(f'{build_dir}/prj.srp', f'{out_dir}/xst.log')
|
||||
|
||||
if res==0:
|
||||
log(" - copy output files")
|
||||
shutil.copy(f'{build_dir}/syn.ngc', f'{out_dir}/{target}.ngc')
|
||||
try:
|
||||
shutil.copy(f'{build_dir}/{target}.v', f'{out_dir}/{target}-synth.v')
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
try:
|
||||
shutil.copy(f'{build_dir}/{target}.vhd', f'{out_dir}/{target}-synth.vhd')
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
return res
|
||||
10
setup.py
10
setup.py
@@ -20,6 +20,12 @@ setup(
|
||||
],
|
||||
packages=['remotesyn'],
|
||||
licence='BSD Licence',
|
||||
install_requires=['paramiko'],
|
||||
scripts=['scripts/rbuild', 'scripts/rmbuild', 'scripts/rmserver']
|
||||
install_requires=['paramiko', 'html2text'],
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'rmserver = remotesyn.rmserver:main',
|
||||
'rmbuild = remotesyn.rmbuild:main',
|
||||
'rbuild = remotesyn.rbuild:main'
|
||||
],
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user