gowiners 0.2.1

Gowin EDA thin oxidized wrapper
Documentation
use std::{env::current_dir, fs, io::ErrorKind};

use anyhow::anyhow;
use bpaf::*;
use colored::Colorize;
use crate::pipeline::{EvaluationError, Pipeline};
use crate::wrapper::{eda::GowinEda, pipeline::commands, project::Project};

#[derive(Debug, Clone)]
pub enum Opts {
	Syn {},
	Impl {},
	Flash { preset: String },
}

fn options() -> OptionParser<Opts> {
	let impl_opts = construct!(Opts::Impl {})
		.to_options()
		.descr("Runs synthesis and routing");

	let syn_opts = construct!(Opts::Syn {}).to_options().descr("Runs synthesis");

	let impl_cmd = impl_opts.command("impl");
	let syn_cmd = syn_opts.command("syn");

	let preset = positional::<String>("PRESET");

	let flash_opts = construct!(Opts::Flash { preset })
		.to_options()
		.descr("Flashes bitstream using provided preset");

	let flash_cmd = flash_opts.command("flash");

	construct!([impl_cmd, syn_cmd, flash_cmd])
		.to_options()
		.descr(env!("CARGO_PKG_DESCRIPTION"))
}

pub fn run() -> anyhow::Result<()> {
	let opts = options().fallback_to_usage().run();
	let cwd = current_dir()?;

	let gowiners_toml_str = match fs::read_to_string(cwd.join("Gowiners.toml")) {
		Ok(it) => it,
		Err(err) if err.kind() == ErrorKind::NotFound => {
			return Err(anyhow!("The `Gowiners.toml` file not found"));
		}
		Err(err) => Err(err)?,
	};

	let eda = GowinEda::from_env()
		.or_else(|| GowinEda::from_file(cwd.join(".gowin")))
		.ok_or(anyhow!("Please specify path to Gowin EDA installation dir via `GOWIN_EDA_HOME` environment variable of `.gowin` file"))?;

	let project: Project = toml::from_str(&gowiners_toml_str)?;

	let configure_project = || -> Result<Pipeline, EvaluationError> {
		println!("{}", "Run Gowin EDA".bold());
		let mut wrk = eda.pipeline();
		println!("  {}", "Configuring project".bold());
		wrk.configure(&project)?;
		Ok(wrk)
	};

	let run_opts = || -> anyhow::Result<()> {
		match opts {
			Opts::Impl { .. } => {
				let mut wrk = configure_project()?;
				println!("  {}", "Run Implementation (Syn + PnR)".bold());
				wrk.push(commands::Run::All);
				wrk.run()?;
			}
			Opts::Syn { .. } => {
				let mut wrk = configure_project()?;
				println!("  {}", "Run Synthesis".bold());
				wrk.push(commands::Run::Syn);
				wrk.run()?;
			}
			Opts::Flash { preset } => {
				println!("{}", "Flash bitstream".bold());
				let mut prg = eda.programmer();
				println!("  {}", "Configuring programmer".bold());
				println!("    {} {}", "Preset:".bold(), preset.cyan());
				prg.evaluate(&project, preset)?;
				println!("  {}", "Flashing".bold());
				prg.run()?;
			}
		}

		Ok(())
	};

	match run_opts() {
		Ok(_) => {
			println!("{}", "Completed".bold().green());
		}
		Err(err) => {
			println!("{}", format!("Failed: {}", err).bold().red());
		}
	}

	Ok(())
}