Files
zynq7000-rs/tools/zynq7000-ps7init-extract/src/main.rs
Robin Mueller bd143ba51d
Some checks failed
ci / Check build (push) Has been cancelled
ci / Check formatting (push) Has been cancelled
ci / Check Documentation Build (push) Has been cancelled
ci / Clippy (push) Has been cancelled
ci / Check build (pull_request) Has been cancelled
ci / Check formatting (pull_request) Has been cancelled
ci / Check Documentation Build (pull_request) Has been cancelled
ci / Clippy (pull_request) Has been cancelled
finish auto-generation effort
2025-10-08 19:01:15 +02:00

342 lines
18 KiB
Rust

use std::{collections::HashMap, ops::RangeInclusive, path::Path};
use clap::Parser as _;
use simple_logger::SimpleLogger;
const DDRC_ADDR_RANGE: RangeInclusive<u32> = 0xf800_6000..=0xf800_62b4;
const DDRIOB_ADDR_RANGE: RangeInclusive<u32> = 0xf800_0b40..=0xf800_0b68;
const DDRC_FILE_NAME: &str = "ddrc_config_autogen.rs";
const DDRIOB_FILE_NAME: &str = "ddriob_config_autogen.rs";
#[derive(clap::Parser, Debug)]
#[command(version, about)]
pub struct Cli {
/// Path to ps7init.tcl file.
#[arg(short, long)]
path: String,
}
fn extract_hex_values(line: &str) -> Option<(u32, u32, u32)> {
let re = regex::Regex::new(r"0[xX]([0-9A-Fa-f]+)").unwrap();
let captures: Vec<u32> = re
.captures_iter(line)
.filter_map(|cap| u32::from_str_radix(&cap[1], 16).ok())
.collect();
if captures.len() == 3 {
Some((captures[0], captures[1], captures[2]))
} else {
None
}
}
#[derive(Default)]
pub struct RegisterToValueMap(pub HashMap<u32, u32>);
impl RegisterToValueMap {
fn val_as_token(&self, reg_name: &str, addr: u32) -> proc_macro2::TokenStream {
let val = self.0.get(&addr).unwrap_or_else(|| {
panic!(
"failed to retrieve register value for register {}",
reg_name
)
});
format!("{:#010x}", val)
.parse::<proc_macro2::TokenStream>()
.unwrap()
}
}
enum ParsingMode {
DdrRev3,
MioRev3,
}
fn main() -> std::io::Result<()> {
SimpleLogger::new().init().unwrap();
let cli = Cli::parse();
let ps7init_tcl = Path::new(&cli.path);
if !ps7init_tcl.exists() {
log::error!("File not found: {}", ps7init_tcl.display());
std::process::exit(1);
}
let mut parsing_mode = None;
let mut reg_to_values = RegisterToValueMap::default();
for line in std::fs::read_to_string(ps7init_tcl)?.lines() {
match parsing_mode {
None => {
if line.contains("ps7_ddr_init_data_3_0") {
parsing_mode = Some(ParsingMode::DdrRev3);
} else if line.contains("ps7_mio_init_data_3_0") {
parsing_mode = Some(ParsingMode::MioRev3);
}
continue;
}
Some(ParsingMode::MioRev3) => {
if line.contains("}") {
parsing_mode = None;
continue;
}
}
Some(ParsingMode::DdrRev3) => {
if line.contains("}") {
parsing_mode = None;
continue;
}
}
}
if let Some((addr, _mask, value)) = extract_hex_values(line)
&& (DDRC_ADDR_RANGE.contains(&addr) || DDRIOB_ADDR_RANGE.contains(&addr))
&& addr % 4 == 0
{
// Only use first value.
if reg_to_values.0.contains_key(&addr) {
if addr != 0xF800_6000 {
log::warn!("detected duplicate register value for address {}", addr);
}
continue;
}
reg_to_values.0.insert(addr, value);
}
}
log::info!("generating DDRC config files: {}", DDRC_FILE_NAME);
generate_ddrc_config(&reg_to_values, DDRC_FILE_NAME)?;
log::info!("generating DDRIOB config files: {}", DDRIOB_FILE_NAME);
generate_ddriob_config(&reg_to_values, DDRIOB_FILE_NAME)?;
Ok(())
}
fn generate_ddrc_config(
reg_to_values: &RegisterToValueMap,
file_name: &str,
) -> std::io::Result<()> {
// Format as hex strings
let ddrc = reg_to_values.val_as_token("DDRC Control", 0xF800_6000);
let two_rank = reg_to_values.val_as_token("Two Rank", 0xF800_6004);
let hpr = reg_to_values.val_as_token("HPR", 0xF800_6008);
let lpr = reg_to_values.val_as_token("LPR", 0xF800_600C);
let wr = reg_to_values.val_as_token("WR", 0xF800_6010);
let dram_param_0 = reg_to_values.val_as_token("DRAM Reg0", 0xF800_6014);
let dram_param_1 = reg_to_values.val_as_token("DRAM Reg1", 0xF800_6018);
let dram_param_2 = reg_to_values.val_as_token("DRAM Reg2", 0xF800_601C);
let dram_param_3 = reg_to_values.val_as_token("DRAM Reg3", 0xF800_6020);
let dram_param_4 = reg_to_values.val_as_token("DRAM Reg4", 0xF800_6024);
let dram_init_param = reg_to_values.val_as_token("DRAM Init Param", 0xF800_6028);
let dram_emr = reg_to_values.val_as_token("DRAM EMR", 0xF800_602C);
let dram_emr_mr = reg_to_values.val_as_token("DRAM EMR MR", 0xF800_6030);
let dram_burst8_rdwr = reg_to_values.val_as_token("DRAM Burst8 RDWR", 0xF800_6034);
let dram_disable_dq = reg_to_values.val_as_token("DRAM Disable DQ", 0xF800_6038);
let dram_addr_map_bank = reg_to_values.val_as_token("DRAM Addr Map Bank", 0xF800_603C);
let dram_addr_map_col = reg_to_values.val_as_token("DRAM Addr Map Col", 0xF800_6040);
let dram_addr_map_row = reg_to_values.val_as_token("DRAM Addr Map Row", 0xF800_6044);
let dram_odt = reg_to_values.val_as_token("DRAM ODT", 0xF800_6048);
let phy_cmd_timeout_rddata_cpt = reg_to_values.val_as_token("PHY CMD Timeout", 0xF800_6050);
let dll_calib = reg_to_values.val_as_token("DLL Calib", 0xF800_6058);
let odt_delay_hold = reg_to_values.val_as_token("ODT Delay Hold", 0xF800_605C);
let ctrl_reg1 = reg_to_values.val_as_token("CTRL Reg 1", 0xF800_6060);
let ctrl_reg2 = reg_to_values.val_as_token("CTRL Reg 2", 0xF800_6064);
let ctrl_reg3 = reg_to_values.val_as_token("CTRL Reg 3", 0xF800_6068);
let ctrl_reg4 = reg_to_values.val_as_token("CTRL Reg 4", 0xF800_606C);
let ctrl_reg5 = reg_to_values.val_as_token("CTRL Reg 5", 0xF800_6078);
let ctrl_reg6 = reg_to_values.val_as_token("CTRL Reg 6", 0xF800_607C);
let che_t_zq = reg_to_values.val_as_token("CHE T ZQ", 0xF800_60A4);
let che_t_zq_short_interval_reg =
reg_to_values.val_as_token("CHE T ZQ Short Interval", 0xF800_60A4);
let deep_powerdown = reg_to_values.val_as_token("Deep Powerdown", 0xF800_60AC);
let reg_2c = reg_to_values.val_as_token("Reg 2C", 0xF800_60B0);
let reg_2d = reg_to_values.val_as_token("Reg 2D", 0xF800_60B4);
let dfi_timing = reg_to_values.val_as_token("DFI Timing", 0xF800_60B8);
let che_ecc_ctrl = reg_to_values.val_as_token("CHE ECC CTRL", 0xF800_60C4);
let ecc_scrub = reg_to_values.val_as_token("ECC Scrub", 0xF800_60F4);
let phy_receiver_enable = reg_to_values.val_as_token("PHY Receiver Enable", 0xF800_6114);
let phy_config_0 = reg_to_values.val_as_token("PHY Config 0", 0xF800_6118);
let phy_config_1 = reg_to_values.val_as_token("PHY Config 1", 0xF800_611C);
let phy_config_2 = reg_to_values.val_as_token("PHY Config 2", 0xF800_6120);
let phy_config_3 = reg_to_values.val_as_token("PHY Config 3", 0xF800_6124);
let phy_init_ratio_0 = reg_to_values.val_as_token("PHY Init Ratio 0", 0xF800_612C);
let phy_init_ratio_1 = reg_to_values.val_as_token("PHY Init Ratio 1", 0xF800_6130);
let phy_init_ratio_2 = reg_to_values.val_as_token("PHY Init Ratio 2", 0xF800_6134);
let phy_init_ratio_3 = reg_to_values.val_as_token("PHY Init Ratio 3", 0xF800_6138);
let phy_rd_dqs_config_0 = reg_to_values.val_as_token("PHY RD DQS Config 0", 0xF800_6140);
let phy_rd_dqs_config_1 = reg_to_values.val_as_token("PHY RD DQS Config 1", 0xF800_6144);
let phy_rd_dqs_config_2 = reg_to_values.val_as_token("PHY RD DQS Config 2", 0xF800_6148);
let phy_rd_dqs_config_3 = reg_to_values.val_as_token("PHY RD DQS Config 3", 0xF800_614C);
let phy_wr_dqs_config_0 = reg_to_values.val_as_token("PHY WR DQS Config 0", 0xF800_6154);
let phy_wr_dqs_config_1 = reg_to_values.val_as_token("PHY WR DQS Config 1", 0xF800_6158);
let phy_wr_dqs_config_2 = reg_to_values.val_as_token("PHY WR DQS Config 2", 0xF800_615C);
let phy_wr_dqs_config_3 = reg_to_values.val_as_token("PHY WR DQS Config 3", 0xF800_6160);
let phy_we_cfg_0 = reg_to_values.val_as_token("PHY WE Config 0", 0xF800_6168);
let phy_we_cfg_1 = reg_to_values.val_as_token("PHY WE Config 1", 0xF800_616C);
let phy_we_cfg_2 = reg_to_values.val_as_token("PHY WE Config 2", 0xF800_6170);
let phy_we_cfg_3 = reg_to_values.val_as_token("PHY WE Config 3", 0xF800_6174);
let phy_wr_data_slv_0 = reg_to_values.val_as_token("PHY WR Data Slv 0", 0xF800_617C);
let phy_wr_data_slv_1 = reg_to_values.val_as_token("PHY WR Data Slv 1", 0xF800_6180);
let phy_wr_data_slv_2 = reg_to_values.val_as_token("PHY WR Data Slv 2", 0xF800_6184);
let phy_wr_data_slv_3 = reg_to_values.val_as_token("PHY WR Data Slv 3", 0xF800_6188);
let reg64 = reg_to_values.val_as_token("Reg64", 0xF800_6190);
let reg65 = reg_to_values.val_as_token("Reg65", 0xF800_6194);
let page_mask = reg_to_values.val_as_token("Page Mask", 0xF800_6204);
let axi_priority_wr_port_0 = reg_to_values.val_as_token("AXI Priority WR Port 0", 0xF800_6208);
let axi_priority_wr_port_1 = reg_to_values.val_as_token("AXI Priority WR Port 1", 0xF800_620C);
let axi_priority_wr_port_2 = reg_to_values.val_as_token("AXI Priority WR Port 2", 0xF800_6210);
let axi_priority_wr_port_3 = reg_to_values.val_as_token("AXI Priority WR Port 3", 0xF800_6214);
let axi_priority_rd_port_0 = reg_to_values.val_as_token("AXI Priority RD Port 0", 0xF800_6218);
let axi_priority_rd_port_1 = reg_to_values.val_as_token("AXI Priority RD Port 1", 0xF800_621C);
let axi_priority_rd_port_2 = reg_to_values.val_as_token("AXI Priority RD Port 2", 0xF800_6220);
let axi_priority_rd_port_3 = reg_to_values.val_as_token("AXI Priority RD Port 3", 0xF800_6224);
let lpddr_ctrl_0 = reg_to_values.val_as_token("LPDDR CTRL 0", 0xF800_62A8);
let lpddr_ctrl_1 = reg_to_values.val_as_token("LPDDR CTRL 1", 0xF800_62AC);
let lpddr_ctrl_2 = reg_to_values.val_as_token("LPDDR CTRL 2", 0xF800_62B0);
let lpddr_ctrl_3 = reg_to_values.val_as_token("LPDDR CTRL 3", 0xF800_62B4);
let generated = quote::quote! {
//!This file was auto-generated by the [zynq7000-ps7init-extract](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/tools/zynq7000-ps7init-extract) program.
//!
//!This configuration file contains static DDR configuration parameters extracted from the
//!AMD ps7init.tcl file
use zynq7000::ddrc::regs;
use zynq7000_hal::ddr::DdrcConfigSet;
pub const DDRC_CONFIG_ZEDBOARD: DdrcConfigSet = DdrcConfigSet {
ctrl: regs::DdrcControl::new_with_raw_value(#ddrc),
two_rank: regs::TwoRankConfig::new_with_raw_value(#two_rank),
hpr: regs::LprHprQueueControl::new_with_raw_value(#hpr),
lpr: regs::LprHprQueueControl::new_with_raw_value(#lpr),
wr: regs::WriteQueueControl::new_with_raw_value(#wr),
dram_param_0: regs::DramParamReg0::new_with_raw_value(#dram_param_0),
dram_param_1: regs::DramParamReg1::new_with_raw_value(#dram_param_1),
dram_param_2: regs::DramParamReg2::new_with_raw_value(#dram_param_2),
dram_param_3: regs::DramParamReg3::new_with_raw_value(#dram_param_3),
dram_param_4: regs::DramParamReg4::new_with_raw_value(#dram_param_4),
dram_init_param: regs::DramInitParam::new_with_raw_value(#dram_init_param),
dram_emr: regs::DramEmr::new_with_raw_value(#dram_emr),
dram_emr_mr: regs::DramEmrMr::new_with_raw_value(#dram_emr_mr),
dram_burst8_rdwr: regs::DramBurst8ReadWrite::new_with_raw_value(#dram_burst8_rdwr),
disable_dq: regs::DisableDq::new_with_raw_value(#dram_disable_dq),
dram_addr_map_bank: regs::DramAddrMapBank::new_with_raw_value(#dram_addr_map_bank),
dram_addr_map_col: regs::DramAddrMapColumn::new_with_raw_value(#dram_addr_map_col),
dram_addr_map_row: regs::DramAddrMapRow::new_with_raw_value(#dram_addr_map_row),
dram_odt: regs::DramOdt::new_with_raw_value(#dram_odt),
phy_cmd_timeout_rddata_cpt: regs::PhyCmdTimeoutRdDataCpt::new_with_raw_value(#phy_cmd_timeout_rddata_cpt),
dll_calib: regs::DllCalib::new_with_raw_value(#dll_calib),
odt_delay_hold: regs::OdtDelayHold::new_with_raw_value(#odt_delay_hold),
ctrl_reg1: regs::CtrlReg1::new_with_raw_value(#ctrl_reg1),
ctrl_reg2: regs::CtrlReg2::new_with_raw_value(#ctrl_reg2),
ctrl_reg3: regs::CtrlReg3::new_with_raw_value(#ctrl_reg3),
ctrl_reg4: regs::CtrlReg4::new_with_raw_value(#ctrl_reg4),
ctrl_reg5: regs::CtrlReg5::new_with_raw_value(#ctrl_reg5),
ctrl_reg6: regs::CtrlReg6::new_with_raw_value(#ctrl_reg6),
che_t_zq: regs::CheTZq::new_with_raw_value(#che_t_zq),
che_t_zq_short_interval_reg: regs::CheTZqShortInterval::new_with_raw_value(#che_t_zq_short_interval_reg),
deep_powerdown: regs::DeepPowerdown::new_with_raw_value(#deep_powerdown),
reg_2c: regs::Reg2c::new_with_raw_value(#reg_2c),
reg_2d: regs::Reg2d::new_with_raw_value(#reg_2d),
dfi_timing: regs::DfiTiming::new_with_raw_value(#dfi_timing),
che_ecc_ctrl: regs::CheEccControl::new_with_raw_value(#che_ecc_ctrl),
ecc_scrub: regs::EccScrub::new_with_raw_value(#ecc_scrub),
phy_receiver_enable: regs::PhyReceiverEnable::new_with_raw_value(#phy_receiver_enable),
phy_config: [
regs::PhyConfig::new_with_raw_value(#phy_config_0),
regs::PhyConfig::new_with_raw_value(#phy_config_1),
regs::PhyConfig::new_with_raw_value(#phy_config_2),
regs::PhyConfig::new_with_raw_value(#phy_config_3),
],
phy_init_ratio: [
regs::PhyInitRatio::new_with_raw_value(#phy_init_ratio_0),
regs::PhyInitRatio::new_with_raw_value(#phy_init_ratio_1),
regs::PhyInitRatio::new_with_raw_value(#phy_init_ratio_2),
regs::PhyInitRatio::new_with_raw_value(#phy_init_ratio_3),
],
phy_rd_dqs_config: [
regs::PhyDqsConfig::new_with_raw_value(#phy_rd_dqs_config_0),
regs::PhyDqsConfig::new_with_raw_value(#phy_rd_dqs_config_1),
regs::PhyDqsConfig::new_with_raw_value(#phy_rd_dqs_config_2),
regs::PhyDqsConfig::new_with_raw_value(#phy_rd_dqs_config_3),
],
phy_wr_dqs_config: [
regs::PhyDqsConfig::new_with_raw_value(#phy_wr_dqs_config_0),
regs::PhyDqsConfig::new_with_raw_value(#phy_wr_dqs_config_1),
regs::PhyDqsConfig::new_with_raw_value(#phy_wr_dqs_config_2),
regs::PhyDqsConfig::new_with_raw_value(#phy_wr_dqs_config_3),
],
phy_we_cfg: [
regs::PhyWriteEnableConfig::new_with_raw_value(#phy_we_cfg_0),
regs::PhyWriteEnableConfig::new_with_raw_value(#phy_we_cfg_1),
regs::PhyWriteEnableConfig::new_with_raw_value(#phy_we_cfg_2),
regs::PhyWriteEnableConfig::new_with_raw_value(#phy_we_cfg_3),
],
phy_wr_data_slv: [
regs::PhyWriteDataSlaveConfig::new_with_raw_value(#phy_wr_data_slv_0),
regs::PhyWriteDataSlaveConfig::new_with_raw_value(#phy_wr_data_slv_1),
regs::PhyWriteDataSlaveConfig::new_with_raw_value(#phy_wr_data_slv_2),
regs::PhyWriteDataSlaveConfig::new_with_raw_value(#phy_wr_data_slv_3),
],
reg64: regs::Reg64::new_with_raw_value(#reg64),
reg65: regs::Reg65::new_with_raw_value(#reg65),
page_mask: #page_mask,
axi_priority_wr_port: [
regs::AxiPriorityWritePort::new_with_raw_value(#axi_priority_wr_port_0),
regs::AxiPriorityWritePort::new_with_raw_value(#axi_priority_wr_port_1),
regs::AxiPriorityWritePort::new_with_raw_value(#axi_priority_wr_port_2),
regs::AxiPriorityWritePort::new_with_raw_value(#axi_priority_wr_port_3),
],
axi_priority_rd_port: [
regs::AxiPriorityReadPort::new_with_raw_value(#axi_priority_rd_port_0),
regs::AxiPriorityReadPort::new_with_raw_value(#axi_priority_rd_port_1),
regs::AxiPriorityReadPort::new_with_raw_value(#axi_priority_rd_port_2),
regs::AxiPriorityReadPort::new_with_raw_value(#axi_priority_rd_port_3),
],
lpddr_ctrl_0: regs::LpddrControl0::new_with_raw_value(#lpddr_ctrl_0),
lpddr_ctrl_1: regs::LpddrControl1::new_with_raw_value(#lpddr_ctrl_1),
lpddr_ctrl_2: regs::LpddrControl2::new_with_raw_value(#lpddr_ctrl_2),
lpddr_ctrl_3: regs::LpddrControl3::new_with_raw_value(#lpddr_ctrl_3),
};
};
std::fs::write(file_name, generated.to_string())?;
Ok(())
}
fn generate_ddriob_config(
reg_to_values: &RegisterToValueMap,
file_name: &str,
) -> std::io::Result<()> {
// Format as hex strings
let addr0 = reg_to_values.val_as_token("DDRIOB Addr 0", 0xF800_0B40);
let addr1 = reg_to_values.val_as_token("DDRIOB Addr 1", 0xF800_0B44);
let data0 = reg_to_values.val_as_token("DDRIOB Data 0", 0xF800_0B48);
let data1 = reg_to_values.val_as_token("DDRIOB Data 1", 0xF800_0B4C);
let diff0 = reg_to_values.val_as_token("DDRIOB Diff 0", 0xF800_0B50);
let diff1 = reg_to_values.val_as_token("DDRIOB Diff 1", 0xF800_0B54);
let clock = reg_to_values.val_as_token("DDRIOB Clock", 0xF800_0B58);
let generated = quote::quote! {
//!This file was auto-generated by the [zynq7000-ps7init-extract](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/tools/zynq7000-ps7init-extract) program.
//!
//!This configuration file contains static DDRIOB configuration parameters extracted from the
//!AMD ps7init.tcl file
use zynq7000::ddrc::regs;
use zynq7000_hal::ddr::DdriobConfigSet;
pub const DDRIOB_CONFIG_SET_ZEDBOARD: DdriobConfigSet = DdriobConfigSet {
addr0: regs::DdriobConfig::new_with_raw_value(#addr0),
addr1: regs::DdriobConfig::new_with_raw_value(#addr1),
data0: regs::DdriobConfig::new_with_raw_value(#data0),
data1: regs::DdriobConfig::new_with_raw_value(#data1),
diff0: regs::DdriobConfig::new_with_raw_value(#diff0),
diff1: regs::DdriobConfig::new_with_raw_value(#diff1),
clock: regs::DdriobConfig::new_with_raw_value(#clock),
};
};
std::fs::write(file_name, generated.to_string())?;
Ok(())
}