Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fpga_diff/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
!*.tcl

fpga_*/
partition-synth-*/
src/tcl/cpu_files.tcl
14 changes: 13 additions & 1 deletion fpga_diff/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ ILA_DEPTH ?= 16384
XDMA_LINK_WIDTH ?= X4
VIVADO_JOBS ?=
DDR_RANK_WIDTH ?= 2
PARTITION_SYNTH ?= 0
PARTITION_SYNTH_OUT ?=
PARTITION_SYNTH_PARALLEL ?= 16
PARTITION_SYNTH_JOBS ?= 8
export ENABLE_ILA ILA_DEPTH XDMA_LINK_WIDTH VIVADO_JOBS DDR_RANK_WIDTH
# Supported CPU parameters:
# kmh
Expand All @@ -23,7 +27,7 @@ PRJ_NAME = fpga_$(CPU)$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),)
PRJ_DIR ?= $(ENV_SCRIPTS_HOME)/$(PRJ_NAME)
PRJ ?= $(PRJ_DIR)/$(PRJ_NAME).xpr

.PHONY: bitstream vivado dump_ila write_jtag_flash update_core_flist
.PHONY: synth bitstream vivado dump_ila write_jtag_flash update_core_flist

# Get Vivado version
VIVADO_VERSION := $(shell vivado -version 2>/dev/null | head -1 | grep -o '[0-9]\{4\}\.[0-9]' || echo "unknown")
Expand All @@ -33,7 +37,15 @@ check_vivado_version:

# Run synthesis using Vivado
synth:
ifeq ($(PARTITION_SYNTH),1)
@test -f "$(PRJ)" || { echo "ERROR: project not found: $(PRJ)" >&2; exit 1; }
tools/partition_synth/run.sh \
--origin-dir . --project "$(PRJ)" \
--parallel "$(PARTITION_SYNTH_PARALLEL)" \
--jobs-per-partition "$(PARTITION_SYNTH_JOBS)"$(if $(strip $(PARTITION_SYNTH_OUT)), --out-dir "$(PARTITION_SYNTH_OUT)")
else
vivado -mode batch -source ./tools/gen_synth.tcl -tclargs $(PRJ)
endif

# Generate FPGA bitstream
bitstream:
Expand Down
40 changes: 40 additions & 0 deletions fpga_diff/src/constr/common/clock_defs.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
########################################################################
# Shared primary-clock definitions for top-level and OOC synthesis.
########################################################################

set fpga_primary_clock_specs {
{PCIE_EP_CLK_IN 10.000 pcie_ep_gt_ref_clk_p}
{mac_rx_clk 40.000 RGMII_RXCLK}
{mac_tx_clk 40.000 RGMII_TXCLK}
{mdc_clk 400.000 MDC}
{CPU_CLK_IN 5.000 clk6_p}
{TMCLK 1000.000 clk8_p}
{DEBUG_CLK_IN 40.000 clk5_p}
{PCIE_CLK_IN 10.000 refclk_p}
{PCIE2_CLK_IN 10.000 refclk2_p}
{jtag_vclk 83.333 JTAG_TCK}
}

proc fpga_clock_spec {clock_name} {
global fpga_primary_clock_specs

foreach spec $fpga_primary_clock_specs {
if {[lindex $spec 0] eq $clock_name} {
return $spec
}
}
error "unknown FPGA primary clock '$clock_name'"
}

proc fpga_clock_period {clock_name} {
return [lindex [fpga_clock_spec $clock_name] 1]
}

proc fpga_create_clock {clock_name objects} {
create_clock -period [fpga_clock_period $clock_name] -name $clock_name $objects
}

proc fpga_create_top_clock {clock_name} {
set spec [fpga_clock_spec $clock_name]
fpga_create_clock $clock_name [get_ports [lindex $spec 2]]
}
21 changes: 11 additions & 10 deletions fpga_diff/src/constr/common/fpga.xdc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
####### Main board
#clk

source [file normalize [file join [file dirname [info script]] clock_defs.tcl]]


set_property PACKAGE_PIN AY50 [get_ports clk8_p]
Expand Down Expand Up @@ -54,7 +55,7 @@ set_property PACKAGE_PIN AD15 [get_ports pcie_ep_lnk_up]

set_property IOSTANDARD LVCMOS33 [get_ports pcie_ep_lnk_up]
set_property IOSTANDARD LVCMOS18 [get_ports pcie_ep_perstn]
create_clock -name PCIE_EP_CLK_IN -period 10.000 [get_ports pcie_ep_gt_ref_clk_p]
fpga_create_top_clock PCIE_EP_CLK_IN
#gpio
#set_property PACKAGE_PIN AA15 [get_ports GPIO_O0]

Expand Down Expand Up @@ -351,8 +352,8 @@ set_property PACKAGE_PIN CB23 [get_ports PERST2_N]
set_property PACKAGE_PIN Y52 [get_ports clk7_p]
set_property PACKAGE_PIN Y53 [get_ports clk7_n]

