use clap::ArgMatches;
use std::process;
use crate::common::{
enforce_extern_verilog_codegen_policy, extract_codegen_flags, parse_bool_flag_or, CodegenFlags,
};
use crate::report_cli_error::report_cli_error_and_exit;
use crate::toolchain_config::ToolchainConfig;
use crate::tools::{run_codegen_combinational, run_opt_main};
use xlsynth_pir::{run_aug_opt_over_ir_text, AugOptOptions};
pub fn handle_ir2combo(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")
.expect("--delay_model must be specified");
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 allow_extern_verilog = parse_bool_flag_or(matches, "allow_extern_verilog", true);
let ir_top_opt = matches.get_one::<String>("ir_top");
ir2combo(
input_path,
delay_model,
&codegen_flags,
optimize,
aug_opt,
allow_extern_verilog,
ir_top_opt.map(|s| s.as_str()),
&keep_temps,
config,
);
}
fn ir2combo(
input_file: &std::path::Path,
delay_model: &str,
codegen_flags: &CodegenFlags,
optimize: bool,
aug_opt: bool,
allow_extern_verilog: bool,
ir_top: Option<&str>,
keep_temps: &Option<bool>,
config: &Option<ToolchainConfig>,
) {
log::info!("ir2combo");
if aug_opt && !optimize {
eprintln!("error: ir2combo: --aug-opt=true requires --opt=true");
process::exit(2);
}
let tool_path = match config.as_ref().and_then(|c| c.tool_path.as_deref()) {
Some(p) => p,
None => {
eprintln!("ir2combo requires a toolchain configuration with a `tool_path` entry");
process::exit(1);
}
};
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 ir_for_codegen_text = std::fs::read_to_string(&ir_for_codegen_path)
.expect("IR file handed to codegen should be readable");
enforce_extern_verilog_codegen_policy(&ir_for_codegen_text, allow_extern_verilog)
.unwrap_or_else(|err| report_cli_error_and_exit(&err, Some("ir2combo"), vec![]));
let sv = run_codegen_combinational(&ir_for_codegen_path, delay_model, codegen_flags, tool_path);
let sv_path = temp_dir.path().join("output.sv");
std::fs::write(&sv_path, &sv).unwrap();
if keep_temps.is_some() {
let temp_dir_path = temp_dir.keep();
eprintln!(
"Combinational code generation successful. Output written to: {}",
temp_dir_path.to_str().unwrap()
);
}
println!("{}", sv);
}