Initial JPEG-LS FPGA encoder baseline with tooling and timeout fix

This commit is contained in:
2026-04-16 18:55:08 +08:00
commit e4fdbdfeec
150 changed files with 25796 additions and 0 deletions

View 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"

View 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

View 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"

View 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"