use clap::ArgMatches;
use crate::common::{
extract_codegen_flags, extract_pipeline_spec, pipeline_codegen_flags_proto,
scheduling_options_proto, CodegenFlags, PipelineSpec,
};
use crate::toolchain_config::ToolchainConfig;
use crate::tools::{run_codegen_pipeline, run_opt_main};
use xlsynth_pir::{run_aug_opt_over_ir_text, AugOptOptions};
pub fn handle_ir2pipeline(matches: &ArgMatches, config: &Option<ToolchainConfig>) {
let input_file = matches.get_one::<String>("ir_input_file").unwrap();
let input_path = std::path::Path::new(input_file);
let delay_model = matches.get_one::<String>("DELAY_MODEL").unwrap();
let pipeline_spec = extract_pipeline_spec(matches);
let codegen_flags = extract_codegen_flags(matches, config.as_ref());
let keep_temps = matches.get_one::<String>("keep_temps").map(|s| s == "true");
let optimize = matches
.get_one::<String>("opt")
.map(|s| s == "true")
.unwrap_or(false);
let aug_opt = matches
.get_one::<String>("aug_opt")
.map(|s| s == "true")
.unwrap_or(false);
let ir_top_opt = matches.get_one::<String>("ir_top");
ir2pipeline(
input_path,
delay_model,
&pipeline_spec,
&codegen_flags,
optimize,
aug_opt,
ir_top_opt.map(|s| s.as_str()),
&keep_temps,
config,
);
}
fn ir2pipeline(
input_file: &std::path::Path,
delay_model: &str,
pipeline_spec: &PipelineSpec,
codegen_flags: &CodegenFlags,
optimize: bool,
aug_opt: bool,
ir_top: Option<&str>,
keep_temps: &Option<bool>,
config: &Option<ToolchainConfig>,
) {
log::info!("ir2pipeline");
if aug_opt && !optimize {
eprintln!("error: ir2pipeline: --aug-opt=true requires --opt=true");
std::process::exit(2);
}
if let Some(tool_path) = config.as_ref().and_then(|c| c.tool_path.as_deref()) {
log::info!("ir2pipeline: using tool path: {}", tool_path);
let temp_dir = tempfile::TempDir::new().unwrap();
let ir_for_codegen_path: std::path::PathBuf = if optimize {
let top_name = ir_top.expect("--opt requires --top to be specified");
let opt_ir = if aug_opt {
let input_text =
std::fs::read_to_string(input_file).expect("IR input file should be readable");
run_aug_opt_over_ir_text(
&input_text,
Some(top_name),
AugOptOptions {
enable: true,
rounds: 1,
..Default::default()
},
)
.expect("aug_opt should succeed")
} else {
run_opt_main(input_file, Some(top_name), tool_path)
};
let opt_ir_path = temp_dir.path().join("opt.ir");
std::fs::write(&opt_ir_path, &opt_ir).unwrap();
opt_ir_path
} else {
input_file.to_path_buf()
};
let sv = run_codegen_pipeline(
&ir_for_codegen_path,
delay_model,
pipeline_spec,
codegen_flags,
tool_path,
);
let sv_path = temp_dir.path().join("output.sv");
std::fs::write(&sv_path, &sv).unwrap();
if let Some(_) = keep_temps {
let temp_dir_path = temp_dir.keep();
eprintln!(
"Pipeline generation successful. Output written to: {}",
temp_dir_path.to_str().unwrap()
);
}
println!("{}", sv);
} else {
log::info!("ir2pipeline: using runtime API");
let ir_text =
std::fs::read_to_string(input_file).expect("IR input file should be readable");
let mut ir_package =
xlsynth::IrPackage::parse_ir(&ir_text, input_file.file_name().and_then(|s| s.to_str()))
.expect("IR parsing should succeed");
if optimize {
let top_name = ir_top.expect("--opt requires --top to be specified");
if aug_opt {
let out_text = run_aug_opt_over_ir_text(
&ir_text,
Some(top_name),
AugOptOptions {
enable: true,
rounds: 1,
..Default::default()
},
)
.expect("aug_opt should succeed");
ir_package = xlsynth::IrPackage::parse_ir(
&out_text,
input_file.file_name().and_then(|s| s.to_str()),
)
.expect("IR parsing after aug_opt should succeed");
} else {
ir_package = xlsynth::optimize_ir(&ir_package, top_name)
.expect("IR optimization should succeed");
}
}
let scheduling_options_flags_proto = scheduling_options_proto(delay_model, pipeline_spec);
let codegen_flags_proto = pipeline_codegen_flags_proto(codegen_flags);
let codegen_result = xlsynth::schedule_and_codegen(
&ir_package,
&scheduling_options_flags_proto,
&codegen_flags_proto,
)
.expect("schedule and codegen should succeed");
let sv = codegen_result.get_verilog_text().unwrap();
println!("{}", sv);
}
}