Added base GOWIN eda script
This commit is contained in:
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
|
||||
# ######################################
|
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
|
Reference in New Issue
Block a user