New project structure

Rewrite of all functions

Signed-off-by: Jojojoppe <joppe@blondel.nl>
This commit is contained in:
2022-09-03 21:52:29 +02:00
parent cbcea361bb
commit 162aaf47a0
31 changed files with 209 additions and 2111 deletions

5
.gitignore vendored
View File

@ -1,2 +1,3 @@
*__pycache__
*egg-info
OUT
BUILD
*__pycache__

21
LICENCE
View File

@ -1,21 +0,0 @@
Copyright (c) 2022, Joppe Blondel
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,30 +0,0 @@
# Remotesyn
```
$> remotesyn -h
Unified FPGA synthesizer frontend
(c) Joppe Blondel - 2022
Usage: /home/joppe/.local/bin/remotesyn [ OPTIONS ] action [ target ] ...
where OPTIONS := { -h | -l | -s host:port privkey pubkey authorized | -c config | -b build_dir }
action := { ip | syn | impl | bit | all | floorplan | sim | init }
Options:
-h Show this help message
-l Local build
-s <s-info> Start server with server information s-info. host:port is the address to bind
to, privkey and pubkey are the ssh keys of the server and authorized is the
authorized_keys file for the SSH server
-c <file> Configuration file, defaults to project.cfg
-b <dir> Build directory, defaults to .build
Actions:
ip <target> Generate IP files from vendor provided libraries
syn <target> Synthesize design for target
impl <target> Route and place design for target
bit <target> Generate output files and run analysis for target
all <target> Generate IP, synthesize, route and place design for target
floorplan <target> Run floorplan editor, currently only for local execution
sim <simtarget> Run simulation target
init Initialize project
```

View File

@ -1,7 +1,6 @@
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
entity toplevel is
port (
ACLK : in std_logic;
@ -9,13 +8,10 @@ entity toplevel is
SW : in std_logic_vector(3 downto 0)
);
end toplevel;
architecture structural of toplevel is
signal ARESETN : std_logic;
begin
ARESETN <= SW(3);
process(ACLK, ARESETN)
begin
if ARESETN='0' then
@ -24,5 +20,4 @@ begin
LED <= SW & SW;
end if;
end process;
end architecture;

View File

@ -1,2 +0,0 @@
OUT
.build

View File

@ -1,41 +0,0 @@
NET "ACLK" LOC = P126;
NET "ACLK" TNM_NET = "SYS_CLK_PIN";
TIMESPEC TS_SYS_CLK_PIN = PERIOD "SYS_CLK_PIN" 10 ns HIGH 50 %;
NET "LED[0]" LOC = P119;
NET "LED[0]" IOSTANDARD = LVCMOS33;
NET "LED[0]" DRIVE = 8;
NET "LED[1]" LOC = P118;
NET "LED[1]" IOSTANDARD = LVCMOS33;
NET "LED[1]" DRIVE = 8;
NET "LED[2]" LOC = P117;
NET "LED[2]" IOSTANDARD = LVCMOS33;
NET "LED[2]" DRIVE = 8;
NET "LED[3]" LOC = P116;
NET "LED[3]" IOSTANDARD = LVCMOS33;
NET "LED[3]" DRIVE = 8;
NET "LED[4]" LOC = P115;
NET "LED[4]" IOSTANDARD = LVCMOS33;
NET "LED[4]" DRIVE = 8;
NET "LED[5]" LOC = P114;
NET "LED[5]" IOSTANDARD = LVCMOS33;
NET "LED[5]" DRIVE = 8;
NET "LED[6]" LOC = P112;
NET "LED[6]" IOSTANDARD = LVCMOS33;
NET "LED[6]" DRIVE = 8;
NET "LED[7]" LOC = P111;
NET "LED[7]" IOSTANDARD = LVCMOS33;
NET "LED[7]" DRIVE = 8;
NET "SW[0]" LOC = P124;
NET "SW[0]" IOSTANDARD = LVCMOS33;
NET "SW[0]" PULLUP;
NET "SW[1]" LOC = P123;
NET "SW[1]" IOSTANDARD = LVCMOS33;
NET "SW[1]" PULLUP;
NET "SW[2]" LOC = P121;
NET "SW[2]" IOSTANDARD = LVCMOS33;
NET "SW[2]" PULLUP;
NET "SW[3]" LOC = P120;
NET "SW[3]" IOSTANDARD = LVCMOS33;
NET "SW[3]" PULLUP;

View File

@ -1,6 +0,0 @@
# Spartan 6 example
Create IP files: `remotesyn -l ip total`<br>
Run full toolchain: `remotesyn -l all total`<br>
Run simulation: `remotesyn -l sim presim_total`<br>
Run post-simulation (after synthesis and implementation): `remotesyn -l sim postsim_total`<br>

View File

@ -1,49 +0,0 @@
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
entity tb_toplevel is
end entity;
architecture behavioural of tb_toplevel is
-- COMPONENTS
-- ----------
component toplevel is
port (
ACLK : in std_logic;
LED : out std_logic_vector(7 downto 0);
SW : in std_logic_vector(3 downto 0)
);
end component;
-- SIGNALS
-- -------
signal ACLK : std_logic := '0';
signal LED : std_logic_vector(7 downto 0) := "00000000";
signal SW : std_logic_vector(3 downto 0) := "0111";
begin
c_toplevel : component toplevel port map(
ACLK, LED, SW
);
ACLK <= not ACLK after 10 ns;
SW(3) <= '1' after 150 ns;
process
begin
wait until SW(3)='1';
SW(2 downto 0) <= "101";
wait for 75 ns;
SW(2 downto 0) <= "010";
wait for 19 ns;
SW(2 downto 0) <= "111";
wait for 100 ns;
report "END OF SIMULATION" severity failure;
end process;
end architecture;

View File

@ -1,78 +0,0 @@
# PROJECT SETTINGS
# ----------------
[server]
hostname = localhost
port = 8080
privkey = keys/id_rsa
pubkey = keys/id_rsa.pub
[project]
# Toolchain selection. choose between [ISE, VIVADO]
toolchain = ISE
out_dir = OUT
[target]
family = spartan6
device = xc6slx9
package = tqg144
speedgrade = -2
# HARDWARE TARGETS
# ----------------
[total]
src_vhdl = RTL/toplevel.vhd
src_verilog =
src_sysverilog =
src_constraints = CON/toplevel.ucf
src_ip = blk_mem
toplevel = toplevel
extra_options = xst -glob_opt max_delay -opt_mode speed
netgen -ism
map -ol high -xe n
par -ol high -xe n
trce -v 3 -s 2 -n 3 -fastpaths
# Currently supported for ISE
# - xst -> settings added to the xst command
# - netgen -> settings added to the netgen command
# - ngd -> settings added to the ngd command
# - map -> settigs added to the map command
# - par -> settings added to the par command
# - bitgen -> settings added to the bitgen command
# - trce -> settings added to the trce command
# SIMULATION TARGETS
# ------------------
[presim_total]
simtype = presim
src_vhdl = RTL/toplevel.vhd
SIM/tb_toplevel.vhd
src_verilog =
src_sysverilog =
toplevel = tb_toplevel
runtime = all
levels = 10
[postsim_total]
simtype = postsim
src_vhdl = SIM/tb_toplevel.vhd
src_verilog = OUT/total/total.map.v
src_sysverilog =
src_ip =
src_sdf = OUT/total/total.map.sdf
toplevel = tb_toplevel
runtime = all
# Delay type: [min typ max]
delay = max
sdfroot = /tb_toplevel/c_toplevel
levels = 10
# IP BLOCKS
# ---------
[ip_blk_mem]
ip_blk_mem = xilinx.com:ip:blk_mem_gen:7.3
component_name = blk_mem
interface_type = Native
port_a_clock = 100
read_width_a = 32
write_width_a = 32
write_depth_a = 256

View File

@ -1,2 +0,0 @@
OUT
.build

View File