create_clock -period 40.000 -name mac_rx_clk [get_ports RGMII_RXCLK]
create_clock -period 40.000 -name mac_tx_clk [get_ports RGMII_TXCLK]
fpga_create_top_clock mac_rx_clk
fpga_create_top_clock mac_tx_clk
set_clock_groups -asynchronous -group [get_clocks mac_rx_clk -include_generated_clocks]
create_clock -period 40.000 -name rgmii_rx_vclk_1
set_false_path -setup -rise_from [get_clocks rgmii_rx_vclk_1] -fall_to [get_clocks mac_rx_clk]
Expand Down Expand Up @@ -422,13 +423,13 @@ set_property IOSTANDARD LVCMOS18 [get_ports RGMII_TXD3]
set_property IOSTANDARD LVCMOS18 [get_ports MDC]
set_property IOSTANDARD LVCMOS18 [get_ports MDIO]
set_property IOSTANDARD LVCMOS18 [get_ports PHY_RESET_B]
create_clock -period 400.000 -name mdc_clk [get_ports MDC]
create_clock -period 5.000 -name CPU_CLK_IN [get_ports clk6_p]
create_clock -period 1000.000 -name TMCLK [get_ports clk8_p]
create_clock -period 40.000 -name DEBUG_CLK_IN [get_ports clk5_p]
create_clock -period 10.000 -name PCIE_CLK_IN [get_ports refclk_p]
create_clock -period 10.000 -name PCIE2_CLK_IN [get_ports refclk2_p]
create_clock -period 83.333 -name jtag_vclk [get_ports JTAG_TCK]
fpga_create_top_clock mdc_clk
fpga_create_top_clock CPU_CLK_IN
fpga_create_top_clock TMCLK
fpga_create_top_clock DEBUG_CLK_IN
fpga_create_top_clock PCIE_CLK_IN
fpga_create_top_clock PCIE2_CLK_IN
fpga_create_top_clock jtag_vclk
set_clock_groups -asynchronous -group [get_clocks jtag_vclk -include_generated_clocks]
set_clock_groups -asynchronous -group [get_clocks -include_generated_clocks CPU_CLK_IN] -group [get_clocks -include_generated_clocks TMCLK]
set_clock_groups -asynchronous -group [get_clocks -include_generated_clocks CPU_CLK_IN] -group [get_clocks -include_generated_clocks DEBUG_CLK_IN]
Expand Down
44 changes: 37 additions & 7 deletions fpga_diff/src/tcl/common/header_files.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ proc fpga_append_unique {var_name value} {

proc fpga_included_source_files {files include_dirs} {
array set known_files {}
array set files_by_tail {}
set search_dirs {}

foreach dir $include_dirs {
Expand All @@ -24,6 +25,8 @@ proc fpga_included_source_files {files include_dirs} {
}
set path [file normalize $file]
set known_files($path) 1
lappend files_by_tail([file tail $path]) $path
fpga_append_unique search_dirs [file dirname $path]
}

array set included_files {}
Expand All @@ -34,6 +37,13 @@ proc fpga_included_source_files {files include_dirs} {
continue
}

set include_tail [file tail $include_path]
if {[info exists files_by_tail($include_tail)] &&
[llength $files_by_tail($include_tail)] == 1} {
set included_files([lindex $files_by_tail($include_tail) 0]) 1
continue
}

if {[file pathtype $include_path] eq "absolute"} {
set candidates [list [file normalize $include_path]]
} else {
Expand All @@ -43,12 +53,22 @@ proc fpga_included_source_files {files include_dirs} {
}
}

set included_path ""
foreach candidate $candidates {
if {[info exists known_files($candidate)]} {
set included_files($candidate) 1
set included_path $candidate
break
}
}
if {$included_path eq "" && [info exists files_by_tail($include_tail)]} {
set same_tail $files_by_tail($include_tail)
if {[llength $same_tail] == 1} {
set included_path [lindex $same_tail 0]
}
}
if {$included_path ne ""} {
set included_files($included_path) 1
}
}
close $in
}
Expand All @@ -61,17 +81,27 @@ proc fpga_set_header_file_types {files include_dirs} {
set header_files($file) 1
}

set header_paths {}
set verilog_paths {}
foreach file $files {
set objects [get_files -quiet $file]
if {[llength $objects] == 0} {
continue
}

set extension [string tolower [file extension $file]]
set path [file normalize $file]
if {$extension in {.svh .vh} || [info exists header_files($path)]} {
set_property -name file_type -value {Verilog Header} -objects $objects
lappend header_paths $path
} elseif {$extension eq ".v"} {
lappend verilog_paths $path
}
}

if {[llength $header_paths] > 0} {
set objects [get_files -quiet $header_paths]
if {[llength $objects] > 0} {
set_property -name file_type -value {Verilog Header} -objects $objects
}
}
if {[llength $verilog_paths] > 0} {
set objects [get_files -quiet $verilog_paths]
if {[llength $objects] > 0} {
set_property -name file_type -value {SystemVerilog} -objects $objects
}
}
Expand Down
8 changes: 8 additions & 0 deletions fpga_diff/tools/gen_synth.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ if {[llength $synth_runs] == 0} {
}

