Files
skills-win/rtl-ip-replace/scripts/gen_ip.tcl
T
bowei ea4541ee90 sync: SHANGHAI-U9 2026-07-27 三个 Simulink→RTL skill 转系统级 + 新增 simulink-rtl-redev
- simulink_rtl_dev / rtl-ip-replace: 从工程级 .claude/skills 迁到用户级并去工程耦合
  (模型名/Notes 文档依赖/工程实测基线移出; addpath 与脚本路径改用户级)
- rtl-ip-replace/scripts/gen_cmp_tb.py: Vivado 路径不再写死, 改读 VIVADO_PATH /
  XILINX_VIVADO (兼容 install root / bin / bin\vivado.bat 三种写法), 回落时提示
  去设 skills_env.md 的 VIVADO_PATH
- simulink-rtl-redev: 新增。原生模型改动后的仿真模型同步规范, 含两个实测过的工具
  check_sync.py (三条时序链新鲜度闸门) 与 measure_k.m (时域/频域/包络三估计器互证)
- sim-rtl-flow/SKILL.md: 加入 sync_sim:* 步骤, 引用上述三个 skill
2026-07-27 10:39:53 +08:00

170 lines
9.1 KiB
Tcl

# =============================================================================
# gen_ip.tcl -- create the Vivado IPs listed in rtl_ip/ip_manifest.tcl
# usage: vivado -mode batch -source gen_ip.tcl -tclargs <ip_manifest.tcl> <ip_out_dir> [part]
# Managed-IP style: .xci + synthesis + simulation targets are generated so the
# cores can be (a) added to the synthesis project and (b) compiled for xsim.
# =============================================================================
set manifest [lindex $argv 0]
set ipdir [file normalize [lindex $argv 1]]
set part xc7z100ffg900-2
if {[llength $argv] > 2} { set part [lindex $argv 2] }
file mkdir $ipdir
create_project -in_memory -part $part
set_property target_language Verilog [current_project]
set ips {}
source $manifest ;# fills $ips: list of {type {..} name {..} width {..} depth {..} coe {..} mode {..}}
# manifest field with a default (older manifests do not carry the newer keys)
proc opt {arrname key def} {
upvar 1 $arrname c
if {[info exists c($key)] && $c($key) ne {}} { return $c($key) }
return $def
}
foreach ip $ips {
array unset c; array set c $ip
set name $c(name)
if {[file exists $ipdir/$name/$name.xci]} {
puts "###### SKIP $name (exists)"
continue
}
switch -- $c(type) {
dist_mem_gen {
create_ip -name dist_mem_gen -vendor xilinx.com -library ip -version 8.0 \
-module_name $name -dir $ipdir
set_property -dict [list \
CONFIG.memory_type {rom} \
CONFIG.data_width $c(width) \
CONFIG.depth $c(depth) \
CONFIG.coefficient_file $c(coe) \
] [get_ips $name]
}
blk_mem_gen {
# SDP, common clock, READ_FIRST on the write port, no output register,
# ENA/ENB pins -- matches SimpleDualPortRAM_generic semantics exactly.
create_ip -name blk_mem_gen -vendor xilinx.com -library ip -version 8.4 \
-module_name $name -dir $ipdir
set_property -dict [list \
CONFIG.Memory_Type {Simple_Dual_Port_RAM} \
CONFIG.Assume_Synchronous_Clk {true} \
CONFIG.Use_Byte_Write_Enable {false} \
CONFIG.Write_Width_A $c(width) \
CONFIG.Write_Depth_A $c(depth) \
CONFIG.Read_Width_A $c(width) \
CONFIG.Write_Width_B $c(width) \
CONFIG.Read_Width_B $c(width) \
CONFIG.Operating_Mode_A {READ_FIRST} \
CONFIG.Enable_A {Use_ENA_Pin} \
CONFIG.Enable_B {Use_ENB_Pin} \
CONFIG.Register_PortB_Output_of_Memory_Primitives {false} \
CONFIG.Register_PortB_Output_of_Memory_Core {false} \
] [get_ips $name]
}
fifo_generator {
# guided: mode field carries standard|fwft; depth/width from manifest
create_ip -name fifo_generator -vendor xilinx.com -library ip -version 13.2 \
-module_name $name -dir $ipdir
set rm {Standard_FIFO}
if {[info exists c(mode)] && $c(mode) eq "fwft"} { set rm {First_Word_Fall_Through} }
set_property -dict [list \
CONFIG.Fifo_Implementation {Common_Clock_Block_RAM} \
CONFIG.Performance_Options $rm \
CONFIG.Input_Data_Width $c(width) \
CONFIG.Input_Depth $c(depth) \
CONFIG.Output_Data_Width $c(width) \
CONFIG.Output_Depth $c(depth) \
] [get_ips $name]
}
cordic {
# guided: Arc_Tan phase-seed kernel. Coarse rotation = full-quadrant atan2
# (bidirectional-adjustment principle: better than the FSM's RHP quirk);
# Radians 3QN phase; Truncate rounding; ACLKEN so enb gating stays exact;
# parallel/maximum pipelining -> latency ~input_width+4, well under the
# 64-cycle commit budget.
create_ip -name cordic -vendor xilinx.com -library ip -version 6.0 \
-module_name $name -dir $ipdir
set_property -dict [list \
CONFIG.Functional_Selection {Arc_Tan} \
CONFIG.Input_Width $c(width) \
CONFIG.Output_Width $c(out_width) \
CONFIG.Data_Format {SignedFraction} \
CONFIG.Phase_Format {Radians} \
CONFIG.Coarse_Rotation {true} \
CONFIG.Round_Mode {Truncate} \
CONFIG.ACLKEN {true} \
CONFIG.Pipelining_Mode {Maximum} \
] [get_ips $name]
}
fir_compiler {
# guided (Task12 §六). Cycle-true-critical settings:
# Integer_Coefficients : taps go in as integers, the IP must NOT re-quantise
# Full_Precision output : truncation stays OUTSIDE, done the way the RTL did it
# Input_Sample_Period/1 : one sample per clock, no hardware folding
# -> the latency is a fixed number we can align to
# ACLKEN : gated by enb exactly like the generated RTL
# no TREADY / no input FIFO: pure pipeline, no variable-latency handshake
create_ip -name fir_compiler -vendor xilinx.com -library ip -version 7.2 \
-module_name $name -dir $ipdir
set_property -dict [list \
CONFIG.Filter_Type [opt c filter_type {Single_Rate}] \
CONFIG.CoefficientSource {COE_File} \
CONFIG.Coefficient_File $c(coe) \
CONFIG.Quantization {Integer_Coefficients} \
CONFIG.Coefficient_Width $c(coef_width) \
CONFIG.Coefficient_Fractional_Bits [opt c coef_frac 0] \
CONFIG.Coefficient_Sign {Signed} \
CONFIG.Coefficient_Structure [opt c coef_structure {Inferred}] \
CONFIG.Data_Width $c(width) \
CONFIG.Data_Fractional_Bits [opt c frac 0] \
CONFIG.Data_Sign {Signed} \
CONFIG.Output_Rounding_Mode {Full_Precision} \
CONFIG.RateSpecification {Input_Sample_Period} \
CONFIG.SamplePeriod 1 \
CONFIG.HardwareOversamplingRate 1 \
CONFIG.Interpolation_Rate [opt c interp 1] \
CONFIG.Decimation_Rate [opt c decim 1] \
CONFIG.Zero_Pack_Factor [opt c zero_pack 1] \
CONFIG.Number_Channels [opt c channels 1] \
CONFIG.Number_Paths [opt c paths 1] \
CONFIG.Coefficient_Reload [opt c reload {false}] \
CONFIG.Num_Reload_Slots [opt c reload_slots 1] \
CONFIG.Has_ACLKEN [opt c aclken {true}] \
CONFIG.Has_ARESETn [opt c aresetn {false}] \
CONFIG.M_DATA_Has_TREADY {false} \
CONFIG.S_DATA_Has_FIFO {false} \
] [get_ips $name]
}
cic_compiler {
# guided: only for large integer rate changes (CIC), fixed rate so the
# decimation/interpolation cadence is static and comparable cycle by cycle.
create_ip -name cic_compiler -vendor xilinx.com -library ip -version 4.0 \
-module_name $name -dir $ipdir
set rate [opt c rate 1]
set_property -dict [list \
CONFIG.Filter_Type [opt c filter_type {Decimation}] \
CONFIG.Number_Of_Stages [opt c stages 3] \
CONFIG.Differential_Delay [opt c diff_delay 1] \
CONFIG.Sample_Rate_Changes {Fixed} \
CONFIG.Fixed_Or_Initial_Rate $rate \
CONFIG.Minimum_Rate [opt c min_rate $rate] \
CONFIG.Maximum_Rate [opt c max_rate $rate] \
CONFIG.Input_Data_Width $c(width) \
CONFIG.Quantization {Full_Precision} \
CONFIG.RateSpecification {Sample_Period} \
CONFIG.SamplePeriod 1 \
CONFIG.Number_Of_Channels [opt c channels 1] \
CONFIG.Use_Xtreme_DSP_Slice {false} \
CONFIG.HAS_ACLKEN [opt c aclken {true}] \
CONFIG.HAS_ARESETN [opt c aresetn {false}] \
CONFIG.HAS_DOUT_TREADY {false} \
] [get_ips $name]
}
default { puts "###### UNKNOWN IP TYPE: $c(type) ($name)"; continue }
}
generate_target {instantiation_template synthesis simulation} [get_ips $name]
puts "###### GENERATED $name ($c(type))"
}
puts "###### DONE [llength $ips] ip(s) in $ipdir"