Initial JPEG-LS FPGA encoder baseline with tooling and timeout fix
This commit is contained in:
139
fpga/synthesis/quick_synth.tcl
Normal file
139
fpga/synthesis/quick_synth.tcl
Normal file
@@ -0,0 +1,139 @@
|
||||
# Quick Vivado synthesis smoke for the JPEG-LS RTL.
|
||||
#
|
||||
# Usage:
|
||||
# vivado -mode batch -source fpga/synthesis/quick_synth.tcl
|
||||
# vivado -mode batch -source fpga/synthesis/quick_synth.tcl -tclargs -part xc7vx690tffg1761-2
|
||||
#
|
||||
# The target part can also be supplied with the JLS_FPGA_PART environment
|
||||
# variable. The default part is provisional and must not be treated as a final
|
||||
# project resource/timing target.
|
||||
|
||||
set script_dir [file dirname [file normalize [info script]]]
|
||||
set repo_root [file normalize [file join $script_dir "../.."]]
|
||||
set report_dir [file normalize [file join $script_dir "quick_synth_reports"]]
|
||||
|
||||
set target_part "xc7vx690tffg1761-2"
|
||||
set clock_period_ns "4.000"
|
||||
set requested_top "all"
|
||||
|
||||
if {[info exists ::env(JLS_FPGA_PART)] && $::env(JLS_FPGA_PART) ne ""} {
|
||||
set target_part $::env(JLS_FPGA_PART)
|
||||
}
|
||||
|
||||
set arg_index 0
|
||||
while {$arg_index < [llength $argv]} {
|
||||
set arg_key [lindex $argv $arg_index]
|
||||
incr arg_index
|
||||
if {$arg_index >= [llength $argv]} {
|
||||
puts "ERROR: missing value for $arg_key"
|
||||
exit 1
|
||||
}
|
||||
|
||||
set arg_value [lindex $argv $arg_index]
|
||||
incr arg_index
|
||||
|
||||
switch -- $arg_key {
|
||||
"-part" {
|
||||
set target_part $arg_value
|
||||
}
|
||||
"-clock_period" {
|
||||
set clock_period_ns $arg_value
|
||||
}
|
||||
"-top" {
|
||||
set requested_top $arg_value
|
||||
}
|
||||
default {
|
||||
puts "ERROR: unknown argument $arg_key"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set rtl_filelist_path [file join $repo_root "fpga/verilog/jpeg_ls_rtl.f"]
|
||||
set rtl_files [list]
|
||||
set rtl_fd [open $rtl_filelist_path "r"]
|
||||
while {[gets $rtl_fd rtl_line] >= 0} {
|
||||
set rtl_line [string trim $rtl_line]
|
||||
if {$rtl_line eq ""} {
|
||||
continue
|
||||
}
|
||||
if {[string match "#*" $rtl_line]} {
|
||||
continue
|
||||
}
|
||||
|
||||
if {[file pathtype $rtl_line] eq "absolute"} {
|
||||
lappend rtl_files [file normalize $rtl_line]
|
||||
} else {
|
||||
lappend rtl_files [file normalize [file join $repo_root $rtl_line]]
|
||||
}
|
||||
}
|
||||
close $rtl_fd
|
||||
|
||||
set all_tops [list \
|
||||
"jpeg_ls_encoder_top" \
|
||||
"jls_input_ctrl" \
|
||||
"jls_preset_defaults" \
|
||||
"jls_header_writer" \
|
||||
"jls_near_ctrl" \
|
||||
]
|
||||
|
||||
if {$requested_top eq "all"} {
|
||||
set top_list $all_tops
|
||||
} else {
|
||||
set top_list [list $requested_top]
|
||||
}
|
||||
|
||||
file mkdir $report_dir
|
||||
|
||||
set summary_path [file join $report_dir "quick_synth_summary.csv"]
|
||||
set summary_fd [open $summary_path "w"]
|
||||
puts $summary_fd "top,part,clock_period_ns,wns_ns,clock_ports,report_dir"
|
||||
|
||||
puts "INFO: JPEG-LS quick synthesis"
|
||||
puts "INFO: repo_root = $repo_root"
|
||||
puts "INFO: report_dir = $report_dir"
|
||||
puts "INFO: target_part = $target_part"
|
||||
puts "INFO: clock_period_ns = $clock_period_ns"
|
||||
puts "INFO: rtl_filelist = $rtl_filelist_path"
|
||||
puts "INFO: rtl_file_count = [llength $rtl_files]"
|
||||
puts "INFO: top_list = $top_list"
|
||||
|
||||
foreach top_name $top_list {
|
||||
puts "INFO: quick synth top $top_name"
|
||||
|
||||
create_project -in_memory -part $target_part
|
||||
set_property target_language Verilog [current_project]
|
||||
|
||||
read_verilog -sv $rtl_files
|
||||
synth_design -top $top_name -part $target_part -mode out_of_context -flatten_hierarchy rebuilt
|
||||
|
||||
set clock_ports [get_ports -quiet clk]
|
||||
set clock_count [llength $clock_ports]
|
||||
if {$clock_count > 0} {
|
||||
create_clock -name clk -period $clock_period_ns $clock_ports
|
||||
}
|
||||
|
||||
set util_path [file join $report_dir "${top_name}_utilization.rpt"]
|
||||
set timing_path [file join $report_dir "${top_name}_timing_summary.rpt"]
|
||||
set clock_path [file join $report_dir "${top_name}_clock_utilization.rpt"]
|
||||
set dcp_path [file join $report_dir "${top_name}.dcp"]
|
||||
|
||||
report_utilization -file $util_path
|
||||
report_timing_summary -file $timing_path -delay_type max -max_paths 10
|
||||
if {$clock_count > 0} {
|
||||
report_clock_utilization -file $clock_path
|
||||
}
|
||||
write_checkpoint -force $dcp_path
|
||||
|
||||
set wns_value "NA"
|
||||
set timing_paths [get_timing_paths -quiet -max_paths 1]
|
||||
if {[llength $timing_paths] > 0} {
|
||||
set wns_value [get_property SLACK [lindex $timing_paths 0]]
|
||||
}
|
||||
|
||||
puts $summary_fd "$top_name,$target_part,$clock_period_ns,$wns_value,$clock_count,$report_dir"
|
||||
close_project
|
||||
}
|
||||
|
||||
close $summary_fd
|
||||
puts "INFO: quick synthesis summary: $summary_path"
|
||||
108
fpga/synthesis/report_timing_violations.tcl
Normal file
108
fpga/synthesis/report_timing_violations.tcl
Normal file
@@ -0,0 +1,108 @@
|
||||
# Detailed timing-violation extractor for JPEG-LS quick synthesis checkpoints.
|
||||
#
|
||||
# Usage:
|
||||
# vivado -mode batch -source fpga/synthesis/report_timing_violations.tcl
|
||||
# vivado -mode batch -source fpga/synthesis/report_timing_violations.tcl \
|
||||
# -tclargs -top jpeg_ls_encoder_top -max_paths 5000
|
||||
|
||||
set script_dir [file dirname [file normalize [info script]]]
|
||||
set repo_root [file normalize [file join $script_dir "../.."]]
|
||||
set report_dir [file normalize [file join $script_dir "quick_synth_reports"]]
|
||||
|
||||
set requested_top "jpeg_ls_encoder_top"
|
||||
set max_paths 5000
|
||||
set slack_limit 0.000
|
||||
|
||||
set arg_index 0
|
||||
while {$arg_index < [llength $argv]} {
|
||||
set arg_key [lindex $argv $arg_index]
|
||||
incr arg_index
|
||||
if {$arg_index >= [llength $argv]} {
|
||||
puts "ERROR: missing value for $arg_key"
|
||||
exit 1
|
||||
}
|
||||
|
||||
set arg_value [lindex $argv $arg_index]
|
||||
incr arg_index
|
||||
|
||||
switch -- $arg_key {
|
||||
"-top" {
|
||||
set requested_top $arg_value
|
||||
}
|
||||
"-max_paths" {
|
||||
set max_paths $arg_value
|
||||
}
|
||||
"-slack_lesser_than" {
|
||||
set slack_limit $arg_value
|
||||
}
|
||||
default {
|
||||
puts "ERROR: unknown argument $arg_key"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set dcp_path [file join $report_dir "${requested_top}.dcp"]
|
||||
if {![file exists $dcp_path]} {
|
||||
puts "ERROR: checkpoint not found: $dcp_path"
|
||||
exit 1
|
||||
}
|
||||
|
||||
open_checkpoint $dcp_path
|
||||
|
||||
set detail_path [file join $report_dir "${requested_top}_timing_violations_all.rpt"]
|
||||
set csv_path [file join $report_dir "${requested_top}_timing_violations_summary.csv"]
|
||||
set non_dsp_csv_path [file join $report_dir "${requested_top}_timing_violations_non_dsp_logic_gt1.csv"]
|
||||
|
||||
report_timing \
|
||||
-delay_type max \
|
||||
-slack_lesser_than $slack_limit \
|
||||
-max_paths $max_paths \
|
||||
-sort_by slack \
|
||||
-file $detail_path
|
||||
|
||||
set paths [get_timing_paths \
|
||||
-delay_type max \
|
||||
-slack_lesser_than $slack_limit \
|
||||
-max_paths $max_paths \
|
||||
-sort_by slack]
|
||||
|
||||
set csv_fd [open $csv_path "w"]
|
||||
set non_dsp_fd [open $non_dsp_csv_path "w"]
|
||||
puts $csv_fd "index,slack_ns,logic_levels,has_dsp,source,destination"
|
||||
puts $non_dsp_fd "index,slack_ns,logic_levels,source,destination"
|
||||
|
||||
set index 0
|
||||
set non_dsp_index 0
|
||||
foreach path $paths {
|
||||
incr index
|
||||
|
||||
set slack [get_property SLACK $path]
|
||||
set source [get_property STARTPOINT_PIN $path]
|
||||
set destination [get_property ENDPOINT_PIN $path]
|
||||
set logic_levels [get_property LOGIC_LEVELS $path]
|
||||
|
||||
set path_report [report_timing -of_objects $path -return_string]
|
||||
set has_dsp 0
|
||||
if {[string first "DSP48" $path_report] >= 0} {
|
||||
set has_dsp 1
|
||||
}
|
||||
|
||||
puts $csv_fd "$index,$slack,$logic_levels,$has_dsp,\"$source\",\"$destination\""
|
||||
|
||||
if {$has_dsp == 0 && $logic_levels > 1} {
|
||||
incr non_dsp_index
|
||||
puts $non_dsp_fd "$index,$slack,$logic_levels,\"$source\",\"$destination\""
|
||||
}
|
||||
}
|
||||
|
||||
close $csv_fd
|
||||
close $non_dsp_fd
|
||||
|
||||
puts "INFO: timing violation detail report: $detail_path"
|
||||
puts "INFO: timing violation CSV: $csv_path"
|
||||
puts "INFO: non-DSP logic-level>1 CSV: $non_dsp_csv_path"
|
||||
puts "INFO: violating path count exported: $index"
|
||||
puts "INFO: non-DSP logic-level>1 path count exported: $non_dsp_index"
|
||||
|
||||
close_design
|
||||
31
fpga/synthesis/run_quick_synth.ps1
Normal file
31
fpga/synthesis/run_quick_synth.ps1
Normal file
@@ -0,0 +1,31 @@
|
||||
param(
|
||||
# Vivado target FPGA part.
|
||||
[string] $Part = $(if ($env:JLS_FPGA_PART) { $env:JLS_FPGA_PART } else { "xc7vx690tffg1761-2" }),
|
||||
|
||||
# Timing target for the main clk port, in ns. 4.000 ns corresponds to 250 MHz.
|
||||
[string] $ClockPeriod = "4.000",
|
||||
|
||||
# RTL top module to synthesize. The default synthesizes all current standalone tops.
|
||||
[string] $Top = "all",
|
||||
|
||||
# Vivado batch launcher. Override if Vivado is installed elsewhere.
|
||||
[string] $VivadoBat = $(if ($env:VIVADO_BAT) { $env:VIVADO_BAT } else { "C:\Xilinx\Vivado\2023.2\bin\vivado.bat" })
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
if (!(Test-Path -LiteralPath $VivadoBat)) {
|
||||
Write-Error "Vivado launcher not found: $VivadoBat. Set VIVADO_BAT or pass -VivadoBat."
|
||||
}
|
||||
|
||||
Write-Host "[jls-quick-synth] Vivado: $VivadoBat"
|
||||
Write-Host "[jls-quick-synth] Part: $Part"
|
||||
Write-Host "[jls-quick-synth] Clock period: $ClockPeriod ns"
|
||||
Write-Host "[jls-quick-synth] Top: $Top"
|
||||
|
||||
& $VivadoBat -mode batch -source fpga/synthesis/quick_synth.tcl -tclargs -part $Part -clock_period $ClockPeriod -top $Top
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Host "[jls-quick-synth] PASS"
|
||||
121
fpga/synthesis/timing_priority_synth.tcl
Normal file
121
fpga/synthesis/timing_priority_synth.tcl
Normal file
@@ -0,0 +1,121 @@
|
||||
# Timing-priority Vivado synthesis for the JPEG-LS RTL.
|
||||
#
|
||||
# Usage:
|
||||
# vivado -mode batch -source fpga/synthesis/timing_priority_synth.tcl
|
||||
# vivado -mode batch -source fpga/synthesis/timing_priority_synth.tcl -tclargs -top jpeg_ls_encoder_top
|
||||
# vivado -mode batch -source fpga/synthesis/timing_priority_synth.tcl -tclargs -directive PerformanceOptimized
|
||||
|
||||
set script_dir [file dirname [file normalize [info script]]]
|
||||
set repo_root [file normalize [file join $script_dir "../.."]]
|
||||
set report_dir [file normalize [file join $script_dir "timing_priority_reports"]]
|
||||
|
||||
set target_part "xc7vx690tffg1761-2"
|
||||
set clock_period_ns "4.000"
|
||||
set requested_top "jpeg_ls_encoder_top"
|
||||
set synth_directive "PerformanceOptimized"
|
||||
|
||||
if {[info exists ::env(JLS_FPGA_PART)] && $::env(JLS_FPGA_PART) ne ""} {
|
||||
set target_part $::env(JLS_FPGA_PART)
|
||||
}
|
||||
|
||||
set arg_index 0
|
||||
while {$arg_index < [llength $argv]} {
|
||||
set arg_key [lindex $argv $arg_index]
|
||||
incr arg_index
|
||||
if {$arg_index >= [llength $argv]} {
|
||||
puts "ERROR: missing value for $arg_key"
|
||||
exit 1
|
||||
}
|
||||
|
||||
set arg_value [lindex $argv $arg_index]
|
||||
incr arg_index
|
||||
|
||||
switch -- $arg_key {
|
||||
"-part" {
|
||||
set target_part $arg_value
|
||||
}
|
||||
"-clock_period" {
|
||||
set clock_period_ns $arg_value
|
||||
}
|
||||
"-top" {
|
||||
set requested_top $arg_value
|
||||
}
|
||||
"-directive" {
|
||||
set synth_directive $arg_value
|
||||
}
|
||||
default {
|
||||
puts "ERROR: unknown argument $arg_key"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set rtl_filelist_path [file join $repo_root "fpga/verilog/jpeg_ls_rtl.f"]
|
||||
set rtl_files [list]
|
||||
set rtl_fd [open $rtl_filelist_path "r"]
|
||||
while {[gets $rtl_fd rtl_line] >= 0} {
|
||||
set rtl_line [string trim $rtl_line]
|
||||
if {$rtl_line eq ""} {
|
||||
continue
|
||||
}
|
||||
if {[string match "#*" $rtl_line]} {
|
||||
continue
|
||||
}
|
||||
|
||||
if {[file pathtype $rtl_line] eq "absolute"} {
|
||||
lappend rtl_files [file normalize $rtl_line]
|
||||
} else {
|
||||
lappend rtl_files [file normalize [file join $repo_root $rtl_line]]
|
||||
}
|
||||
}
|
||||
close $rtl_fd
|
||||
|
||||
file mkdir $report_dir
|
||||
|
||||
set summary_path [file join $report_dir "timing_priority_summary.csv"]
|
||||
set summary_fd [open $summary_path "w"]
|
||||
puts $summary_fd "top,part,clock_period_ns,directive,wns_ns,clock_ports,report_dir"
|
||||
|
||||
puts "INFO: JPEG-LS timing-priority synthesis"
|
||||
puts "INFO: repo_root = $repo_root"
|
||||
puts "INFO: report_dir = $report_dir"
|
||||
puts "INFO: target_part = $target_part"
|
||||
puts "INFO: clock_period_ns = $clock_period_ns"
|
||||
puts "INFO: synth_directive = $synth_directive"
|
||||
puts "INFO: rtl_filelist = $rtl_filelist_path"
|
||||
puts "INFO: rtl_file_count = [llength $rtl_files]"
|
||||
puts "INFO: top = $requested_top"
|
||||
|
||||
create_project -in_memory -part $target_part
|
||||
set_property target_language Verilog [current_project]
|
||||
|
||||
read_verilog -sv $rtl_files
|
||||
synth_design -top $requested_top -part $target_part -mode out_of_context -flatten_hierarchy rebuilt -directive $synth_directive
|
||||
|
||||
set clock_ports [get_ports -quiet clk]
|
||||
set clock_count [llength $clock_ports]
|
||||
if {$clock_count > 0} {
|
||||
create_clock -name clk -period $clock_period_ns $clock_ports
|
||||
}
|
||||
|
||||
set util_path [file join $report_dir "${requested_top}_utilization.rpt"]
|
||||
set timing_path [file join $report_dir "${requested_top}_timing_summary.rpt"]
|
||||
set clock_path [file join $report_dir "${requested_top}_clock_utilization.rpt"]
|
||||
set dcp_path [file join $report_dir "${requested_top}.dcp"]
|
||||
|
||||
report_utilization -file $util_path
|
||||
report_timing_summary -file $timing_path -delay_type max -max_paths 10
|
||||
if {$clock_count > 0} {
|
||||
report_clock_utilization -file $clock_path
|
||||
}
|
||||
write_checkpoint -force $dcp_path
|
||||
|
||||
set wns_value "NA"
|
||||
set timing_paths [get_timing_paths -quiet -max_paths 1]
|
||||
if {[llength $timing_paths] > 0} {
|
||||
set wns_value [get_property SLACK [lindex $timing_paths 0]]
|
||||
}
|
||||
|
||||
puts $summary_fd "$requested_top,$target_part,$clock_period_ns,$synth_directive,$wns_value,$clock_count,$report_dir"
|
||||
close $summary_fd
|
||||
puts "INFO: timing-priority synthesis summary: $summary_path"
|
||||
Reference in New Issue
Block a user