use argh::FromArgs;
#[cfg(feature = "serialize")]
use calyx_backend::SexpBackend;
use calyx_backend::{
xilinx::{XilinxInterfaceBackend, XilinxXmlBackend},
Backend, BackendOpt, FirrtlBackend, MlirBackend, PrimitiveUsesBackend,
ResourcesBackend, VerilogBackend, YxiBackend,
};
use calyx_ir as ir;
use calyx_utils::{CalyxResult, Error, OutputFile};
use std::path::Path;
use std::path::PathBuf;
use std::str::FromStr;
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "pass-help")]
pub struct Help {
#[argh(positional)]
pub name: Option<String>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
pub enum Subcommand {
Help(Help),
}
#[derive(FromArgs)]
pub struct Opts {
#[argh(subcommand)]
pub sub: Option<Subcommand>,
#[argh(positional, from_str_fn(read_path))]
pub file: Option<PathBuf>,
#[argh(option, short = 'o', default = "OutputFile::Stdout")]
pub output: OutputFile,
#[argh(
option,
short = 'l',
default = "Path::new(option_env!(\"CALYX_PRIMITIVES_DIR\").unwrap_or(\".\")).into()"
)]
pub lib_path: PathBuf,
#[argh(option, short = 'm', default = "CompileMode::default()")]
pub compile_mode: CompileMode,
#[argh(switch, long = "synthesis")]
pub enable_synthesis: bool,
#[argh(switch)]
pub disable_verify: bool,
#[argh(switch, long = "nested")]
pub nested_assign: bool,
#[argh(switch, long = "emit-primitive-extmodules")]
pub emit_primitive_extmodules: bool,
#[argh(option, short = 'b', default = "BackendOpt::default()")]
pub backend: BackendOpt,
#[argh(option, short = 'p')]
pub pass: Vec<String>,
#[argh(option, short = 'd', long = "disable-pass")]
pub disable_pass: Vec<String>,
#[argh(option, short = 'x', long = "extra-opt")]
pub extra_opts: Vec<String>,
#[argh(option, long = "log", default = "log::LevelFilter::Warn")]
pub log_level: log::LevelFilter,
#[argh(switch, long = "dump-ir")]
pub dump_ir: bool,
#[argh(switch, long = "version")]
pub version: bool,
}
fn read_path(path: &str) -> Result<PathBuf, String> {
Ok(Path::new(path).into())
}
#[derive(Default, PartialEq, Eq)]
pub enum CompileMode {
File,
#[default]
Project,
}
impl FromStr for CompileMode {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"file" => Ok(CompileMode::File),
"project" => Ok(CompileMode::Project),
s => Err(format!("Unknown compilation mode: {}. Valid options are `file` or `project`", s))
}
}
}
impl Opts {
pub fn run_backend(self, context: ir::Context) -> CalyxResult<()> {
match self.backend {
BackendOpt::Mlir => {
let backend = MlirBackend;
backend.run(context, self.output)
}
BackendOpt::Resources => {
let backend = ResourcesBackend;
backend.run(context, self.output)
}
BackendOpt::Sexp => {
#[cfg(feature = "serialize")]
{
let backend = SexpBackend;
backend.run(context, self.output)
}
#[cfg(not(feature = "serialize"))]
{
Err(Error::misc(
"Sexp backend requires the `serialize` feature to be enabled",
))
}
}
BackendOpt::Verilog => {
let backend = VerilogBackend;
backend.run(context, self.output)
}
BackendOpt::Xilinx => {
let backend = XilinxInterfaceBackend;
backend.run(context, self.output)
}
BackendOpt::XilinxXml => {
let backend = XilinxXmlBackend;
backend.run(context, self.output)
}
BackendOpt::Yxi => {
let backend = YxiBackend;
backend.run(context, self.output)
}
BackendOpt::Firrtl => {
let backend = FirrtlBackend;
backend.run(context, self.output)
}
BackendOpt::PrimitiveUses => {
let backend = PrimitiveUsesBackend;
backend.run(context, self.output)
}
BackendOpt::Calyx => {
ir::Printer::write_context(
&context,
false,
&mut self.output.get_write(),
)?;
Ok(())
}
BackendOpt::None => Ok(()),
}
}
pub fn get_opts() -> CalyxResult<Opts> {
let mut opts: Opts = argh::from_env();
if opts.compile_mode == CompileMode::File
&& !matches!(opts.backend, BackendOpt::Calyx | BackendOpt::None)
{
return Err(Error::misc(format!(
"--compile-mode=file is only valid with -b calyx. `-b {}` requires --compile-mode=project",
opts.backend.to_string()
)));
}
if opts.pass.is_empty() {
opts.pass = vec!["all".into()];
}
Ok(opts)
}
}