New project structure
Rewrite of all functions Signed-off-by: Jojojoppe <joppe@blondel.nl>
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
OUT
|
||||
BUILD
|
||||
*__pycache__
|
||||
*egg-info
|
21
LICENCE
21
LICENCE
@ -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.
|
30
README.md
30
README.md
@ -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
|
||||
```
|
@ -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;
|
2
examples/spartan6/.gitignore
vendored
2
examples/spartan6/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
OUT
|
||||
.build
|
@ -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;
|
@ -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>
|
@ -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;
|
@ -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
|
2
examples/zynq7000/.gitignore
vendored
2
examples/zynq7000/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
OUT
|
||||
.build
|
@ -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]}]
|
@ -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>
|
@ -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;
|
@ -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;
|
@ -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
|
@ -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
19
project.cfg
Normal 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
42
rbuild.py
Executable 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
|
@ -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)
|
1
remotesyn/ISE/__init__.py
Normal file
1
remotesyn/ISE/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .synth import synth
|
14
remotesyn/ISE/runner.py
Normal file
14
remotesyn/ISE/runner.py
Normal 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
107
remotesyn/ISE/synth.py
Normal 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
|
@ -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
22
remotesyn/copy.py
Normal 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")
|
@ -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')
|
@ -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}")
|
@ -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')
|
@ -1 +0,0 @@
|
||||
paramiko
|
@ -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)
|
27
setup.py
27
setup.py
@ -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']
|
||||
)
|
Reference in New Issue
Block a user