@ -1,4 +0,0 @@
set_property IOSTANDARD LVCMOS33 [get_ports {LED[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {LED[0]}]
set_property PACKAGE_PIN W13 [get_ports {LED[0]}]
set_property PACKAGE_PIN W14 [get_ports {LED[1]}]

View File

@ -1,6 +0,0 @@
# ZYNQ 7000 example
Create IP files: `remotesyn -l ip total`<br>
Run full toolchain: `remotesyn -l all total`<br>
Run simulation (first one should create IP files for the sim targets): `remotesyn -l sim presim_total`<br>
Run post-simulation (after synthesis and implementation): `remotesyn -l sim postsim_total`<br>

View File

@ -1,39 +0,0 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity heartbeat is
generic (
Fin : integer := 100000000;
Fout : integer := 8
);
port (
ACLK : in std_logic;
ARESETN : in std_logic;
LED : out std_logic_vector(1 downto 0)
);
end entity;
architecture structural of heartbeat is
signal iLED : std_logic_vector(1 downto 0);
begin
LED <= iLED;
process (ACLK, ARESETN)
variable cnt : integer range 0 to Fin/(2 * Fout) - 1 := 0;
begin
if ARESETN = '0' then
cnt := 0;
iLED <= "01";
elsif rising_edge(ACLK) then
if (cnt = Fin/(2 * Fout) - 1) then
cnt := 0;
iLED <= not iLED;
else
cnt := cnt + 1;
end if;
end if;
end process;
end architecture;

View File

@ -1,161 +0,0 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity toplevel is
port (
-- DDR
DDR_Addr : inout std_logic_vector(14 downto 0);
DDR_BankAddr : inout std_logic_vector(2 downto 0);
DDR_CAS_n : inout std_logic;
DDR_Clk_n : inout std_logic;
DDR_Clk : inout std_logic;
DDR_CKE : inout std_logic;
DDR_CS_n : inout std_logic;
DDR_DM : inout std_logic_vector(3 downto 0);
DDR_DQ : inout std_logic_vector(31 downto 0);
DDR_DQS_n : inout std_logic_vector(3 downto 0);
DDR_DQS_p : inout std_logic_vector(3 downto 0);
DDR_ODT : inout std_logic;
DDR_RAS_n : inout std_logic;
DDR_DSTRB : inout std_logic;
DDR_WEB : inout std_logic;
DDR_VRN : inout std_logic;
DDR_VRP : inout std_logic;
-- FIXED IO
MIO : inout std_logic_vector(53 downto 0);
ps_clk : inout std_logic;
ps_porb : inout std_logic;
ps_srstb : inout std_logic;
-- OWN DEFINED
LED : out std_logic_vector(1 downto 0)
);
end entity;
architecture structural of toplevel is
-- ----------
-- COMPONENTS
-- ----------
component zynq_ps
port (
FCLK_CLK0 : out std_logic;
FCLK_RESET0_N : out std_logic;
MIO : inout std_logic_vector(53 downto 0);
DDR_CAS_n : inout std_logic;
DDR_CKE : inout std_logic;
DDR_Clk_n : inout std_logic;
DDR_Clk : inout std_logic;
DDR_CS_n : inout std_logic;
DDR_DRSTB : inout std_logic;
DDR_ODT : inout std_logic;
DDR_RAS_n : inout std_logic;
DDR_WEB : inout std_logic;
DDR_BankAddr : inout std_logic_vector(2 downto 0);
DDR_Addr : inout std_logic_vector(14 downto 0);
DDR_VRN : inout std_logic;
DDR_VRP : inout std_logic;
DDR_DM : inout std_logic_vector(3 downto 0);
DDR_DQ : inout std_logic_vector(31 downto 0);
DDR_DQS_n : inout std_logic_vector(3 downto 0);
DDR_DQS : inout std_logic_vector(3 downto 0);
PS_SRSTB : inout std_logic;
PS_CLK : inout std_logic;
PS_PORB : inout std_logic
);
end component;
component rst_gen
port (
slowest_sync_clk : in std_logic;
ext_reset_in : in std_logic;
aux_reset_in : in std_logic;
mb_debug_sys_rst : in std_logic;
dcm_locked : in std_logic;
mb_reset : out std_logic;
bus_struct_reset : out std_logic_vector(0 downto 0);
peripheral_reset : out std_logic_vector(0 downto 0);
interconnect_aresetn : out std_logic_vector(0 downto 0);
peripheral_aresetn : out std_logic_vector(0 downto 0)
);
end component;
component heartbeat is
generic (
Fin : integer := 100000000;
Fout : integer := 8
);
port (
ACLK : in std_logic;
ARESETN : in std_logic;
LED : out std_logic_vector(1 downto 0)
);
end component;
-- -------
-- SIGNALS
-- -------
signal FCLK_CLK0 : std_logic;
signal FCLK_RESET0_N : std_logic;
signal ARESETN : std_logic_vector(0 downto 0);
begin
heartbeat_i : component heartbeat generic map(
100000000,
10
) port map(
ACLK => FCLK_CLK0,
ARESETN => ARESETN(0),
LED => LED
);
zynq_ps_i : component zynq_ps port map(
-- MIO
MIO => MIO,
-- CLOCKS
FCLK_CLK0 => FCLK_CLK0,
FCLK_RESET0_N => FCLK_RESET0_N,
-- DDR
DDR_CAS_n => DDR_CAS_n,
DDR_CKE => DDR_CKE,
DDR_Clk_n => DDR_Clk_n,
DDR_Clk => DDR_Clk,
DDR_CS_n => DDR_CS_n,
DDR_DRSTB => DDR_DSTRB,
DDR_ODT => DDR_ODT,
DDR_RAS_n => DDR_RAS_n,
DDR_WEB => DDR_WEB,
DDR_BankAddr => DDR_BankAddr,
DDR_Addr => DDR_Addr,
DDR_VRN => DDR_VRN,
DDR_VRP => DDR_VRP,
DDR_DM => DDR_DM,
DDR_DQ => DDR_DQ,
DDR_DQS_n => DDR_DQS_n,
DDR_DQS => DDR_DQS_p,
-- PS FIXED IO
PS_SRSTB => PS_SRSTB,
PS_CLK => PS_CLK,
PS_PORB => PS_PORB
);
rst_gen_i : rst_gen port map(
slowest_sync_clk => FCLK_CLK0,
ext_reset_in => FCLK_RESET0_N,
aux_reset_in => '1',
mb_debug_sys_rst => '0',
dcm_locked => '1',
--mb_reset => mb_reset,
--bus_struct_reset => bus_struct_reset,
--peripheral_reset => peripheral_reset,
--interconnect_aresetn => interconnect_aresetn,
peripheral_aresetn => ARESETN
);
end architecture;

View File

@ -1,36 +0,0 @@
`timescale 1ns / 1ps
module tb_top ();
reg ACLK ;
reg ARESETN;
initial begin
ACLK = 1'b0;
end
always #5 ACLK = !ACLK;
initial begin
ARESETN = 1'b0;
tb_top.ps.inst.fpga_soft_reset(32'h1);
repeat(20)@(posedge ACLK);
ARESETN = 1'b1;
tb_top.ps.inst.fpga_soft_reset(32'h0);
repeat(5)@(posedge ACLK);
repeat(100)@(posedge ACLK);
// Write some data
//tb_top.ps.inst.write_data(32'h40000000, 4, 32'hdeadbeef, resp);
//tb_top.ps.inst.write_data(32'h40000004, 16, 128'habcdef0185274123deadbeef95123578, resp);
$display("End of simulation");
$stop;
end
zynq_ps ps (
.PS_CLK (ACLK ),
.PS_SRSTB (ARESETN ),
.PS_PORB (ARESETN )
);
endmodule

View File

@ -1,85 +0,0 @@
# PROJECT SETTINGS
# ----------------
[server]
hostname = localhost
port = 8080
privkey = keys/id_rsa
pubkey = keys/id_rsa.pub
[project]
# Toolchain selection. choose between [ISE, VIVADO]
toolchain = VIVADO
out_dir = OUT
[target]
family = zynq
device = xc7z010
package = clg400
speedgrade = -2
# HARDWARE TARGETS
# ----------------
[total]
src_vhdl = RTL/heartbeat.vhd
RTL/toplevel.vhd
src_verilog =
src_sysverilog =
src_constraints = CON/iopins.xdc
src_ip = zynq_ps rst_gen
toplevel = toplevel
extra_options = syn -flatten_hierarchy none -keep_equivalent_registers
netlist_top toplevel
# Currently supported for VIVADO
# - syn -> settings added to the synth_design command
# - netlist_top -> module used as toplevel for netlist/SDF generation
# defaults to the toplevel setting
# SIMULATION TARGETS
# ------------------
[presim_total]
simtype = presim
src_vhdl = RTL/heartbeat.vhd
RTL/toplevel.vhd
src_verilog =
src_sysverilog = SIM/tb_top.sv
src_ip = zynq_ps rst_gen
src_c =
toplevel = tb_top
runtime = all
[postsim_total]
simtype = postsim
src_vhdl =
src_verilog = OUT/total/impl_netlist.v
src_sysverilog = SIM/tb_top.sv
src_ip =
src_c =
src_sdf = OUT/total/impl_netlist.sdf
toplevel = tb_top
runtime = all
# Delay type: [min typ max]
delay = max
sdfroot = duv
# IP BLOCKS
# ---------
[ip_zynq_ps]
ip_zynq_ps = ip:xilinx.com:processing_system7
PCW_UIPARAM_DDR_BUS_WIDTH = 16 Bit
PCW_UIPARAM_DDR_PARTNO = MT41K256M16 RE-125
PCW_UART1_PERIPHERAL_ENABLE = 1
PCW_UART1_UART1_IO = MIO 44 .. 45
PCW_FPGA0_PERIPHERAL_FREQMHZ = 100
PCW_USE_S_AXI_GP0 = 0
PCW_USE_S_AXI_GP1 = 0
PCW_USE_M_AXI_GP0 = 0
PCW_USE_M_AXI_GP1 = 0
PCW_USE_S_AXI_HP0 = 0
PCW_USE_S_AXI_HP1 = 0
PCW_USE_S_AXI_HP2 = 0
PCW_USE_S_AXI_HP3 = 0
[ip_rst_gen]
ip_rst_gen = ip:xilinx.com:proc_sys_reset
C_EXT_RESET_HIGH = 0
C_AUX_RESET_HIGH = 0

19
project.cfg Normal file
View File

@ -0,0 +1,19 @@
[project]
name = testproject
version = 0.1
out_dir = OUT
build_dir = BUILD
[target:default]
family = spartan6
device = xc6slx9
package = tqg144
speedgrade = -2
toolchain = ISE
[sources:default]
target = default
toplevel = toplevel
src_vhdl = RTL/toplevel.vhd
src_verilog =
src_sysverilog =

42
rbuild.py Executable file
View File

@ -0,0 +1,42 @@
#!/usr/bin/env python
import remotesyn
import remotesyn.ISE as ISE
import configparser
import signal
import time
threads = []
def sighandler(sig, frame):
print("\nCRTL-C: stopping threads")
for t in threads:
t.stop();
exit(0);
if __name__=="__main__":
signal.signal(signal.SIGINT, sighandler)
config = configparser.ConfigParser()
config.read("project.cfg")
# Test local build
copy = remotesyn.copy_local(config)
synth = ISE.synth(config, copy, 'default')
threads.append(synth)
needed_files = synth.needed_files()
print(needed_files)
synth.start()
looping = True
while looping:
time.sleep(1)
looping = False
for t in threads:
if t.running:
looping = True

View File

@ -1,34 +0,0 @@
import threading
import time
import base64
class Heartbeat(threading.Thread):
def __init__(self, channel):
threading.Thread.__init__(self)
self.channel = channel
self.running = True
self.printing = False
def stop(self):
self.running = False
def run(self):
while self.running:
if self.printing:
print('.', end='', flush=True)
self.channel.exec_command(base64.encodebytes(b'hb'))
time.sleep(2)
class HeartbeatChecker(threading.Thread):
def __init__(self, server):
threading.Thread.__init__(self)
self.server = server
self.running = True
self.hb = True
def stop(self):
self.running = False
def run(self):
while self.running:
if not self.hb:
self.server.active = False
self.server.event.set()
self.hb = False
time.sleep(5)

View File

@ -0,0 +1 @@
from .synth import synth

14
remotesyn/ISE/runner.py Normal file
View File

@ -0,0 +1,14 @@
import threading
import shutil
import os
import time
import subprocess
def runner(threads, process, name):
print(f" - executing {name}: ", end='', flush=True)
p = subprocess.Popen(process, shell=True, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
threads.append(p)
while p.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
res = p.returncode

107
remotesyn/ISE/synth.py Normal file
View File

@ -0,0 +1,107 @@
import threading
import shutil
import os
import time
import subprocess
import signal
import random
from .runner import runner
class synth(threading.Thread):
def __init__(self, config, copy, target):
threading.Thread.__init__(self)
self.config = config
self.copy = copy
self.target = target
self.threads = []
self.running = True
self.name = config.get('project', 'name', fallback=f'{random.random():.4f}')
self.version = config.get('project', 'version', fallback=f'{random.random():.4f}')
self.builddir = f"{config.get('project', 'build_dir', fallback='.build')}/synth_{target}_{self.name}_{self.version}"
self.outdir = config.get('project', 'out_dir', fallback='out')
# Returns the list of needed files to execute operation. Caller need
# to check for existance of the files and if in remote execution these
# files must be synched
def needed_files(self):
if not self.config.has_section(f'sources:{self.target}'):
print("ERROR: config file has no sources section for target")
return None
needed_files = []
for s in self.config.get(f'sources:{self.target}', 'src_vhdl', fallback="").split():
needed_files.append(s)
for s in self.config.get(f'sources:{self.target}', 'src_verilog', fallback="").split():
needed_files.append(s)
for s in self.config.get(f'sources:{self.target}', 'src_sysverilog', fallback="").split():
needed_files.append(s)
return needed_files
def stop(self):
print("Stopping synth...")
for t in self.threads:
print(" <> kill", t)
t.send_signal(signal.SIGINT)
ti = 0
while t.poll() is None:
time.sleep(1)
ti += 1
if ti>2:
print(" <> force kill", t)
t.send_signal(signal.SIGKILL)
self.running = False
def run(self):
print("Synthesize:")
if not self.config.has_section(f'sources:{self.target}'):
print("ERROR: config file has no sources section for target")
self.running = False
return None
devtarget = f'target:{self.config.get(f"sources:{self.target}", "target", fallback="")}'
if not self.config.has_section(devtarget):
print("ERROR: config file has no section for device target")
self.running = False
return None
device = f"{self.config.get(devtarget, 'device', fallback='')}{self.config.get(devtarget, 'speedgrade', fallback='')}-{self.config.get(devtarget, 'package', fallback='')}"
os.makedirs(self.builddir, exist_ok=True)
curdir = os.getcwd()
os.chdir(self.builddir)
try:
print(" - writing project file")
with open('syn.prj', 'w') as f:
for s in self.config.get(f'sources:{self.target}', 'src_vhdl', fallback="").split():
f.write(f"vhdl work {curdir}/{s}\n")
for s in self.config.get(f'sources:{self.target}', 'src_verilog', fallback="").split():
f.write(f"verilog work {curdir}/{s}\n")
for s in self.config.get(f'sources:{self.target}', 'src_sysverilog', fallback="").split():
f.write(f"verilog work {curdir}/{s}\n")
print(" - writing project generation file")
with open('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 {self.config.get(f"sources:{self.target}", "toplevel", fallback="toplevel")}\n')
f.write(f'-p {device}\n-glob_opt max_delay -opt_mode speed')
runner(self.threads, "xst -intstyle xflow -ifn prj.scr", "xst")
if not self.running:
os.chdir(curdir)
return
print('DONE')
print(" - copy output files")
os.makedirs(f'{curdir}/{self.outdir}/{self.target}', exist_ok=True)
self.copy.copy_to_dir('syn.ngc', f'{curdir}/{self.outdir}/{self.target}/synth.ngc')
self.copy.copy_to_dir('prj.srp', f'{curdir}/{self.outdir}/{self.target}/synth.log')
except Exception as e:
print(e)
finally:
os.chdir(curdir)
self.running = False

View File

@ -1,200 +1 @@
from .exec_ISE import exec_ISE
from .exec_VIVADO import exec_VIVADO
from .exec_REMOTE import exec_REMOTE
from .Heartbeat import Heartbeat, HeartbeatChecker
import sys
import os
import shutil
import subprocess
import paramiko
import socket
import threading
import struct
import base64
class Executer(threading.Thread):
def __init__(self, args, channel, identifier):
threading.Thread.__init__(self)
self.args = args
self.channel = channel
self.identifier = identifier
self.pid = None
def run(self):
self.pid = subprocess.Popen(f"../{sys.argv[0]} -l -c project.cfg {self.args}", shell=True, cwd=f'{self.identifier}', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
res = self.pid.wait()
self.pid = None
self.channel.sendall(struct.pack('>I', res))
class FileTransferSF(threading.Thread):
def __init__(self, channel, fname, identifier, fsize):
threading.Thread.__init__(self)
self.channel = channel
self.fname = fname
self.identifier = identifier
self.fsize = fsize
def run(self):
with open(f"{self.identifier}/{self.fname}", 'wb') as f:
fsize = self.fsize
while fsize>0:
fdata = self.channel.recv(1024)
f.write(fdata)
fsize -= 1024
class FileTransferRF(threading.Thread):
def __init__(self, channel, fname, identifier):
threading.Thread.__init__(self)
self.channel = channel
self.fname = fname
self.identifier = identifier
def run(self):
with open(f"{self.identifier}/{self.fname}", 'rb') as f:
stat = os.fstat(f.fileno())
print(' -> fsize', stat.st_size)
fsize = struct.pack('>q', stat.st_size)
i = stat.st_size
self.channel.sendall(b'OK'+fsize)
while i>0:
fdata = f.read(1024)
self.channel.sendall(fdata)
i -= 1024
class Server(paramiko.ServerInterface):
def __init__(self, authorized):
self.event = threading.Event()
self.authorized = authorized
self.active = True
self.hbchecker = HeartbeatChecker(self)
self.hbchecker.start()
self.processes = []
def stopall(self):
print("Stop all running processes")
for p in self.processes:
if p.pid is not None:
p.pid.terminate()
def check_channel_request(self, kind, chanid):
if kind == 'session':
return paramiko.OPEN_SUCCEEDED
def check_auth_publickey(self, username, key):
keyascii = key.get_base64()
for auth in self.authorized:
authascii = auth.split(' ')[1]
if authascii==keyascii:
return paramiko.AUTH_SUCCESSFUL
return paramiko.AUTH_FAILED
def get_allowed_auths(self, username):
return 'publickey'
def rstr(self, b):
l = struct.unpack('>I', b[:4])[0]
return (bytes.decode(b[4:4+l], 'utf-8'), b[4+l:])
def sstr(self, s):
return struct.pack('>I', len(s)) + s.encode('utf-8')
def check_channel_exec_request(self, channel, command):
# self.event.set()
command = base64.decodebytes(command)
cmd = command[:2]
data = command[2:]
if cmd==b'id':
identifier = struct.unpack('>q', data[:8])[0]
self.identifier = str(identifier)
print('>', identifier)
# Create directory
if os.path.exists(str(identifier)):
shutil.rmtree(str(identifier))
os.mkdir(str(identifier))
elif cmd==b'ex':
print('<', self.identifier)
#shutil.rmtree(str(self.identifier))
self.active = False
self.hbchecker.stop()
self.event.set()
elif cmd==b'hb':
self.hbchecker.hb = True
# List files
elif cmd==b'ls':
dr, data = self.rstr(data)
print('ls', dr)
if not os.path.exists(f"{self.identifier}/{dr}"):
channel.sendall(b'ERFile not found')
es = []
for f in os.listdir(f'{self.identifier}/{dr}'):
if os.path.isfile(f'{self.identifier}/{dr}/{f}'):
df = 'f'
else:
df = 'd'
es.append(f'{df}{f}')
channel.sendall(b'OK' + self.sstr('\n'.join(es)))
# Send file
elif cmd==b'sf':
fname, data = self.rstr(data)
fsize = struct.unpack('>q', data)[0]
print('>>', fname, fsize)
os.makedirs(os.path.dirname(f"{self.identifier}/{fname}"), exist_ok=True)
channel.sendall(b'OK\n')
FileTransferSF(channel, fname, self.identifier, fsize).start()
# Receive file
elif cmd==b'rf':
fname, data = self.rstr(data)
print('<<', fname)
if not os.path.exists(f"{self.identifier}/{fname}"):
channel.sendall(b'ERFile not found')
else:
FileTransferRF(channel, fname, self.identifier).start()
# Execute synth
elif cmd==b'do':
args, data = self.rstr(data)
print('[]', args)
executer = Executer(args, channel, self.identifier)
executer.start()
self.processes.append(executer)
return True
class Connection(threading.Thread):
def __init__(self, client, addr, host_key, authorized):
threading.Thread.__init__(self)
self.client = client
self.addr = addr
self.host_key = host_key
self.running = True
self.authorized = authorized
print(f"Connection from {addr}")
def stop(self):
self.running = False
self.server.event.set()
def run(self):
self.running = True
t = paramiko.Transport(self.client)
t.set_gss_host(socket.getfqdn(""))
t.load_server_moduli()
t.add_server_key(self.host_key)
server = Server(self.authorized)
t.start_server(server=server)
self.server = server
# Wait for the event
while server.active:
server.event.wait(10)
server.stopall()
shutil.rmtree(server.identifier)
t.close()
print('connection closed')
from .copy import copy_local, copy_remote

22
remotesyn/copy.py Normal file
View File

@ -0,0 +1,22 @@
import shutil
class copy_local:
def __init__(self, config):
self.config = config
def copy_from_dir(self, src, dst):
pass
# Nothing to do here since we are working in local build
def copy_to_dir(self, src, dst):
shutil.copy(src, dst)
class copy_remote:
def __init__(self, config):
self.config = config
def copy_from_dir(self, src, dst):
print("ERROR: Not yet implemented")
def copy_to_dir(self, src, dst):
print("ERROR: Not yet implemented")

View File

@ -1,349 +0,0 @@
import os
import shutil
import subprocess
import time
class exec_ISE:
def __init__(self, config, builddir):
self.config = config
self.builddir = builddir
self.create_builddir()
def create_outdir(self, target):
self.outdir = self.config.get('project', 'out_dir', fallback='OUT')
if not os.path.exists(self.outdir):
os.mkdir(self.outdir)
if not os.path.exists(f'{self.outdir}/{target}'):
os.mkdir(f'{self.outdir}/{target}')
def create_builddir(self):
if not os.path.exists(self.builddir):
os.mkdir(self.builddir)
def enter_builddir(self):
self.curdir = os.getcwd()
os.chdir(self.builddir)
def leave_builddir(self):
os.chdir(self.curdir)
def do_ip_gen(self, target):
# get used IP's for target
ips = self.config.get(target, 'src_ip', fallback='').split()
self.create_outdir(target)
print("+ Generate IPs")
for i, ip in enumerate(ips):
# Create cgp file
with open(f'{self.builddir}/coregen_{i}.cgp', 'w') as f:
f.write(f'SET busformat = BusFormatAngleBracketNotRipped\n')
f.write(f'SET designentry = VHDL\n')
f.write(f'SET device = {self.config.get("target", "device")}\n')
f.write(f'SET devicefamily = {self.config.get("target", "family")}\n')
f.write(f'SET package = {self.config.get("target", "package")}\n')
f.write(f'SET speedgrade = {self.config.get("target", "speedgrade")}\n')
f.write(f'SET flowvendor = Other\n')
f.write(f'SET verilogsim = true\n')
f.write(f'SET vhdlsim = true\n')
# crete xco file
with open(f'{self.builddir}/coregen_{i}.xco', 'w') as f:
ipsec = 'ip_%s'%ip
f.write(f'SELECT {ip} {self.config.get(ipsec, ipsec)}\n')
for s in self.config[ipsec]:
if s==ipsec:
continue
f.write(f'CSET {s}={self.config.get(ipsec, s)}\n')
f.write('GENERATE')
# Clear log
if os.path.exists(f'{self.builddir}/coregen.log'):
os.remove(f'{self.builddir}/coregen.log')
# Run coregen
pid = subprocess.Popen(f'coregen -p coregen_{i}.cgp -b coregen_{i}.xco', shell=True, cwd=self.builddir, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
res = pid.returncode
print('')
if not os.path.exists(f'{self.outdir}/{target}/{ip}'):
os.mkdir(f'{self.outdir}/{target}/{ip}')
# Copy files to output directory if succeeded
if res == 0:
shutil.copyfile(f'{self.builddir}/{ip}.vhd', f'{self.outdir}/{target}/{ip}/{ip}.vhd')
shutil.copyfile(f'{self.builddir}/{ip}.v', f'{self.outdir}/{target}/{ip}/{ip}.v')
shutil.copyfile(f'{self.builddir}/{ip}.ngc', f'{self.outdir}/{target}/{ip}/{ip}.ngc')
# Copy log
shutil.copyfile(f'{self.builddir}/coregen.log', f'{self.outdir}/{target}/{ip}/{ip}.log')
if res!=0:
exit(res)
def do_synthesize(self, target):
self.create_outdir(target)
self.enter_builddir()
print('+ Synthesize')
extra_opts = self.config.get(target, 'extra_options').split('\n')
opts = {}
for o in extra_opts:
tp = o.split()[0]
op = ' '.join(o.split()[1:])
opts[tp] = op
if 'xst' not in opts:
opts['xst'] = ''
if 'netgen' not in opts:
opts['netgen'] = ''
with open('syn.prj', 'w') as f:
src = self.config.get(target, 'src_vhdl', fallback='').split()
for s in src:
f.write(f'vhdl work "{self.curdir}/{s}"\n')
src = self.config.get(target, 'src_verilog', fallback='').split()
for s in src:
f.write(f'verilog work "{self.curdir}/{s}"\n')
src = self.config.get(target, 'src_sysverilog', fallback='').split()
for s in src:
f.write(f'verilog work "{self.curdir}/{s}"\n')
src = self.config.get(target, 'src_ip', fallback='').split()
for s in src:
f.write(f'vhdl work "{self.curdir}/{self.outdir}/{target}/{s}/{s}.vhd"\n')
with open('prj.scr', 'w') as f:
f.write('run\n-ifn syn.prj\n-ofn syn.ngc\n-ifmt mixed\n')
f.write(f"-top {self.config.get(target, 'toplevel', fallback='_top_')}\n")
f.write(f"-p {self.config.get('target', 'device', fallback='_d_')}")
f.write(self.config.get('target', 'speedgrade', fallback='_s_'))
f.write(f"-{self.config.get('target', 'package', fallback='_p_')}")
f.write(f"\n{opts['xst']}\n")
pid = subprocess.Popen(f'xst -intstyle xflow -ifn prj.scr', shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
res = pid.returncode
print('')
if res!=0:
self.leave_builddir()
exit(res)
success = True
pid = subprocess.Popen(f"netgen -intstyle xflow -sim -ofmt verilog -w -insert_glbl true {opts['netgen']} syn.ngc", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
res = pid.returncode
print('')
if res!=0:
success = False
exit(res)
self.leave_builddir()
if success:
if not os.path.exists(f'{self.outdir}/{target}'):
os.mkdir(f'{self.outdir}/{target}')
# Copy files to output directory if succeeded
shutil.copyfile(f'{self.builddir}/syn.ngc', f'{self.outdir}/{target}/{target}.ngc')
shutil.copyfile(f'{self.builddir}/syn.v', f'{self.outdir}/{target}/{target}.v')
shutil.copyfile(f'{self.builddir}/prj.srp', f'{self.outdir}/{target}/syn.log')
def do_implement(self, target):
self.create_outdir(target)
self.enter_builddir()
print('+ Implement')
extra_opts = self.config.get(target, 'extra_options').split('\n')
opts = {}
for o in extra_opts:
tp = o.split()[0]
op = ' '.join(o.split()[1:])
opts[tp] = op
if 'ngd' not in opts:
opts['ngd'] = ''
if 'map' not in opts:
opts['map'] = ''
if 'par' not in opts:
opts['par'] = ''
part = f"{self.config.get('target', 'device', fallback='_d_')}{self.config.get('target', 'speedgrade', fallback='_s_')}-{self.config.get('target', 'package', fallback='_p_')}"
cons = self.config.get(target, 'src_constraints', fallback='__con__')
pid = subprocess.Popen(f"ngdbuild -intstyle xflow -p {part} -uc {self.curdir}/{cons} {opts['ngd']} {self.curdir}/{self.outdir}/{target}/{target}.ngc impl.ngd", shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
res = pid.returncode
print('')
shutil.copyfile(f'impl.bld', f'{self.curdir}/{self.outdir}/{target}/impl-ngd.log')
if res!=0:
self.leave_builddir()
exit(res)
pid = subprocess.Popen(f"map -intstyle xflow -detail -p {part} {opts['map']} -w impl.ngd -o impl.map.ncd impl.pcf", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
res = pid.returncode
print('')
shutil.copyfile(f'impl.map.mrp', f'{self.curdir}/{self.outdir}/{target}/impl-map.log')
if res!=0:
self.leave_builddir()
exit(res)
pid = subprocess.Popen(f"par -intstyle xflow {opts['par']} -w impl.map.ncd impl.pcf | tee impl.par.log", shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
res = pid.returncode
print('')
shutil.copyfile(f'impl.par.log', f'{self.curdir}/{self.outdir}/{target}/impl-par.log')
if res!=0:
self.leave_builddir()
exit(res)
pid = subprocess.Popen(f"netgen -intstyle xflow -sim -ofmt verilog -w -insert_glbl true -sdf_anno true {opts['netgen']} impl.map.ncd", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
res = pid.returncode
print('')
if res!=0:
self.leave_builddir()
exit(res)
self.leave_builddir()
shutil.copyfile(f'{self.builddir}/impl.map.v', f'{self.outdir}/{target}/{target}.map.v')
shutil.copyfile(f'{self.builddir}/impl.map.sdf', f'{self.outdir}/{target}/{target}.map.sdf')
shutil.copyfile(f'{self.builddir}/impl.pcf.ncd', f'{self.outdir}/{target}/{target}.ncd')
shutil.copyfile(f'{self.builddir}/impl.pcf', f'{self.outdir}/{target}/{target}.pcf')
def do_bit(self, target):
self.create_outdir(target)
self.enter_builddir()
print('+ Generate output files')
extra_opts = self.config.get(target, 'extra_options').split('\n')
opts = {}
for o in extra_opts:
tp = o.split()[0]
op = ' '.join(o.split()[1:])
opts[tp] = op
if 'bitgen' not in opts:
opts['bitgen'] = ''
if 'trce' not in opts:
opts['trce'] = ''
pid = subprocess.Popen(f"bitgen -intstyle xflow -g Binary:Yes -w {opts['bitgen']} {self.curdir}/{self.outdir}/{target}/{target}.ncd bit.bit {self.curdir}/{self.outdir}/{target}/{target}.pcf", shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
res = pid.returncode
print('')
self.leave_builddir()
shutil.copyfile(f'{self.builddir}/bit.bit', f'{self.outdir}/{target}/{target}.bit')
shutil.copyfile(f'{self.builddir}/bit.bin', f'{self.outdir}/{target}/{target}.bin')
if res!=0:
exit(res)
self.enter_builddir()
pid = subprocess.Popen(f"trce -intstyle xflow {opts['trce']} {self.curdir}/{self.outdir}/{target}/{target}.ncd {self.curdir}/{self.outdir}/{target}/{target}.pcf", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
res = pid.returncode
print('')
self.leave_builddir()
shutil.copyfile(f'{self.builddir}/{target}.twr', f'{self.outdir}/{target}/timing.log')
if res!=0:
exit(res)
def do_floorplan(self, target):
self.create_outdir(target)
self.enter_builddir()
part = f"{self.config.get('target', 'device', fallback='_d_')}{self.config.get('target', 'package', fallback='_p_')}{self.config.get('target', 'speedgrade', fallback='_s_')}"
cons = f"{self.curdir}/{self.config.get(target, 'src_constraints', fallback='__con__')}"
with open('paproj.tcl', 'w') as f:
f.write(f'create_project -name paproj -dir paproj -part {part} -force\n')
f.write('set_property design_mode GateLvl [get_property srcset [current_run -impl]]\n')
f.write(f"set_property edif_top_file {self.curdir}/{self.outdir}/{target}/{target}.ngc [get_property srcset [current_run]]\n")
f.write(f"add_files [list {{{cons}}}] -fileset [get_property constrset [current_run]]\n")
f.write(f"set_property target_constrs_file {cons} [current_fileset -constrset]\n")
f.write(f"link_design\nread_xdl -file {self.curdir}/{self.outdir}/{target}/{target}.ncd\n")
pid = subprocess.Popen('planAhead -source paproj.tcl', shell=True) #, stdout=subprocess.DEVNULL, stderr=None)
res = pid.wait()
self.leave_builddir()
def do_sim(self, target):
self.create_outdir(target)
self.enter_builddir()
print('+ Simulate')
if os.path.exists('isim'):
shutil.rmtree('isim')
with open('sim.prj', 'w') as f:
src = self.config.get(target, 'src_vhdl', fallback='').split()
for s in src:
f.write(f'vhdl work "{self.curdir}/{s}"\n')
src = self.config.get(target, 'src_verilog', fallback='').split()
for s in src:
f.write(f'verilog work "{self.curdir}/{s}"\n')
src = self.config.get(target, 'src_sysverilog', fallback='').split()
for s in src:
f.write(f'verilog work "{self.curdir}/{s}"\n')
# TODO add IP
extras = ''
if self.config.get(target, 'simtype', fallback='presim') == 'postsim':
extras = f"--{self.config.get(target, 'delay', fallback='typ')}delay work.glbl"
pid = subprocess.Popen(f"fuse {extras} work.{self.config.get(target, 'toplevel', fallback='toplevel')} -prj sim.prj -o sim", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
res = pid.returncode
print('')
if res!=0:
self.leave_builddir()
shutil.copyfile(f'{self.builddir}/fuse.log', f'{self.outdir}/{target}/synth.log')
exit(res)
with open('sim.tcl', 'w') as f:
f.write("onerror {resume}\n")
f.write("vcd dumpfile sim.vcd\n")
f.write(f"vcd dumpvars -m {self.config.get(target, 'toplevel', fallback='toplevel')} -l {self.config.get(target, 'levels', fallback='10')}\n")
f.write("vcd dumpon\n")
f.write(f"run {self.config.get(target, 'runtime', fallback='100 ns')}\n")
f.write("vcd dumpflush\nquit\n")
extras = ''
if self.config.get(target, 'simtype', fallback='presim') == 'postsim':
extras = f"-sdf{self.config.get(target, 'delay', fallback='typ')} {self.config.get(target, 'sdfroot', fallback='dut')}={self.curdir}/{self.config.get(target, 'src_sdf', fallback='_s_')}"
pid = subprocess.Popen(f'./sim -tclbatch sim.tcl {extras} > sim.log', shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
res = pid.returncode
print('')
if res!=0:
exit(res)
self.leave_builddir()
if not os.path.exists(f'{self.outdir}/{target}'):
os.mkdir(f'{self.outdir}/{target}')
shutil.copyfile(f'{self.builddir}/sim.vcd', f'{self.outdir}/{target}/output.vcd')
shutil.copyfile(f'{self.builddir}/fuse.log', f'{self.outdir}/{target}/synth.log')
shutil.copyfile(f'{self.builddir}/sim.log', f'{self.outdir}/{target}/output.log')

View File

@ -1,295 +0,0 @@
import os
import paramiko
import struct
import base64
from .Heartbeat import Heartbeat
class exec_REMOTE:
def __init__(self, config, configfile):
self.config = config
self.configfile = configfile
self.privkey = self.config.get('server', 'privkey', fallback='__privkey__')
self.pubkey = self.config.get('server', 'pubkey', fallback='__pubkey__')
self.hostname = self.config.get('server', 'hostname', fallback='__hostname__')
self.port = self.config.get('server', 'port', fallback='__port__')
self.tc = self.config.get('project', 'toolchain', fallback='ISE')
if self.privkey=='__privkey__' or self.pubkey=='__pubkey__' or self.hostname=='__hostname__' or self.port=='__port__':
print("Not enough server information in the config file")
exit(1)
self.host_key = paramiko.RSAKey(filename=self.privkey)
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
trans = paramiko.Transport((self.hostname, int(self.port)))
trans.connect(None, pkey=self.host_key)
self.channel = trans.open_channel('session')
self.hbchannel = trans.open_channel('session')
self.heartbeat = Heartbeat(self.hbchannel)
self.heartbeat.start()
# Send project identification
cmd = b'id' + struct.pack('>q', hash(self.host_key.get_base64()))
self.channel.exec_command(base64.encodebytes(cmd))
def __del__(self):
self.heartbeat.stop()
self.channel.exec_command(base64.encodebytes(b'ex'))
def cmd(self, cmd):
self.channel.exec_command(base64.encodebytes(cmd))
def sstr(self, s):
return struct.pack('>I', len(s)) + s.encode('utf-8')
def rstr(self):
l = struct.unpack('>I', self.channel.recv(4))[0]
return bytes.decode(self.channel.recv(l), 'utf-8')
def recv_dir(self, dr):
self.cmd(b'ls'+self.sstr(dr))
status = self.channel.recv(2)
if status!=b'OK':
msg = self.channel.recv(1024)
print("Error:", bytes.decode(msg, 'ascii'))
exit(1)
ls = self.rstr()
for p in ls.split('\n'):
tp = p[0]
name = p[1:]
if tp=='d':
self.recv_dir(f'{dr}/{name}')
else:
self.recv_file(f'{dr}/{name}')
def send_file(self, file, othername=None):
print(f"> {file}")
if not os.path.exists(file):
print(f"Error: {file} does not exists")
with open(file, 'rb') as f:
stat = os.fstat(f.fileno())
print(' -> fsize', stat.st_size)
if othername is None:
othername = file
fsize = struct.pack('>q', stat.st_size)
self.cmd(b'sf'+self.sstr(othername)+fsize)
status = self.channel.recv(3)
if status!=b'OK\n':
print('Something went wrong...')
exit(1)
i = stat.st_size
while i>0:
fdata = f.read(1024)
i -= 1024
self.channel.sendall(fdata)
def recv_file(self, file):
print(f"< {file}")
if os.path.dirname(file) != '':
os.makedirs(os.path.dirname(file), exist_ok=True)
with open(file, 'wb') as f:
self.cmd(b'rf'+self.sstr(file))
status = self.channel.recv(2)
if status!=b'OK':
msg = self.channel.recv(1024)
print("Error:", bytes.decode(msg, 'ascii'))
exit(1)
fsize = self.channel.recv(8)
fsize = struct.unpack('>q', fsize)[0]
print(' -> fsize', fsize)
while fsize>0:
f.write(self.channel.recv(1024))
fsize -= 1024
def do_ip_gen(self, target):
print("+ Generate IPs")
self.send_file(self.configfile, 'project.cfg')
self.heartbeat.printing = True
self.cmd(b'do'+self.sstr(f'ip {target}'))
res = struct.unpack('>I', self.channel.recv(4))[0]
self.heartbeat.printing = False
print(f' [{res}]')
# get used IP's for target
ips = self.config.get(target, 'src_ip', fallback='').split()
for i, ip in enumerate(ips):
self.recv_dir(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{ip}")
if res != 0:
print("Some error occured...")
exit(1)
def do_synthesize(self, target):
print("+ Synthesize")
self.send_file(self.configfile, 'project.cfg')
src = self.config.get(target, 'src_vhdl', fallback='').split()
for s in src:
self.send_file(s)
src = self.config.get(target, 'src_verilog', fallback='').split()
for s in src:
self.send_file(s)
src = self.config.get(target, 'src_sysverilog', fallback='').split()
for s in src:
self.send_file(s)
src = self.config.get(target, 'src_ip', fallback='').split()
for s in src:
if self.tc=='ISE':
self.send_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{s}/{s}.vhd")
elif self.tc=="VIVADO":
self.send_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{s}/{s}.xci")
if self.tc=="VIVADO":
self.send_file(f"{self.config.get(target, 'src_constraints', fallback='__con__')}")
self.heartbeat.printing = True
self.cmd(b'do'+self.sstr(f'syn {target}'))
res = struct.unpack('>I', self.channel.recv(4))[0]
self.heartbeat.printing = False
print(f' [{res}]')
if res != 0:
print("Some error occured...")
if self.tc=='ISE':
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/syn.log")
elif self.tc=="VIVADO":
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/synth.log")
exit(1)
if self.tc=='ISE':
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{target}.ngc")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{target}.v")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/syn.log")
elif self.tc=="VIVADO":
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/synth.log")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/post_synth.dcp")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/synth_netlist.v")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/synth_netlist.sdf")
def do_implement(self, target):
print("+ Implement")
self.send_file(self.configfile, 'project.cfg')
if self.tc=='ISE':
self.send_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{target}.ngc")
self.send_file(f"{self.config.get(target, 'src_constraints', fallback='__con__')}")
elif self.tc=="VIVADO":
self.send_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/post_synth.dcp")
self.heartbeat.printing = True
self.cmd(b'do'+self.sstr(f'impl {target}'))
res = struct.unpack('>I', self.channel.recv(4))[0]
self.heartbeat.printing = False
print(f' [{res}]')
if res != 0:
print("Some error occured...")
if self.tc=='ISE':
# FIXME possible that not all are there
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/impl-ngd.log")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/impl-map.log")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/impl-par.log")
elif self.tc=="VIVADO":
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/impl.log")
exit(1)
if self.tc=='ISE':
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/impl-ngd.log")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/impl-map.log")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/impl-par.log")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{target}.map.v")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{target}.map.sdf")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{target}.ncd")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{target}.pcf")
elif self.tc=="VIVADO":
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/impl.log")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/post_impl.dcp")
def do_bit(self, target):
print("+ Generate output files")
self.send_file(self.configfile, 'project.cfg')
if self.tc=='ISE':
self.send_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{target}.ncd")
self.send_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{target}.pcf")
elif self.tc=="VIVADO":
self.send_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/post_impl.dcp")
self.heartbeat.printing = True
self.cmd(b'do'+self.sstr(f'bit {target}'))
res = struct.unpack('>I', self.channel.recv(4))[0]
self.heartbeat.printing = False
print(f' [{res}]')
if res != 0:
print("Some error occured...")
if self.tc=='ISE':
# TODO what to send?
pass
elif self.tc=="VIVADO":
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/bit.log")
exit(1)
if self.tc=='ISE':
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/timing.log")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{target}.bit")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{target}.bin")
elif self.tc=="VIVADO":
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/bit.log")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/out.bit")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/out.bin")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/power.log")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/timing.log")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/util.log")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/system.xsa")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/total.dcp")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/impl_netlist.sdf")
self.recv_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/impl_netlist.v")
def do_floorplan(self, target):
print("Error: floorplan editing not implemented for remote execution")
exit(1)
def do_sim(self, target):
print("+ Simulate")
self.send_file(self.configfile, 'project.cfg')
src = self.config.get(target, 'src_vhdl', fallback='').split()
for s in src:
self.send_file(s)
src = self.config.get(target, 'src_verilog', fallback='').split()
for s in src:
self.send_file(s)
src = self.config.get(target, 'src_sysverilog', fallback='').split()
for s in src:
self.send_file(s)
src = self.config.get(target, 'src_sdf', fallback='')
if src!='':
self.send_file(src)
src = self.config.get(target, 'src_ip', fallback='').split()
for s in src:
if self.tc=='ISE':
self.send_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{s}/{s}.vhd")
elif self.tc=="VIVADO":
self.send_file(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}/{s}/{s}.xci")
if self.tc=="VIVADO":
src = self.config.get(target, 'src_c', fallback='').split()
for s in src:
self.send_file(s)
self.heartbeat.printing = True
self.cmd(b'do'+self.sstr(f'sim {target}'))
res = struct.unpack('>I', self.channel.recv(4))[0]
self.heartbeat.printing = False
print(f' [{res}]')
self.recv_dir(f"{self.config.get('project', 'out_dir', fallback='OUT')}/{target}")

View File

@ -1,402 +0,0 @@
import os
import shutil
import subprocess
import time
import glob
class exec_VIVADO:
def __init__(self, config, builddir):
self.config = config
self.builddir = builddir
self.create_builddir()
def create_outdir(self, target):
self.outdir = self.config.get('project', 'out_dir', fallback='OUT')
if not os.path.exists(self.outdir):
os.mkdir(self.outdir)
if not os.path.exists(f'{self.outdir}/{target}'):
os.mkdir(f'{self.outdir}/{target}')
def create_builddir(self):
if not os.path.exists(self.builddir):
os.mkdir(self.builddir)
def enter_builddir(self):
self.curdir = os.getcwd()
os.chdir(self.builddir)
def leave_builddir(self):
os.chdir(self.curdir)
def do_ip_gen(self, target):
# get used IP's for target
ips = self.config.get(target, 'src_ip', fallback='').split()
self.create_outdir(target)
print("+ Generate IPs")
dev = self.config.get('target', 'device', fallback='_d_')
sgrade = self.config.get('target', 'speedgrade', fallback='_s_')
pkg = self.config.get('target', 'package', fallback='_p_')
for i, ip in enumerate(ips):
self.enter_builddir()
ipsec = 'ip_%s'%ip
ipname = self.config.get(ipsec, ipsec)
ipconfig = '[ list \\\n'
for s in self.config[ipsec]:
if s==ipsec:
continue
ipconfig += f' CONFIG.{s.upper()} {{{self.config.get(ipsec, s)}}}\\\n'
ipconfig += ' ]'
with open('do.tcl', 'w') as f:
f.write(f"file mkdir {ip}\ncreate_project -in_memory\nset_property part {dev}{pkg}{sgrade} [current_project]\n")
f.write(f"create_ip -name {ipname.split(':')[2]} -vendor {ipname.split(':')[1]} -library {ipname.split(':')[0 ]} -module_name {ip} -dir {ip}\n")
f.write(f"set_property -dict {ipconfig} [ get_ips {ip} ]\n")
f.write(f"export_ip_user_files -of_objects [get_files {ip}/{ip}/{ip}.xci ] -no_script -sync -force -quiet\n")
f.write(f"upgrade_ip [get_ips]\ngenerate_target all [get_ips]\n#synth_ip [get_ips]\n")
# f.write(f"export_simulation -directory {ip} -simulator xsim -absolute_path -export_source_files -of_objects [get_files {ip}/{ip}/{ip}.xci]")
pid = subprocess.Popen('vivado -mode batch -source do.tcl', shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
ret = pid.returncode
print('')
if ret != 0:
self.leave_builddir()
if not os.path.exists(f'{self.outdir}/{target}/{ip}'):
os.mkdir(f'{self.outdir}/{target}/{ip}')
shutil.copyfile(f"{self.builddir}/vivado.log", f'{self.outdir}/{target}/{ip}/log.log')
exit(ret)
self.leave_builddir()
if not os.path.exists(f'{self.outdir}/{target}/{ip}'):
os.mkdir(f'{self.outdir}/{target}/{ip}')
shutil.copyfile(f"{self.builddir}/{ip}/{ip}/{ip}.vho", f'{self.outdir}/{target}/{ip}/{ip}.vho')
shutil.copyfile(f"{self.builddir}/{ip}/{ip}/{ip}.veo", f'{self.outdir}/{target}/{ip}/{ip}.veo')
shutil.copyfile(f"{self.builddir}/{ip}/{ip}/{ip}.xci", f'{self.outdir}/{target}/{ip}/{ip}.xci')
shutil.copyfile(f"{self.builddir}/vivado.log", f'{self.outdir}/{target}/{ip}/log.log')
for f in glob.glob(f"{self.builddir}/{ip}/{ip}/*.c"):
shutil.copy(f, f'{self.outdir}/{target}/{ip}/')
for f in glob.glob(f"{self.builddir}/{ip}/{ip}/*.h"):
shutil.copy(f, f'{self.outdir}/{target}/{ip}/')
def do_synthesize(self, target):
self.create_outdir(target)
self.enter_builddir()
print('+ Synthesize')
extra_opts = self.config.get(target, 'extra_options').split('\n')
opts = {}
for o in extra_opts:
tp = o.split()[0]
op = ' '.join(o.split()[1:])
opts[tp] = op
if 'syn' not in opts:
opts['syn'] = ''
if 'netlist_top' not in opts:
opts['netlist_top'] = self.config.get(target, 'toplevel', fallback='toplevel')
dev = self.config.get('target', 'device', fallback='_d_')
sgrade = self.config.get('target', 'speedgrade', fallback='_s_')
pkg = self.config.get('target', 'package', fallback='_p_')
with open('do.tcl', 'w') as f:
src = self.config.get(target, 'src_vhdl', fallback='').split()
for s in src:
f.write(f'read_vhdl "{self.curdir}/{s}"\n')
src = self.config.get(target, 'src_verilog', fallback='').split()
for s in src:
f.write(f'read_verilog "{self.curdir}/{s}"\n')
src = self.config.get(target, 'src_sysverilog', fallback='').split()
for s in src:
f.write(f'read_verilog -sv "{self.curdir}/{s}"\n')
src = self.config.get(target, 'src_constraints', fallback='')
f.write(f'read_xdc "{self.curdir}/{src}"\n')
src = self.config.get(target, 'src_ip', fallback='').split()
for s in src:
if os.path.exists(s):
shutil.rmtree(s)
os.mkdir(s)
shutil.copyfile(f'{self.curdir}/{self.outdir}/{target}/{s}/{s}.xci', f'{s}/{s}.xci')
f.write(f'read_ip "{s}/{s}.xci"\n')
f.write(f"set_property part {dev}{pkg}{sgrade} [current_project]\n")
f.write(f"upgrade_ip [get_ips]\ngenerate_target all [get_ips]\nsynth_ip [get_ips]\n")
f.write(f"synth_design -top {self.config.get(target, 'toplevel', fallback='toplevel')} -part {dev}{pkg}{sgrade} {opts['syn']}\n")
f.write(f"write_checkpoint -force post_synth.dcp\nwrite_verilog -force -mode timesim -cell {opts['netlist_top']} -sdf_anno true -nolib netlist.v\n")
f.write(f"write_sdf -force -cell {opts['netlist_top']} -mode timesim netlist.sdf\n")
pid = subprocess.Popen('vivado -mode batch -source do.tcl', shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
ret = pid.returncode
print('')
if ret != 0:
self.leave_builddir()
shutil.copyfile(f"{self.builddir}/vivado.log", f'{self.outdir}/{target}/synth.log')
exit(ret)
self.leave_builddir()
shutil.copyfile(f'{self.builddir}/netlist.v', f'{self.outdir}/{target}/synth_netlist.v')
shutil.copyfile(f'{self.builddir}/netlist.sdf', f'{self.outdir}/{target}/synth_netlist.sdf')
shutil.copyfile(f'{self.builddir}/post_synth.dcp', f'{self.outdir}/{target}/post_synth.dcp')
shutil.copyfile(f"{self.builddir}/vivado.log", f'{self.outdir}/{target}/synth.log')
def do_implement(self, target):
self.create_outdir(target)
self.enter_builddir()
print('+ Implement')
extra_opts = self.config.get(target, 'extra_options').split('\n')
opts = {}
for o in extra_opts:
tp = o.split()[0]
op = ' '.join(o.split()[1:])
opts[tp] = op
if 'opt' not in opts:
opts['opt'] = ''
if 'place' not in opts:
opts['place'] = ''
if 'route' not in opts:
opts['route'] = ''
with open('do.tcl', 'w') as f:
f.write(f"open_checkpoint {self.curdir}/{self.outdir}/{target}/post_synth.dcp\n")
f.write(f"opt_design {opts['opt']}\nplace_design {opts['place']}\nroute_design {opts['route']}\n")
f.write(f"write_checkpoint -force {self.curdir}/{self.outdir}/{target}/post_impl.dcp\n")
pid = subprocess.Popen('vivado -mode batch -source do.tcl', shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
ret = pid.returncode
print('')
if ret != 0:
self.leave_builddir()
shutil.copyfile(f"{self.builddir}/vivado.log", f'{self.outdir}/{target}/impl.log')
exit(ret)
self.leave_builddir()
shutil.copyfile(f"{self.builddir}/vivado.log", f'{self.outdir}/{target}/impl.log')
def do_bit(self, target):
self.create_outdir(target)
self.enter_builddir()
print('+ Generate output files')
extra_opts = self.config.get(target, 'extra_options').split('\n')
opts = {}
for o in extra_opts:
tp = o.split()[0]
op = ' '.join(o.split()[1:])
opts[tp] = op
if 'netlist_top' not in opts:
opts['netlist_top'] = self.config.get(target, 'toplevel', fallback='toplevel')
with open('do.tcl', 'w') as f:
f.write(f"open_checkpoint {self.curdir}/{self.outdir}/{target}/post_impl.dcp\n")
f.write(f"set_property SEVERITY {{Warning}} [get_drc_checks NSTD-1]\nset_property SEVERITY {{Warning}} [get_drc_checks UCIO-1]\n")
f.write(f"set_property BITSTREAM.General.UnconstrainedPins {{Allow}} [current_design]\n")
f.write(f"write_debug_probes -force out.ltx\nwrite_bitstream -force -bin_file out.bit\nreport_timing_summary -file timing.log\nreport_power -file power.log\n")
f.write(f"report_utilization -file util.log\n")
f.write(f"write_checkpoint -force {self.curdir}/{self.outdir}/{target}/total.dcp\n")
f.write(f"open_checkpoint {self.curdir}/{self.outdir}/{target}/total.dcp\n")
f.write(f"write_hw_platform -fixed -force -file {self.curdir}/{self.outdir}/{target}/system.xsa\n")
f.write(f"write_verilog -force -mode timesim -cell {opts['netlist_top']} -rename_top {opts['netlist_top']} -sdf_anno true netlist.v\n") # -nolib
f.write(f"write_sdf -force -cell {opts['netlist_top']} -rename_top {opts['netlist_top']} -mode timesim netlist.sdf\n")
pid = subprocess.Popen('vivado -mode batch -source do.tcl', shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
ret = pid.returncode
print('')
if ret != 0:
self.leave_builddir()
shutil.copyfile(f"{self.builddir}/vivado.log", f'{self.outdir}/{target}/bit.log')
exit(ret)
self.leave_builddir()
shutil.copyfile(f"{self.builddir}/vivado.log", f'{self.outdir}/{target}/bit.log')
shutil.copyfile(f"{self.builddir}/timing.log", f'{self.outdir}/{target}/timing.log')
shutil.copyfile(f"{self.builddir}/util.log", f'{self.outdir}/{target}/util.log')
shutil.copyfile(f"{self.builddir}/power.log", f'{self.outdir}/{target}/power.log')
shutil.copyfile(f"{self.builddir}/out.bit", f'{self.outdir}/{target}/out.bit')
shutil.copyfile(f"{self.builddir}/out.bin", f'{self.outdir}/{target}/out.bin')
shutil.copyfile(f"{self.builddir}/netlist.v", f'{self.outdir}/{target}/impl_netlist.v')
shutil.copyfile(f"{self.builddir}/netlist.sdf", f'{self.outdir}/{target}/impl_netlist.sdf')
def do_floorplan(self, target):
self.create_outdir(target)
self.enter_builddir()
print('+ Open floorplan viewer')
with open('do.tcl', 'w') as f:
f.write(f"open_checkpoint {self.curdir}/{self.outdir}/{target}/post_impl.dcp\n")
f.write(f"start_gui")
pid = subprocess.Popen('vivado -mode batch -source do.tcl', shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
ret = pid.returncode
print('')
self.leave_builddir()
if ret != 0:
exit(ret)
def do_sim(self, target):
self.create_outdir(target)
self.enter_builddir()
print('+ Simulate')
if os.path.exists('sim'):
shutil.rmtree('sim')
dev = self.config.get('target', 'device', fallback='_d_')
sgrade = self.config.get('target', 'speedgrade', fallback='_s_')
pkg = self.config.get('target', 'package', fallback='_p_')
with open('do.tcl', 'w') as f:
f.write(f"create_project -force -part {dev}{pkg}{sgrade} sim sim\n")
src = self.config.get(target, 'src_vhdl', fallback='').split()
for s in src:
f.write(f'add_files -norecurse -scan_for_includes {self.curdir}/{s}\n')
f.write(f'import_files -norecurse {self.curdir}/{s}\n')
src = self.config.get(target, 'src_verilog', fallback='').split()
for s in src:
f.write(f'add_files -norecurse -scan_for_includes {self.curdir}/{s}\n')
f.write(f'import_files -norecurse {self.curdir}/{s}\n')
src = self.config.get(target, 'src_sysverilog', fallback='').split()
for s in src:
f.write(f'add_files -norecurse -scan_for_includes {self.curdir}/{s}\n')
f.write(f'import_files -norecurse {self.curdir}/{s}\n')
src = self.config.get(target, 'src_ip', fallback='').split()
for s in src:
f.write(f'add_files -norecurse {self.curdir}/{self.outdir}/{target}/{s}/{s}.xci\n')
src = self.config.get(target, 'src_c', fallback='').split()
for s in src:
if s.endswith('.h'):
continue
f.write(f'add_files -norecurse -scan_for_includes {self.curdir}/{s}\n')
f.write(f'import_files -norecurse {self.curdir}/{s}\n')
if self.config.get(target, 'src_sdf', fallback='__sdf__') != '__sdf__':
s = self.config.get(target, 'src_sdf', fallback='__sdf__')
f.write(f'add_files -norecurse -scan_for_includes {self.curdir}/{s}\n')
f.write(f'import_files -norecurse {self.curdir}/{s}\n')
f.write(f"file mkdir sim/sim.sim/sim_1/behav/xsim\nfile copy -force {self.curdir}/{s} {self.curdir}/{self.builddir}/sim/sim.sim/sim_1/behav/xsim/netlist.sdf\n")
# f.write(f"file mkdir sim/sim.sim/sim_1/behav/xsim\nfile copy -force {self.curdir}/{s} {self.curdir}/{self.builddir}/sim/sim.sim/sim_1/behav/xsim/{os.path.split(s)[1]}\n")
f.write(f"set_property top {self.config.get(target, 'toplevel', fallback='toplevel')} [get_filesets sim_1]\n")
f.write("set_property top_lib xil_defaultlib [get_filesets sim_1]\n")
f.write("launch_simulation -noclean_dir -scripts_only -absolute_path\n")
pid = subprocess.Popen('vivado -mode batch -source do.tcl', shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
ret = pid.returncode
print('')
if ret != 0:
self.leave_builddir()
print("Something went wrong...")
shutil.copyfile(f"{self.builddir}/vivado.log", f'{self.outdir}/{target}/prepare.log')
exit(ret)
shutil.copyfile(f"vivado.log", f'{self.curdir}/{self.outdir}/{target}/prepare.log')
extras = ''
if self.config.get(target, 'simtype', fallback='presim') == 'postsim':
extras = f"-{self.config.get(target, 'delay', fallback='typ')}delay -transport_int_delays -pulse_r 0 -pulse_int_r 0 -L simprims_ver"
pid = subprocess.Popen(f'sed -i "s/xelab/xelab {extras}/g" elaborate.sh', shell=True, cwd='sim/sim.sim/sim_1/behav/xsim', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
ret = pid.returncode
print('')
if ret!=0:
print("Something went wrong with editing elaborate stage...")
exit(ret)
if self.config.get(target, 'simtype', fallback='presim') == 'postsim':
pid = subprocess.Popen(f"sed -i '/ \/I /d' netlist.sdf && sed -i '/glbl.v/d' *.prj", shell=True, cwd='sim/sim.sim/sim_1/behav/xsim', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
# pid = subprocess.Popen(f"sed -i '/glbl.v/d' *.prj", shell=True, cwd='sim/sim.sim/sim_1/behav/xsim', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
ret = pid.returncode
print('')
if ret!=0:
print("Something went wrong with editing project files...")
exit(ret)
pid = subprocess.Popen(f'bash compile.sh', shell=True, cwd='sim/sim.sim/sim_1/behav/xsim', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
ret = pid.returncode
print('')
if ret!=0:
self.leave_builddir()
print("Compile error")
shutil.copyfile(f"{self.builddir}/sim/sim.sim/sim_1/behav/xsim/compile.log", f'{self.outdir}/{target}/compile.log')
exit(ret)
shutil.copyfile(f"{self.curdir}/{self.builddir}/sim/sim.sim/sim_1/behav/xsim/compile.log", f'{self.curdir}/{self.outdir}/{target}/compile.log')
pid = subprocess.Popen(f'bash elaborate.sh', shell=True, cwd='sim/sim.sim/sim_1/behav/xsim', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
ret = pid.returncode
print('')
if ret!=0:
self.leave_builddir()
print("Elaborate error")
shutil.copyfile(f"{self.builddir}/sim/sim.sim/sim_1/behav/xsim/elaborate.log", f'{self.outdir}/{target}/elaborate.log')
exit(ret)
shutil.copyfile(f"{self.curdir}/{self.builddir}/sim/sim.sim/sim_1/behav/xsim/elaborate.log", f'{self.curdir}/{self.outdir}/{target}/elaborate.log')
with open(f"sim/sim.sim/sim_1/behav/xsim/{self.config.get(target, 'toplevel', fallback='toplevel')}.tcl", 'w') as f:
f.write(f"open_vcd out.vcd\nlog_vcd\nrun {self.config.get(target, 'runtime', fallback='100 ns')}\nclose_vcd\nquit\n")
pid = subprocess.Popen(f'bash simulate.sh', shell=True, cwd='sim/sim.sim/sim_1/behav/xsim', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
while pid.poll() is None:
print('.', end='', flush=True)
time.sleep(2)
ret = pid.returncode
print('')
if ret!=0:
self.leave_builddir()
print("Simulation error")
shutil.copyfile(f"{self.builddir}/sim/sim.sim/sim_1/behav/xsim/simulate.log", f'{self.outdir}/{target}/simulate.log')
exit(ret)
shutil.copyfile(f"{self.curdir}/{self.builddir}/sim/sim.sim/sim_1/behav/xsim/simulate.log", f'{self.curdir}/{self.outdir}/{target}/simulate.log')
self.leave_builddir()
shutil.copyfile(f'{self.builddir}/sim/sim.sim/sim_1/behav/xsim/out.vcd', f'{self.outdir}/{target}/output.vcd')

View File

@ -1 +0,0 @@
paramiko

View File

@ -1,234 +0,0 @@
#!/usr/bin/env python3
import sys
import os
import configparser
import paramiko
import socket
from remotesyn import Connection, exec_ISE, exec_VIVADO, exec_REMOTE
def server(accidentals, positionals):
addr = accidentals['server'].split(':')
if len(addr)!=2:
print("Host address must be in form hostname:port")
exit(1)
host_key = paramiko.RSAKey(filename=accidentals['privkey'])
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((addr[0], int(addr[1])))
sock.listen(100)
# Get authorized hosts
with open(accidentals['authorized'], 'r') as f:
authorized = f.read().split('\n')
running = True
threads = []
try:
while running:
client, addr = sock.accept()
conn = Connection(client, addr, host_key, authorized)
conn.start()
threads.append(conn)
except KeyboardInterrupt:
print("Stopping server")
running = False
for t in threads:
t.stop()
finally:
sock.close()
def main(accidentals, positionals):
if 'server' in accidentals:
return server(accidentals, positionals)
elif 'local' in accidentals:
config = accidentals['config']
if config.get('project', 'toolchain') == 'ISE':
execInterface = exec_ISE(config, accidentals['builddir'])
else:
execInterface = exec_VIVADO(config, accidentals['builddir'])
else:
config = accidentals['config']
execInterface = exec_REMOTE(config, accidentals['configname'])
i = 0
while i< len(positionals):
action = positionals[i]
i += 1
if action == 'ip':
if i>=len(positionals):
print("Unexpected end of input")
exit(1)
target = positionals[i]
i += 1
execInterface.do_ip_gen(target)
elif action == 'syn':
if i>=len(positionals):
print("Unexpected end of input")
exit(1)
target = positionals[i]
i += 1
execInterface.do_synthesize(target)
elif action == 'impl':
if i>=len(positionals):
print("Unexpected end of input")
exit(1)
target = positionals[i]
i += 1
execInterface.do_implement(target)
elif action == 'bit':
if i>=len(positionals):
print("Unexpected end of input")
exit(1)
target = positionals[i]
i += 1
execInterface.do_bit(target)
elif action == 'all':
if i>=len(positionals):
print("Unexpected end of input")
exit(1)
target = positionals[i]
i += 1
execInterface.do_synthesize(target)
execInterface.do_implement(target)
execInterface.do_bit(target)
elif action == 'floorplan':
if i>=len(positionals):
print("Unexpected end of input")
exit(1)
target = positionals[i]
i += 1
execInterface.do_floorplan(target)
elif action == 'sim':
if i>=len(positionals):
print("Unexpected end of input")
exit(1)
target = positionals[i]
i += 1
execInterface.do_sim(target)
else:
print("Unknown action...")
exit(1)
def print_help():
print("Unified FPGA synthesizer frontend\r\n(c) Joppe Blondel - 2022\r\n")
print(f"Usage: {sys.argv[0]} [ OPTIONS ] action [ target ] ...")
print("where OPTIONS := { -h | -l | -s host:port privkey pubkey authorized | -c config | -b build_dir }")
print(" action := { ip | syn | impl | bit | all | floorplan | sim | init }")
print("")
print("Options:")
print(" -h Show this help message")
print(" -l Local build")
print(" -s <s-info> Start server with server information s-info. host:port is the address to bind")
print(" to, privkey and pubkey are the ssh keys of the server and authorized is the")
print(" authorized_keys file for the SSH server")
print(" -c <file> Configuration file, defaults to project.cfg")
print(" -b <dir> Build directory, defaults to .build")
print("")
print("Actions:")
print("ip <target> Generate IP files from vendor provided libraries")
print("syn <target> Synthesize design for target")
print("impl <target> Route and place design for target")
print("bit <target> Generate output files and run analysis for target")
print("all <target> Generate IP, synthesize, route and place design for target")
print("floorplan <target> Run floorplan editor, currently only for local execution")
print("sim <simtarget> Run simulation target")
print("init Initialize project")
if __name__=="__main__":
accidentals = {}
positionals = []
if len(sys.argv)==1:
print_help()
exit(1)
i = 1
while i<len(sys.argv):
if sys.argv[i].startswith('-'):
if sys.argv[i] == '-h':
print_help()
exit(0)
elif sys.argv[i] == '-l':
accidentals['local'] = True
elif sys.argv[i] == '-s':
if i+1>=len(sys.argv):
print("Unexpected end of input")
exit(1)
accidentals['server'] = sys.argv[i+1]
i += 1
if i+1>=len(sys.argv):
print("Unexpected end of input")
exit(1)
accidentals['privkey'] = sys.argv[i+1]
i += 1
if i+1>=len(sys.argv):
print("Unexpected end of input")
exit(1)
accidentals['pubkey'] = sys.argv[i+1]
i += 1
if i+1>=len(sys.argv):
print("Unexpected end of input")
exit(1)
accidentals['authorized'] = sys.argv[i+1]
i += 1
elif sys.argv[i] == '-c':
if i+1>=len(sys.argv):
print("Unexpected end of input")
exit(1)
accidentals['config'] = sys.argv[i+1]
i += 1
elif sys.argv[i] == '-b':
if i+1>=len(sys.argv):
print("Unexpected end of input")
exit(1)
accidentals['builddir'] = sys.argv[i+1]
i += 1
else:
if sys.argv[i] == 'init':
print("+ Generate example configuration file")
with open('example.cfg', 'w') as f:
f.write("# PROJECT SETTINGS\n")
f.write("# ----------------\n")
f.write("[server]\nhostname = localhost\nport = 8080\nprivkey = keys/id_rsa\npubkey = keys/id_rsa.pub\n\n")
f.write("[project]\n# Toolchain selection. choose between [ISE, VIVADO]\ntoolchain = ISE\nout_dir = OUT\n\n")
f.write("[target]\nfamily = spartan6\ndevice = xc6slx9\npackage = tqg144\nspeedgrade = -2\n\n")
f.write("# HARDWARE TARGETS\n")
f.write("# ----------------\n")
f.write("[total]\n")
f.write("src_vhdl = RTL/toplevel.vhd\nsrc_verilog = \nsrc_sysverilog = \n")
f.write("src_constraints = CON/toplevel.ucf\nsrc_ip = \ntoplevel = toplevel\nextra_options = ")
exit(1)
positionals.append(sys.argv[i])
i += 1
if 'config' not in accidentals and 'server' not in accidentals:
# Running in client mode and no config file specified -> pick default
accidentals['config'] = 'project.cfg'
if 'config' in accidentals and 'server' not in accidentals:
if os.path.exists(accidentals['config']):
accidentals['configname'] = accidentals['config']
config = configparser.ConfigParser()
config.read(accidentals['config'])
accidentals['config'] = config
else:
print(f"Config file \'{accidentals['config']}\' not found")
exit(1)
if ('server' in accidentals or 'local' in accidentals) and 'builddir' not in accidentals:
accidentals['builddir'] = '.build'
main(accidentals, positionals)
exit(0)

View File

@ -1,2 +0,0 @@
[metadata]
description-file = README.md

View File

@ -1,27 +0,0 @@
from setuptools import setup
with open("README.md", 'r') as f:
long_description = f.read()
setup(
name='remotesyn',
version='0.1',
description='Remote FPGA synthesis abstraction tool',
author='Joppe Blondel',
author_email='joppe@blondel.nl',
download_url='',
url='https://git.joppeb.nl/joppe/remotesyn',
keywords = ['FPGA', 'Synthesis', 'Xilinx', 'ISE', 'Vivado',],
classifiers=[
'Development Status :: 3 - Alpha',
'License :: OSI Approved :: BSD License',
'Programming Language :: Python :: 3',
],
packages=['remotesyn'],
licence='BSD Licence',
install_requires=['paramiko'],
scripts=['scripts/remotesyn']
)