set synth_run [lindex $synth_runs 0]

set partition_dir [file normalize [file join [file dirname [info script]] partition_synth]]
if {[file isfile "$partition_dir/sources.tcl"]} {
source "$partition_dir/sources.tcl"
if {[ps_restore_project_sources] > 0} {
reset_run $synth_run
}
}
set status [get_property STATUS $synth_run]
puts "INFO: synth_1 status: $status"

Expand Down
149 changes: 149 additions & 0 deletions fpga_diff/tools/partition_synth/defs.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
########################################################################
# Common helpers for parallel OOC partition declarations.
########################################################################

set ps_dir [file normalize [file dirname [info script]]]
set ps_partition_file [file normalize "$ps_dir/partitions.tcl"]

proc ps_load_partitions {} {
global ps_partition_file ps_partition_specs ps_partitions
global ps_partition_top ps_partition_blackboxes ps_partition_clocks

unset -nocomplain ps_partition_specs ps_partition_clock_ports ps_partitions
unset -nocomplain ps_partition_top ps_partition_blackboxes
unset -nocomplain ps_partition_clocks

source $ps_partition_file
if {![info exists ps_partition_specs]} {
error "partition file does not set ps_partition_specs: $ps_partition_file"
}

set ps_partitions {}
array set seen_tops {}
foreach spec $ps_partition_specs {
if {[llength $spec] == 0} {
continue
}

set kind [lindex $spec 0]
switch -- $kind {
module {
if {[llength $spec] != 3} {
error "invalid module partition declaration: $spec"
}
lassign $spec _ name top
set blackboxes {}
}
without {
if {[llength $spec] != 4} {
error "invalid without partition declaration: $spec"
}
lassign $spec _ name top blackboxes
if {[llength $blackboxes] == 0} {
error "without partition needs at least one child module: $spec"
}
}
default {
error "unknown partition declaration '$kind': $spec"
}
}

if {$name eq "" || $top eq ""} {
error "partition name and top module must be nonempty: $spec"
}
if {![regexp {^[A-Za-z_][A-Za-z0-9_]*$} $top]} {
error "unsupported top module name '$top'"
}
foreach blackbox $blackboxes {
if {![regexp {^[A-Za-z_][A-Za-z0-9_]*$} $blackbox]} {
error "unsupported child module name '$blackbox'"
}
}
if {[lsearch -exact $ps_partitions $name] >= 0} {
error "duplicate partition name '$name'"
}
if {[info exists seen_tops($top)]} {
error "module '$top' is the top of more than one partition"
}

lappend ps_partitions $name
set ps_partition_top($name) $top
set seen_tops($top) $name
if {[llength $blackboxes] > 0} {
set ps_partition_blackboxes($name) $blackboxes
}
}

if {![info exists ps_partition_clock_ports]} {
set ps_partition_clock_ports {}
}
if {[llength $ps_partition_clock_ports] % 2 != 0} {
error "partition clock mapping must be a key/value list: $ps_partition_clock_ports"
}
array set declared_partition_clocks $ps_partition_clock_ports
foreach partition [array names declared_partition_clocks] {
if {[lsearch -exact $ps_partitions $partition] < 0} {
error "clock mapping references unknown partition '$partition'"
}
}
foreach partition $ps_partitions {
set clocks {}
if {[info exists declared_partition_clocks($partition)]} {
unset -nocomplain seen_clock_names seen_port_names
array set seen_clock_names {}
array set seen_port_names {}
foreach mapping $declared_partition_clocks($partition) {
if {[llength $mapping] != 2} {
error "invalid clock mapping for partition '$partition': $mapping"
}
lassign $mapping clock_name port_name
if {$clock_name eq "" || $port_name eq ""} {
error "clock mapping needs a clock and port for partition '$partition': $mapping"
}
if {[info exists seen_clock_names($clock_name)]} {
error "duplicate clock '$clock_name' for partition '$partition'"
}
if {[info exists seen_port_names($port_name)]} {
error "duplicate port '$port_name' for partition '$partition'"
}
set seen_clock_names($clock_name) 1
set seen_port_names($port_name) 1
lappend clocks [list $clock_name $port_name]
}
}
set ps_partition_clocks($partition) $clocks
}
}

proc ps_partition_top {partition} {
global ps_partition_top
return $ps_partition_top($partition)
}

proc ps_partition_blackboxes {partition} {
global ps_partition_blackboxes
if {[info exists ps_partition_blackboxes($partition)]} {
return $ps_partition_blackboxes($partition)
}
return {}
}

proc ps_partition_clocks {partition} {
global ps_partition_clocks
return $ps_partition_clocks($partition)
}

if {[info exists argv0] && [file normalize $argv0] eq [file normalize [info script]]} {
if {[llength $argv] != 1} {
puts "Usage: tclsh defs.tcl partitions"
exit 1
}
ps_load_partitions
switch -- [lindex $argv 0] {
partitions { puts [join $ps_partitions ","] }
default {
puts "Usage: tclsh defs.tcl partitions"
exit 1
}
}
}
Loading