WIP adding peripherals
Some checks failed
/ test (pull_request) Failing after 49s

This commit is contained in:
Jacob Lifshay 2025-10-17 18:00:11 -07:00
parent 4d54f903be
commit 2848f3dee4
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
18 changed files with 1200 additions and 240 deletions

31
Cargo.lock generated
View file

@ -319,6 +319,7 @@ dependencies = [
"jobslot",
"num-bigint",
"num-traits",
"ordered-float",
"petgraph",
"serde",
"serde_json",
@ -524,6 +525,17 @@ version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "ordered-float"
version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d"
dependencies = [
"num-traits",
"rand",
"serde",
]
[[package]]
name = "petgraph"
version = "0.8.1"
@ -576,6 +588,25 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"rand_core",
"serde",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"serde",
]
[[package]]
name = "rustix"
version = "0.38.31"

View file

@ -30,6 +30,7 @@ indexmap = { version = "2.5.0", features = ["serde"] }
jobslot = "0.2.23"
num-bigint = "0.4.6"
num-traits = "0.2.16"
ordered-float = { version = "5.1.0", features = ["serde"] }
petgraph = "0.8.1"
prettyplease = "0.2.20"
proc-macro2 = "1.0.83"

View file

@ -26,6 +26,7 @@ hashbrown.workspace = true
jobslot.workspace = true
num-bigint.workspace = true
num-traits.workspace = true
ordered-float.workspace = true
petgraph.workspace = true
serde_json.workspace = true
serde.workspace = true

View file

@ -6,6 +6,7 @@ use crate::{
bundle::{Bundle, BundleType},
intern::{Intern, InternSlice, Interned},
module::Module,
platform::{DynPlatform, Platform},
util::{job_server::AcquiredJob, os_str_strip_prefix},
vendor,
};
@ -318,6 +319,7 @@ impl<K: JobKind> JobKindAndArgs<K> {
self,
dependencies: <K::Dependencies as JobDependencies>::KindsAndArgs,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<JobAndDependencies<K>> {
K::args_to_jobs(
JobArgsAndDependencies {
@ -325,6 +327,7 @@ impl<K: JobKind> JobKindAndArgs<K> {
dependencies,
},
params,
global_params,
)
}
}
@ -446,8 +449,12 @@ where
}
impl<K: JobKind> JobArgsAndDependencies<K> {
pub fn args_to_jobs(self, params: &JobParams) -> eyre::Result<JobAndDependencies<K>> {
K::args_to_jobs(self, params)
pub fn args_to_jobs(
self,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<JobAndDependencies<K>> {
K::args_to_jobs(self, params, global_params)
}
}
@ -455,6 +462,7 @@ impl<K: JobKind<Dependencies = JobKindAndDependencies<D>>, D: JobKind> JobArgsAn
pub fn args_to_jobs_simple<F>(
self,
params: &JobParams,
global_params: &GlobalParams,
f: F,
) -> eyre::Result<JobAndDependencies<K>>
where
@ -464,7 +472,7 @@ impl<K: JobKind<Dependencies = JobKindAndDependencies<D>>, D: JobKind> JobArgsAn
args: JobKindAndArgs { kind, args },
dependencies,
} = self;
let mut dependencies = dependencies.args_to_jobs(params)?;
let mut dependencies = dependencies.args_to_jobs(params, global_params)?;
let job = f(kind, args, &mut dependencies)?;
Ok(JobAndDependencies {
job: JobAndKind { kind, job },
@ -479,6 +487,7 @@ impl<C: external::ExternalCommand<Dependencies = JobKindAndDependencies<D>>, D:
pub fn args_to_jobs_external_simple<F>(
self,
params: &JobParams,
global_params: &GlobalParams,
f: F,
) -> eyre::Result<(
C::AdditionalJobData,
@ -494,7 +503,7 @@ impl<C: external::ExternalCommand<Dependencies = JobKindAndDependencies<D>>, D:
args: JobKindAndArgs { kind: _, args },
dependencies,
} = self;
let mut dependencies = dependencies.args_to_jobs(params)?;
let mut dependencies = dependencies.args_to_jobs(params, global_params)?;
let additional_job_data = f(args, &mut dependencies)?;
Ok((additional_job_data, dependencies))
}
@ -624,7 +633,6 @@ impl_job_dependencies! {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct JobParams {
main_module: Module<Bundle>,
application_name: Interned<str>,
}
impl AsRef<Self> for JobParams {
@ -634,24 +642,65 @@ impl AsRef<Self> for JobParams {
}
impl JobParams {
pub fn new_canonical(main_module: Module<Bundle>, application_name: Interned<str>) -> Self {
Self {
main_module,
application_name,
}
pub fn new_canonical(main_module: Module<Bundle>) -> Self {
Self { main_module }
}
pub fn new<B: BundleType>(
main_module: impl AsRef<Module<B>>,
application_name: impl AsRef<str>,
) -> Self {
Self::new_canonical(
main_module.as_ref().canonical(),
application_name.as_ref().intern(),
)
pub fn new<B: BundleType>(main_module: impl AsRef<Module<B>>) -> Self {
Self::new_canonical(main_module.as_ref().canonical())
}
pub fn main_module(&self) -> &Module<Bundle> {
&self.main_module
}
}
#[derive(Clone, Debug)]
pub struct GlobalParams {
top_level_cmd: Option<clap::Command>,
application_name: Interned<str>,
}
impl AsRef<Self> for GlobalParams {
fn as_ref(&self) -> &Self {
self
}
}
impl GlobalParams {
pub fn new(top_level_cmd: Option<clap::Command>, application_name: impl AsRef<str>) -> Self {
Self {
top_level_cmd,
application_name: application_name.as_ref().intern(),
}
}
pub fn top_level_cmd(&self) -> Option<&clap::Command> {
self.top_level_cmd.as_ref()
}
pub fn into_top_level_cmd(self) -> Option<clap::Command> {
self.top_level_cmd
}
pub fn extract_clap_error(&self, e: eyre::Report) -> eyre::Result<clap::Error> {
let e = e.downcast::<clap::Error>()?;
Ok(match &self.top_level_cmd {
Some(cmd) => e.with_cmd(cmd),
None => e,
})
}
pub fn exit_if_clap_error(&self, e: eyre::Report) -> eyre::Report {
match self.extract_clap_error(e) {
Ok(e) => e.exit(),
Err(e) => e,
}
}
pub fn clap_error(
&self,
kind: clap::error::ErrorKind,
message: impl fmt::Display,
) -> clap::Error {
match self.top_level_cmd.clone() {
Some(top_level_cmd) => top_level_cmd.clone().error(kind, message),
None => clap::Error::raw(kind, message),
}
}
pub fn application_name(&self) -> Interned<str> {
self.application_name
}
@ -710,6 +759,7 @@ pub trait JobKind: 'static + Send + Sync + Hash + Eq + fmt::Debug + Sized + Copy
fn args_to_jobs(
args: JobArgsAndDependencies<Self>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<JobAndDependencies<Self>>;
fn inputs(self, job: &Self::Job) -> Interned<[JobItemName]>;
fn outputs(self, job: &Self::Job) -> Interned<[JobItemName]>;
@ -720,6 +770,7 @@ pub trait JobKind: 'static + Send + Sync + Hash + Eq + fmt::Debug + Sized + Copy
job: &Self::Job,
inputs: &[JobItem],
params: &JobParams,
global_params: &GlobalParams,
acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>>;
fn subcommand_hidden(self) -> bool {
@ -1064,6 +1115,7 @@ trait DynJobArgsTrait: 'static + Send + Sync + fmt::Debug {
self: Arc<Self>,
dependencies_args: Vec<DynJobArgs>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<(DynJob, Vec<DynJob>)>;
}
@ -1117,12 +1169,13 @@ impl<K: JobKind> DynJobArgsTrait for DynJobArgsInner<K> {
self: Arc<Self>,
dependencies_args: Vec<DynJobArgs>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<(DynJob, Vec<DynJob>)> {
let JobAndDependencies { job, dependencies } = JobArgsAndDependencies {
args: Arc::unwrap_or_clone(self).0,
dependencies: K::Dependencies::from_dyn_args(dependencies_args),
}
.args_to_jobs(params)?;
.args_to_jobs(params, global_params)?;
Ok((job.into(), K::Dependencies::into_dyn_jobs(dependencies)))
}
}
@ -1179,8 +1232,9 @@ impl DynJobArgs {
self,
dependencies_args: Vec<DynJobArgs>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<(DynJob, Vec<DynJob>)> {
DynJobArgsTrait::args_to_jobs(self.0, dependencies_args, params)
DynJobArgsTrait::args_to_jobs(self.0, dependencies_args, params, global_params)
}
}
@ -1261,6 +1315,7 @@ trait DynJobTrait: 'static + Send + Sync + fmt::Debug {
&self,
inputs: &[JobItem],
params: &JobParams,
global_params: &GlobalParams,
acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>>;
}
@ -1317,9 +1372,11 @@ impl<T: JobKind> DynJobTrait for DynJobInner<T> {
&self,
inputs: &[JobItem],
params: &JobParams,
global_params: &GlobalParams,
acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>> {
self.kind.run(&self.job, inputs, params, acquired_job)
self.kind
.run(&self.job, inputs, params, global_params, acquired_job)
}
}
@ -1429,9 +1486,10 @@ impl DynJob {
&self,
inputs: &[JobItem],
params: &JobParams,
global_params: &GlobalParams,
acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>> {
DynJobTrait::run(&*self.0, inputs, params, acquired_job)
DynJobTrait::run(&*self.0, inputs, params, global_params, acquired_job)
}
}
@ -1481,56 +1539,159 @@ impl<'de> Deserialize<'de> for DynJob {
}
pub trait RunBuild<Extra: ToArgs = NoArgs>: Sized {
fn main<F>(make_params: F)
fn main_without_platform<F>(application_name: impl AsRef<str>, make_params: F)
where
Self: clap::Parser + Clone,
F: FnOnce(Self, Extra) -> eyre::Result<JobParams>,
{
match Self::try_main(make_params) {
let application_name = application_name.as_ref();
match Self::try_main_without_platform(application_name, make_params) {
Ok(()) => {}
Err(e) => {
let e = GlobalParams::new(Some(Self::command()), application_name)
.exit_if_clap_error(e);
eprintln!("{e:#}");
std::process::exit(1);
}
}
}
fn try_main<F>(make_params: F) -> eyre::Result<()>
fn try_main_without_platform<F>(
application_name: impl AsRef<str>,
make_params: F,
) -> eyre::Result<()>
where
Self: clap::Parser + Clone,
F: FnOnce(Self, Extra) -> eyre::Result<JobParams>,
{
let args = Self::parse();
let global_params = GlobalParams::new(Some(Self::command()), application_name);
args.clone()
.run(|extra| make_params(args, extra), Self::command())
.run_without_platform(|extra| make_params(args, extra), &global_params)
.map_err(|e| global_params.exit_if_clap_error(e))
}
fn run<F>(self, make_params: F, cmd: clap::Command) -> eyre::Result<()>
fn run_without_platform<F>(
self,
make_params: F,
global_params: &GlobalParams,
) -> eyre::Result<()>
where
F: FnOnce(Extra) -> eyre::Result<JobParams>;
fn main<F>(application_name: impl AsRef<str>, make_params: F)
where
Self: clap::Parser + Clone + GetPlatform,
F: FnOnce(Self, DynPlatform, Extra) -> eyre::Result<JobParams>,
{
let application_name = application_name.as_ref();
match Self::try_main(application_name, make_params) {
Ok(()) => {}
Err(e) => {
let e = GlobalParams::new(Some(Self::command()), application_name)
.exit_if_clap_error(e);
eprintln!("{e:#}");
std::process::exit(1);
}
}
}
fn try_main<F>(application_name: impl AsRef<str>, make_params: F) -> eyre::Result<()>
where
Self: clap::Parser + Clone + GetPlatform,
F: FnOnce(Self, DynPlatform, Extra) -> eyre::Result<JobParams>,
{
let args = Self::parse();
let global_params = GlobalParams::new(Some(Self::command()), application_name);
let Some(platform) = args.get_platform() else {
return args.handle_missing_platform(&global_params);
};
args.clone()
.run(
|platform, extra| make_params(args, platform, extra),
platform,
&global_params,
)
.map_err(|e| global_params.exit_if_clap_error(e))
}
fn handle_missing_platform(self, global_params: &GlobalParams) -> eyre::Result<()> {
global_params
.clap_error(
clap::error::ErrorKind::MissingRequiredArgument,
"--platform is required",
)
.exit();
}
fn run<F>(
self,
make_params: F,
platform: DynPlatform,
global_params: &GlobalParams,
) -> eyre::Result<()>
where
F: FnOnce(DynPlatform, Extra) -> eyre::Result<JobParams>,
{
self.run_without_platform(|extra| make_params(platform, extra), global_params)
}
}
impl<K: JobKind> RunBuild for JobArgsAndDependencies<K> {
fn run<F>(self, make_params: F, cmd: clap::Command) -> eyre::Result<()>
fn run_without_platform<F>(
self,
make_params: F,
global_params: &GlobalParams,
) -> eyre::Result<()>
where
F: FnOnce(NoArgs) -> eyre::Result<JobParams>,
{
let params = make_params(NoArgs)?;
self.args_to_jobs(&params)?.run(|_| Ok(params), cmd)
self.args_to_jobs(&params, global_params)?
.run_without_platform(|_| Ok(params), global_params)
}
fn run<F>(
self,
make_params: F,
platform: DynPlatform,
global_params: &GlobalParams,
) -> eyre::Result<()>
where
F: FnOnce(DynPlatform, NoArgs) -> eyre::Result<JobParams>,
{
let params = make_params(platform.clone(), NoArgs)?;
self.args_to_jobs(&params, global_params)?
.run(|_, _| Ok(params), platform, global_params)
}
}
impl<K: JobKind> RunBuild for JobAndDependencies<K> {
fn run<F>(self, make_params: F, cmd: clap::Command) -> eyre::Result<()>
fn run_without_platform<F>(
self,
make_params: F,
global_params: &GlobalParams,
) -> eyre::Result<()>
where
F: FnOnce(NoArgs) -> eyre::Result<JobParams>,
{
let _ = cmd;
let params = make_params(NoArgs)?;
let Self { job, dependencies } = self;
let mut jobs = vec![DynJob::from(job)];
K::Dependencies::into_dyn_jobs_extend(dependencies, &mut jobs);
let mut job_graph = JobGraph::new();
job_graph.add_jobs(jobs); // add all at once to avoid recomputing graph properties multiple times
job_graph.run(&params)
job_graph.run(&params, global_params)
}
fn run<F>(
self,
make_params: F,
platform: DynPlatform,
global_params: &GlobalParams,
) -> eyre::Result<()>
where
F: FnOnce(DynPlatform, NoArgs) -> eyre::Result<JobParams>,
{
let params = make_params(platform, NoArgs)?;
let Self { job, dependencies } = self;
let mut jobs = vec![DynJob::from(job)];
K::Dependencies::into_dyn_jobs_extend(dependencies, &mut jobs);
let mut job_graph = JobGraph::new();
job_graph.add_jobs(jobs); // add all at once to avoid recomputing graph properties multiple times
job_graph.run(&params, global_params)
}
}
@ -1629,15 +1790,18 @@ impl<Extra: ToArgs> clap::FromArgMatches for RunSingleJob<Extra> {
}
impl<Extra: ToArgs> RunBuild<Extra> for RunSingleJob<Extra> {
fn run<F>(self, make_params: F, cmd: clap::Command) -> eyre::Result<()>
fn run_without_platform<F>(
self,
make_params: F,
global_params: &GlobalParams,
) -> eyre::Result<()>
where
F: FnOnce(Extra) -> eyre::Result<JobParams>,
{
let _ = cmd;
let params = make_params(self.extra)?;
let mut job_graph = JobGraph::new();
job_graph.add_jobs([self.job]);
job_graph.run(&params)
job_graph.run(&params, global_params)
}
}
@ -1674,11 +1838,18 @@ impl Completions {
}
impl RunBuild for Completions {
fn run<F>(self, _make_params: F, mut cmd: clap::Command) -> eyre::Result<()>
fn run_without_platform<F>(
self,
_make_params: F,
global_params: &GlobalParams,
) -> eyre::Result<()>
where
F: FnOnce(NoArgs) -> eyre::Result<JobParams>,
{
let Self::Completions { shell } = self;
let Some(cmd) = global_params.top_level_cmd() else {
eyre::bail!("completions command requires GlobalParams::top_level_cmd() to be Some");
};
let bin_name = cmd.get_bin_name().map(str::intern).unwrap_or_else(|| {
program_name_for_internal_jobs()
.to_interned_str()
@ -1686,12 +1857,15 @@ impl RunBuild for Completions {
});
clap_complete::aot::generate(
shell,
&mut cmd,
&mut cmd.clone(),
&*bin_name,
&mut std::io::BufWriter::new(std::io::stdout().lock()),
);
Ok(())
}
fn handle_missing_platform(self, global_params: &GlobalParams) -> eyre::Result<()> {
self.run_without_platform(|_| unreachable!(), global_params)
}
}
#[derive(
@ -1730,16 +1904,52 @@ pub enum BuildCli<Extra: ToArgs = NoArgs> {
}
impl<Extra: ToArgs> RunBuild<Extra> for BuildCli<Extra> {
fn run<F>(self, make_params: F, cmd: clap::Command) -> eyre::Result<()>
fn run_without_platform<F>(
self,
make_params: F,
global_params: &GlobalParams,
) -> eyre::Result<()>
where
F: FnOnce(Extra) -> eyre::Result<JobParams>,
{
match self {
BuildCli::Job(v) => v.run(make_params, cmd),
BuildCli::RunSingleJob(v) => v.run(make_params, cmd),
BuildCli::Completions(v) => v.run(|NoArgs {}| unreachable!(), cmd),
BuildCli::Job(v) => v.run_without_platform(make_params, global_params),
BuildCli::RunSingleJob(v) => v.run_without_platform(make_params, global_params),
BuildCli::Completions(v) => {
v.run_without_platform(|NoArgs {}| unreachable!(), global_params)
}
#[cfg(unix)]
BuildCli::CreateUnixShellScript(v) => v.run(make_params, cmd),
BuildCli::CreateUnixShellScript(v) => {
v.run_without_platform(make_params, global_params)
}
}
}
fn handle_missing_platform(self, global_params: &GlobalParams) -> eyre::Result<()> {
match self {
BuildCli::Job(v) => v.handle_missing_platform(global_params),
BuildCli::RunSingleJob(v) => v.handle_missing_platform(global_params),
BuildCli::Completions(v) => v.handle_missing_platform(global_params),
#[cfg(unix)]
BuildCli::CreateUnixShellScript(v) => v.handle_missing_platform(global_params),
}
}
fn run<F>(
self,
make_params: F,
platform: DynPlatform,
global_params: &GlobalParams,
) -> eyre::Result<()>
where
F: FnOnce(DynPlatform, Extra) -> eyre::Result<JobParams>,
{
match self {
BuildCli::Job(v) => v.run(make_params, platform, global_params),
BuildCli::RunSingleJob(v) => v.run(make_params, platform, global_params),
BuildCli::Completions(v) => {
v.run(|_, NoArgs {}| unreachable!(), platform, global_params)
}
#[cfg(unix)]
BuildCli::CreateUnixShellScript(v) => v.run(make_params, platform, global_params),
}
}
}
@ -1759,7 +1969,11 @@ enum CreateUnixShellScriptInner<Extra: ToArgs> {
pub struct CreateUnixShellScript<Extra: ToArgs = NoArgs>(CreateUnixShellScriptInner<Extra>);
impl<Extra: ToArgs> RunBuild<Extra> for CreateUnixShellScript<Extra> {
fn run<F>(self, make_params: F, cmd: clap::Command) -> eyre::Result<()>
fn run_without_platform<F>(
self,
make_params: F,
global_params: &GlobalParams,
) -> eyre::Result<()>
where
F: FnOnce(Extra) -> eyre::Result<JobParams>,
{
@ -1774,16 +1988,17 @@ impl<Extra: ToArgs> RunBuild<Extra> for CreateUnixShellScript<Extra> {
} = self.0;
let extra_args = extra.to_interned_args_vec();
let params = make_params(extra)?;
let (job, dependencies) = args.args_to_jobs(dependencies_args, &params)?;
let bin_name = global_params
.top_level_cmd()
.and_then(clap::Command::get_bin_name)
.map(|v| OsStr::new(v).intern());
let (job, dependencies) = args.args_to_jobs(dependencies_args, &params, global_params)?;
let mut job_graph = JobGraph::new();
job_graph.add_jobs([job].into_iter().chain(dependencies));
std::io::stdout().write_all(
job_graph
.to_unix_shell_script_with_internal_program_prefix(
&[cmd
.get_bin_name()
.map(|v| OsStr::new(v).intern())
.unwrap_or_else(|| program_name_for_internal_jobs())],
&[bin_name.unwrap_or_else(|| program_name_for_internal_jobs())],
&extra_args,
)
.as_bytes(),
@ -1956,21 +2171,24 @@ impl<Extra: ToArgs> clap::FromArgMatches for AnyJobSubcommand<Extra> {
}
impl<Extra: ToArgs> RunBuild<Extra> for AnyJobSubcommand<Extra> {
fn run<F>(self, make_params: F, cmd: clap::Command) -> eyre::Result<()>
fn run_without_platform<F>(
self,
make_params: F,
global_params: &GlobalParams,
) -> eyre::Result<()>
where
F: FnOnce(Extra) -> eyre::Result<JobParams>,
{
let _ = cmd;
let Self {
args,
dependencies_args,
extra,
} = self;
let params = make_params(extra)?;
let (job, dependencies) = args.args_to_jobs(dependencies_args, &params)?;
let (job, dependencies) = args.args_to_jobs(dependencies_args, &params, global_params)?;
let mut job_graph = JobGraph::new();
job_graph.add_jobs([job].into_iter().chain(dependencies)); // add all at once to avoid recomputing graph properties multiple times
job_graph.run(&params)
job_graph.run(&params, global_params)
}
}
@ -2045,6 +2263,7 @@ impl JobKind for CreateOutputDirJobKind {
fn args_to_jobs(
args: JobArgsAndDependencies<Self>,
_params: &JobParams,
_global_params: &GlobalParams,
) -> eyre::Result<JobAndDependencies<Self>> {
let JobArgsAndDependencies {
args:
@ -2120,6 +2339,7 @@ impl JobKind for CreateOutputDirJobKind {
job: &Self::Job,
inputs: &[JobItem],
_params: &JobParams,
_global_params: &GlobalParams,
_acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>> {
let [] = inputs else {
@ -2162,11 +2382,14 @@ pub struct BaseJobArgs {
/// run commands even if their results are already cached
#[arg(long, env = Self::RUN_EVEN_IF_CACHED_ENV_NAME)]
pub run_even_if_cached: bool,
/// platform
#[arg(long)]
pub platform: Option<DynPlatform>,
}
impl BaseJobArgs {
pub const RUN_EVEN_IF_CACHED_ENV_NAME: &'static str = "FAYALITE_RUN_EVEN_IF_CACHED";
pub fn from_output_dir_and_env(output: PathBuf) -> Self {
pub fn from_output_dir_and_env(output: PathBuf, platform: Option<DynPlatform>) -> Self {
Self {
create_output_dir_args: CreateOutputDirArgs {
output: Some(output),
@ -2174,6 +2397,7 @@ impl BaseJobArgs {
},
file_stem: None,
run_even_if_cached: std::env::var_os(Self::RUN_EVEN_IF_CACHED_ENV_NAME).is_some(),
platform,
}
}
}
@ -2184,6 +2408,7 @@ impl ToArgs for BaseJobArgs {
create_output_dir_args,
file_stem,
run_even_if_cached,
platform,
} = self;
create_output_dir_args.to_args(args);
if let Some(file_stem) = file_stem {
@ -2192,6 +2417,9 @@ impl ToArgs for BaseJobArgs {
if *run_even_if_cached {
args.write_arg("--run-even-if-cached");
}
if let Some(platform) = platform {
args.write_long_option_eq("platform", platform.name());
}
}
}
@ -2202,6 +2430,7 @@ pub struct BaseJob {
create_output_dir: CreateOutputDir,
file_stem: Interned<OsStr>,
run_even_if_cached: bool,
platform: Option<DynPlatform>,
}
impl BaseJob {
@ -2219,6 +2448,9 @@ impl BaseJob {
pub fn run_even_if_cached(&self) -> bool {
self.run_even_if_cached
}
pub fn platform(&self) -> Option<&DynPlatform> {
self.platform.as_ref()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
@ -2236,17 +2468,22 @@ impl JobKind for BaseJobKind {
fn args_to_jobs(
args: JobArgsAndDependencies<Self>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<JobAndDependencies<Self>> {
let BaseJobArgs {
create_output_dir_args,
file_stem,
run_even_if_cached,
platform,
} = args.args.args;
let create_output_dir_args = JobKindAndArgs {
kind: CreateOutputDirJobKind,
args: create_output_dir_args,
};
let create_output_dir = create_output_dir_args.args_to_jobs((), params)?.job.job;
let create_output_dir = create_output_dir_args
.args_to_jobs((), params, global_params)?
.job
.job;
let file_stem = file_stem
.map(Intern::intern_deref)
.unwrap_or(params.main_module().name().into());
@ -2257,6 +2494,7 @@ impl JobKind for BaseJobKind {
create_output_dir,
file_stem,
run_even_if_cached,
platform,
},
},
dependencies: (),
@ -2284,9 +2522,16 @@ impl JobKind for BaseJobKind {
job: &Self::Job,
inputs: &[JobItem],
params: &JobParams,
global_params: &GlobalParams,
acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>> {
CreateOutputDirJobKind.run(&job.create_output_dir, inputs, params, acquired_job)
CreateOutputDirJobKind.run(
&job.create_output_dir,
inputs,
params,
global_params,
acquired_job,
)
}
fn subcommand_hidden(self) -> bool {
@ -2382,3 +2627,105 @@ impl<K: JobKind> GetJob<K::Job, GetJobPositionJob> for JobAndDependencies<K> {
&this.job.job
}
}
impl<J, Position, K: JobKind<Dependencies: JobDependencies<KindsAndArgs: GetJob<J, Position>>>>
GetJob<J, GetJobPositionDependencies<Position>> for JobArgsAndDependencies<K>
{
fn get_job(this: &Self) -> &J {
GetJob::get_job(&this.dependencies)
}
}
impl<K: JobKind> GetJob<K::Args, GetJobPositionJob> for JobArgsAndDependencies<K> {
fn get_job(this: &Self) -> &K::Args {
&this.args.args
}
}
impl<J, Position, K: JobKind<Dependencies: GetJob<J, Position>>>
GetJob<J, GetJobPositionDependencies<Position>> for JobKindAndDependencies<K>
{
fn get_job(this: &Self) -> &J {
GetJob::get_job(&this.dependencies)
}
}
impl<K: JobKind> GetJob<K, GetJobPositionJob> for JobKindAndDependencies<K> {
fn get_job(this: &Self) -> &K {
&this.kind
}
}
pub trait GetPlatform {
fn get_platform(&self) -> Option<DynPlatform>;
}
impl<T: ?Sized + GetPlatform> GetPlatform for &'_ T {
fn get_platform(&self) -> Option<DynPlatform> {
T::get_platform(self)
}
}
impl<T: ?Sized + GetPlatform> GetPlatform for &'_ mut T {
fn get_platform(&self) -> Option<DynPlatform> {
T::get_platform(self)
}
}
impl<T: ?Sized + GetPlatform> GetPlatform for Box<T> {
fn get_platform(&self) -> Option<DynPlatform> {
T::get_platform(self)
}
}
impl GetPlatform for BaseJobArgs {
fn get_platform(&self) -> Option<DynPlatform> {
self.platform.clone()
}
}
impl GetPlatform for BaseJob {
fn get_platform(&self) -> Option<DynPlatform> {
self.platform.clone()
}
}
impl GetPlatform for JobAndDependencies<BaseJobKind> {
fn get_platform(&self) -> Option<DynPlatform> {
self.job.get_platform()
}
}
impl GetPlatform for JobArgsAndDependencies<BaseJobKind> {
fn get_platform(&self) -> Option<DynPlatform> {
self.args.get_platform()
}
}
impl<K: JobKind<Job: GetPlatform>> GetPlatform for JobAndKind<K> {
fn get_platform(&self) -> Option<DynPlatform> {
self.job.get_platform()
}
}
impl<K: JobKind<Args: GetPlatform>> GetPlatform for JobKindAndArgs<K> {
fn get_platform(&self) -> Option<DynPlatform> {
self.args.get_platform()
}
}
impl<K: JobKind<Dependencies: JobDependencies<JobsAndKinds: GetPlatform>>> GetPlatform
for JobAndDependencies<K>
{
fn get_platform(&self) -> Option<DynPlatform> {
self.dependencies.get_platform()
}
}
impl<K: JobKind<Dependencies: JobDependencies<KindsAndArgs: GetPlatform>>> GetPlatform
for JobArgsAndDependencies<K>
{
fn get_platform(&self) -> Option<DynPlatform> {
self.dependencies.get_platform()
}
}

View file

@ -3,7 +3,7 @@
use crate::{
build::{
ArgsWriter, BaseJob, CommandParams, GetJob, JobAndDependencies, JobAndKind,
ArgsWriter, BaseJob, CommandParams, GetJob, GlobalParams, JobAndDependencies, JobAndKind,
JobArgsAndDependencies, JobDependencies, JobItem, JobItemName, JobKind, JobKindAndArgs,
JobParams, ToArgs, WriteArgs,
},
@ -996,6 +996,7 @@ pub trait ExternalCommand: 'static + Send + Sync + Hash + Eq + fmt::Debug + Size
fn args_to_jobs(
args: JobArgsAndDependencies<ExternalCommandJobKind<Self>>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<(
Self::AdditionalJobData,
<Self::Dependencies as JobDependencies>::JobsAndKinds,
@ -1028,6 +1029,7 @@ impl<T: ExternalCommand> JobKind for ExternalCommandJobKind<T> {
fn args_to_jobs(
args: JobArgsAndDependencies<Self>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<JobAndDependencies<Self>> {
let JobKindAndArgs {
kind,
@ -1042,7 +1044,7 @@ impl<T: ExternalCommand> JobKind for ExternalCommandJobKind<T> {
additional_args: _,
},
} = args.args;
let (additional_job_data, dependencies) = T::args_to_jobs(args, params)?;
let (additional_job_data, dependencies) = T::args_to_jobs(args, params, global_params)?;
let base_job = GetJob::<BaseJob, _>::get_job(&dependencies);
let job = ExternalCommandJob {
additional_job_data,
@ -1078,7 +1080,8 @@ impl<T: ExternalCommand> JobKind for ExternalCommandJobKind<T> {
self,
job: &Self::Job,
inputs: &[JobItem],
params: &JobParams,
_params: &JobParams,
global_params: &GlobalParams,
acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>> {
assert!(
@ -1093,7 +1096,7 @@ impl<T: ExternalCommand> JobKind for ExternalCommandJobKind<T> {
} = job.command_params();
ExternalJobCaching::new(
&job.output_dir,
&params.application_name(),
&global_params.application_name(),
&T::job_kind_name(),
job.run_even_if_cached,
)?

View file

@ -3,7 +3,7 @@
use crate::{
build::{
BaseJob, BaseJobKind, CommandParams, DynJobKind, JobAndDependencies,
BaseJob, BaseJobKind, CommandParams, DynJobKind, GlobalParams, JobAndDependencies,
JobArgsAndDependencies, JobItem, JobItemName, JobKind, JobKindAndDependencies, JobParams,
ToArgs, WriteArgs,
},
@ -64,9 +64,11 @@ impl JobKind for FirrtlJobKind {
fn args_to_jobs(
args: JobArgsAndDependencies<Self>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<JobAndDependencies<Self>> {
args.args_to_jobs_simple(
params,
global_params,
|_kind, FirrtlArgs { export_options }, dependencies| {
Ok(Firrtl {
base: dependencies.get_job::<BaseJob, _>().clone(),
@ -103,6 +105,7 @@ impl JobKind for FirrtlJobKind {
job: &Self::Job,
inputs: &[JobItem],
params: &JobParams,
_global_params: &GlobalParams,
_acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>> {
let [JobItem::Path { path: input_path }] = *inputs else {

View file

@ -3,8 +3,8 @@
use crate::{
build::{
BaseJob, CommandParams, DynJobKind, GetJobPositionDependencies, JobAndDependencies,
JobArgsAndDependencies, JobDependencies, JobItem, JobItemName, JobKind,
BaseJob, CommandParams, DynJobKind, GetJobPositionDependencies, GlobalParams,
JobAndDependencies, JobArgsAndDependencies, JobDependencies, JobItem, JobItemName, JobKind,
JobKindAndDependencies, JobParams, ToArgs, WriteArgs,
external::{
ExternalCommand, ExternalCommandJob, ExternalCommandJobKind, ExternalProgramTrait,
@ -201,6 +201,7 @@ impl JobKind for WriteSbyFileJobKind {
fn args_to_jobs(
mut args: JobArgsAndDependencies<Self>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<JobAndDependencies<Self>> {
args.dependencies
.dependencies
@ -209,7 +210,7 @@ impl JobKind for WriteSbyFileJobKind {
.additional_args
.verilog_dialect
.get_or_insert(VerilogDialect::Yosys);
args.args_to_jobs_simple(params, |_kind, args, dependencies| {
args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| {
let FormalArgs {
sby_extra_args,
formal_mode,
@ -255,6 +256,7 @@ impl JobKind for WriteSbyFileJobKind {
job: &Self::Job,
inputs: &[JobItem],
params: &JobParams,
_global_params: &GlobalParams,
_acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>> {
assert!(inputs.iter().map(JobItem::name).eq(self.inputs(job)));
@ -351,11 +353,12 @@ impl ExternalCommand for Formal {
fn args_to_jobs(
args: JobArgsAndDependencies<ExternalCommandJobKind<Self>>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<(
Self::AdditionalJobData,
<Self::Dependencies as JobDependencies>::JobsAndKinds,
)> {
args.args_to_jobs_external_simple(params, |args, dependencies| {
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
let FormalAdditionalArgs {} = args.additional_args;
let write_sby_file = dependencies.get_job::<WriteSbyFileJob, _>().clone();
Ok(Formal {

View file

@ -2,7 +2,9 @@
// See Notices.txt for copyright information
use crate::{
build::{DynJob, JobItem, JobItemName, JobParams, program_name_for_internal_jobs},
build::{
DynJob, GlobalParams, JobItem, JobItemName, JobParams, program_name_for_internal_jobs,
},
intern::Interned,
util::{HashMap, HashSet, job_server::AcquiredJob},
};
@ -639,7 +641,7 @@ impl JobGraph {
}
retval
}
pub fn run(&self, params: &JobParams) -> eyre::Result<()> {
pub fn run(&self, params: &JobParams, global_params: &GlobalParams) -> eyre::Result<()> {
// use scope to auto-join threads on errors
thread::scope(|scope| {
struct WaitingJobState {
@ -725,13 +727,18 @@ impl JobGraph {
job: DynJob,
inputs: Vec<JobItem>,
params: &'a JobParams,
global_params: &'a GlobalParams,
acquired_job: AcquiredJob,
finished_jobs_sender: mpsc::Sender<<JobGraphInner as GraphBase>::NodeId>,
}
impl RunningJobInThread<'_> {
fn run(mut self) -> eyre::Result<Vec<JobItem>> {
self.job
.run(&self.inputs, self.params, &mut self.acquired_job)
self.job.run(
&self.inputs,
self.params,
self.global_params,
&mut self.acquired_job,
)
}
}
impl Drop for RunningJobInThread<'_> {
@ -749,6 +756,7 @@ impl JobGraph {
})
}))?,
params,
global_params,
acquired_job: AcquiredJob::acquire()?,
finished_jobs_sender: finished_jobs_sender.clone(),
};

View file

@ -4,10 +4,9 @@
use crate::{
build::{DynJobKind, JobKind, built_in_job_kinds},
intern::Interned,
util::InternedStrCompareAsStr,
};
use std::{
borrow::Borrow,
cmp::Ordering,
collections::BTreeMap,
fmt,
sync::{Arc, OnceLock, RwLock, RwLockWriteGuard},
@ -23,33 +22,6 @@ impl DynJobKind {
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
struct InternedStrCompareAsStr(Interned<str>);
impl fmt::Debug for InternedStrCompareAsStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl Ord for InternedStrCompareAsStr {
fn cmp(&self, other: &Self) -> Ordering {
str::cmp(&self.0, &other.0)
}
}
impl PartialOrd for InternedStrCompareAsStr {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Borrow<str> for InternedStrCompareAsStr {
fn borrow(&self) -> &str {
&self.0
}
}
#[derive(Clone, Debug)]
struct JobKindRegistry {
job_kinds: BTreeMap<InternedStrCompareAsStr, DynJobKind>,

View file

@ -4,8 +4,8 @@
use crate::{
build::{
BaseJob, CommandParams, DynJobKind, GetJobPositionDependencies, GetJobPositionJob,
JobAndDependencies, JobArgsAndDependencies, JobDependencies, JobItem, JobItemName, JobKind,
JobKindAndDependencies, JobParams, ToArgs, WriteArgs,
GlobalParams, JobAndDependencies, JobArgsAndDependencies, JobDependencies, JobItem,
JobItemName, JobKind, JobKindAndDependencies, JobParams, ToArgs, WriteArgs,
external::{
ExternalCommand, ExternalCommandJob, ExternalCommandJobKind, ExternalProgramTrait,
},
@ -152,11 +152,12 @@ impl ExternalCommand for UnadjustedVerilog {
fn args_to_jobs(
args: JobArgsAndDependencies<ExternalCommandJobKind<Self>>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<(
Self::AdditionalJobData,
<Self::Dependencies as JobDependencies>::JobsAndKinds,
)> {
args.args_to_jobs_external_simple(params, |args, dependencies| {
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
let UnadjustedVerilogArgs {
firtool_extra_args,
verilog_dialect,
@ -316,8 +317,9 @@ impl JobKind for VerilogJobKind {
fn args_to_jobs(
args: JobArgsAndDependencies<Self>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<JobAndDependencies<Self>> {
args.args_to_jobs_simple(params, |_kind, args, dependencies| {
args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| {
let VerilogJobArgs {} = args;
let base_job = dependencies.get_job::<BaseJob, _>();
Ok(VerilogJob {
@ -364,6 +366,7 @@ impl JobKind for VerilogJobKind {
job: &Self::Job,
inputs: &[JobItem],
_params: &JobParams,
_global_params: &GlobalParams,
_acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>> {
assert!(inputs.iter().map(JobItem::name).eq(self.inputs(job)));

View file

@ -8,10 +8,12 @@ use crate::{
module::{Module, ModuleBuilder, ModuleIO, connect_with_loc, instance_with_loc, wire_with_loc},
source_location::SourceLocation,
ty::{CanonicalType, Type},
util::HashMap,
util::{HashMap, InternedStrCompareAsStr},
};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
use std::{
any::{Any, TypeId},
borrow::Cow,
cmp::Ordering,
collections::{BTreeMap, BTreeSet},
convert::Infallible,
@ -19,13 +21,16 @@ use std::{
hash::{Hash, Hasher},
marker::PhantomData,
mem,
sync::{Arc, Mutex, MutexGuard, OnceLock},
sync::{Arc, Mutex, MutexGuard, OnceLock, RwLock, RwLockWriteGuard},
};
pub mod peripherals;
trait DynPlatformTrait: 'static + Send + Sync + fmt::Debug {
fn as_any(&self) -> &dyn Any;
fn eq_dyn(&self, other: &dyn DynPlatformTrait) -> bool;
fn hash_dyn(&self, state: &mut dyn Hasher);
fn name_dyn(&self) -> Interned<str>;
fn new_peripherals_dyn<'builder>(
&self,
builder_factory: PeripheralsBuilderFactory<'builder>,
@ -51,6 +56,10 @@ impl<T: Platform> DynPlatformTrait for T {
self.hash(&mut state);
}
fn name_dyn(&self) -> Interned<str> {
self.name()
}
fn new_peripherals_dyn<'builder>(
&self,
builder_factory: PeripheralsBuilderFactory<'builder>,
@ -155,6 +164,9 @@ impl Peripherals for DynPeripherals {
impl Platform for DynPlatform {
type Peripherals = DynPeripherals;
fn name(&self) -> Interned<str> {
DynPlatformTrait::name_dyn(&*self.0)
}
fn new_peripherals<'a>(
&self,
builder_factory: PeripheralsBuilderFactory<'a>,
@ -1033,6 +1045,7 @@ impl<'a> fmt::Debug for PlatformIOBuilder<'a> {
pub trait Platform: Clone + 'static + Send + Sync + fmt::Debug + Hash + Eq {
type Peripherals: Peripherals;
fn name(&self) -> Interned<str>;
fn new_peripherals<'builder>(
&self,
builder_factory: PeripheralsBuilderFactory<'builder>,
@ -1144,3 +1157,393 @@ pub trait Platform: Clone + 'static + Send + Sync + fmt::Debug + Hash + Eq {
.unwrap_or_else(|e: Infallible| match e {})
}
}
impl DynPlatform {
pub fn registry() -> PlatformRegistrySnapshot {
PlatformRegistrySnapshot(PlatformRegistry::get())
}
#[track_caller]
pub fn register(self) {
PlatformRegistry::register(PlatformRegistry::lock(), self);
}
}
#[derive(Clone, Debug)]
struct PlatformRegistry {
platforms: BTreeMap<InternedStrCompareAsStr, DynPlatform>,
}
enum PlatformRegisterError {
SameName {
name: InternedStrCompareAsStr,
old_platform: DynPlatform,
new_platform: DynPlatform,
},
}
impl fmt::Display for PlatformRegisterError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::SameName {
name,
old_platform,
new_platform,
} => write!(
f,
"two different `Platform` can't share the same name:\n\
{name:?}\n\
old platform:\n\
{old_platform:?}\n\
new platform:\n\
{new_platform:?}",
),
}
}
}
trait PlatformRegistryRegisterLock {
type Locked;
fn lock(self) -> Self::Locked;
fn make_mut(locked: &mut Self::Locked) -> &mut PlatformRegistry;
}
impl PlatformRegistryRegisterLock for &'static RwLock<Arc<PlatformRegistry>> {
type Locked = RwLockWriteGuard<'static, Arc<PlatformRegistry>>;
fn lock(self) -> Self::Locked {
self.write().expect("shouldn't be poisoned")
}
fn make_mut(locked: &mut Self::Locked) -> &mut PlatformRegistry {
Arc::make_mut(locked)
}
}
impl PlatformRegistryRegisterLock for &'_ mut PlatformRegistry {
type Locked = Self;
fn lock(self) -> Self::Locked {
self
}
fn make_mut(locked: &mut Self::Locked) -> &mut PlatformRegistry {
locked
}
}
impl PlatformRegistry {
fn lock() -> &'static RwLock<Arc<Self>> {
static REGISTRY: OnceLock<RwLock<Arc<PlatformRegistry>>> = OnceLock::new();
REGISTRY.get_or_init(Default::default)
}
fn try_register<L: PlatformRegistryRegisterLock>(
lock: L,
platform: DynPlatform,
) -> Result<(), PlatformRegisterError> {
use std::collections::btree_map::Entry;
let name = InternedStrCompareAsStr(platform.name());
// run user code only outside of lock
let mut locked = lock.lock();
let this = L::make_mut(&mut locked);
let result = match this.platforms.entry(name) {
Entry::Occupied(entry) => Err(PlatformRegisterError::SameName {
name,
old_platform: entry.get().clone(),
new_platform: platform,
}),
Entry::Vacant(entry) => {
entry.insert(platform);
Ok(())
}
};
drop(locked);
// outside of lock now, so we can test if it's the same DynPlatform
match result {
Err(PlatformRegisterError::SameName {
name: _,
old_platform,
new_platform,
}) if old_platform == new_platform => Ok(()),
result => result,
}
}
#[track_caller]
fn register<L: PlatformRegistryRegisterLock>(lock: L, platform: DynPlatform) {
match Self::try_register(lock, platform) {
Err(e) => panic!("{e}"),
Ok(()) => {}
}
}
fn get() -> Arc<Self> {
Self::lock().read().expect("shouldn't be poisoned").clone()
}
}
impl Default for PlatformRegistry {
fn default() -> Self {
let mut retval = Self {
platforms: BTreeMap::new(),
};
for platform in built_in_platforms() {
Self::register(&mut retval, platform);
}
retval
}
}
#[derive(Clone, Debug)]
pub struct PlatformRegistrySnapshot(Arc<PlatformRegistry>);
impl PlatformRegistrySnapshot {
pub fn get() -> Self {
PlatformRegistrySnapshot(PlatformRegistry::get())
}
pub fn get_by_name<'a>(&'a self, name: &str) -> Option<&'a DynPlatform> {
self.0.platforms.get(name)
}
pub fn iter_with_names(&self) -> PlatformRegistryIterWithNames<'_> {
PlatformRegistryIterWithNames(self.0.platforms.iter())
}
pub fn iter(&self) -> PlatformRegistryIter<'_> {
PlatformRegistryIter(self.0.platforms.values())
}
}
impl<'a> IntoIterator for &'a PlatformRegistrySnapshot {
type Item = &'a DynPlatform;
type IntoIter = PlatformRegistryIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a> IntoIterator for &'a mut PlatformRegistrySnapshot {
type Item = &'a DynPlatform;
type IntoIter = PlatformRegistryIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Clone, Debug)]
pub struct PlatformRegistryIter<'a>(
std::collections::btree_map::Values<'a, InternedStrCompareAsStr, DynPlatform>,
);
impl<'a> Iterator for PlatformRegistryIter<'a> {
type Item = &'a DynPlatform;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
fn count(self) -> usize
where
Self: Sized,
{
self.0.count()
}
fn last(self) -> Option<Self::Item> {
self.0.last()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth(n)
}
fn fold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.0.fold(init, f)
}
}
impl<'a> std::iter::FusedIterator for PlatformRegistryIter<'a> {}
impl<'a> ExactSizeIterator for PlatformRegistryIter<'a> {}
impl<'a> DoubleEndedIterator for PlatformRegistryIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth_back(n)
}
fn rfold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.0.rfold(init, f)
}
}
#[derive(Clone, Debug)]
pub struct PlatformRegistryIterWithNames<'a>(
std::collections::btree_map::Iter<'a, InternedStrCompareAsStr, DynPlatform>,
);
impl<'a> Iterator for PlatformRegistryIterWithNames<'a> {
type Item = (Interned<str>, &'a DynPlatform);
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|(name, platform)| (name.0, platform))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
fn count(self) -> usize
where
Self: Sized,
{
self.0.count()
}
fn last(self) -> Option<Self::Item> {
self.0.last().map(|(name, platform)| (name.0, platform))
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth(n).map(|(name, platform)| (name.0, platform))
}
fn fold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.0
.map(|(name, platform)| (name.0, platform))
.fold(init, f)
}
}
impl<'a> std::iter::FusedIterator for PlatformRegistryIterWithNames<'a> {}
impl<'a> ExactSizeIterator for PlatformRegistryIterWithNames<'a> {}
impl<'a> DoubleEndedIterator for PlatformRegistryIterWithNames<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0
.next_back()
.map(|(name, platform)| (name.0, platform))
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.0
.nth_back(n)
.map(|(name, platform)| (name.0, platform))
}
fn rfold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.0
.map(|(name, platform)| (name.0, platform))
.rfold(init, f)
}
}
#[track_caller]
pub fn register_platform<K: Platform>(kind: K) {
DynPlatform::new(kind).register();
}
impl Serialize for DynPlatform {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.name().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for DynPlatform {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let name = Cow::<str>::deserialize(deserializer)?;
match Self::registry().get_by_name(&name) {
Some(retval) => Ok(retval.clone()),
None => Err(D::Error::custom(format_args!(
"unknown platform: name not found in registry: {name:?}"
))),
}
}
}
#[derive(Copy, Clone, Debug, Default)]
pub struct DynPlatformValueParser;
#[derive(Clone, PartialEq, Eq, Hash)]
struct DynPlatformValueEnum {
name: Interned<str>,
platform: DynPlatform,
}
impl clap::ValueEnum for DynPlatformValueEnum {
fn value_variants<'a>() -> &'a [Self] {
Interned::into_inner(
PlatformRegistrySnapshot::get()
.iter_with_names()
.map(|(name, platform)| Self {
name,
platform: platform.clone(),
})
.collect(),
)
}
fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
Some(clap::builder::PossibleValue::new(Interned::into_inner(
self.name,
)))
}
}
impl clap::builder::TypedValueParser for DynPlatformValueParser {
type Value = DynPlatform;
fn parse_ref(
&self,
cmd: &clap::Command,
arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> clap::error::Result<Self::Value> {
clap::builder::EnumValueParser::<DynPlatformValueEnum>::new()
.parse_ref(cmd, arg, value)
.map(|v| v.platform)
}
fn possible_values(
&self,
) -> Option<Box<dyn Iterator<Item = clap::builder::PossibleValue> + '_>> {
static ENUM_VALUE_PARSER: OnceLock<clap::builder::EnumValueParser<DynPlatformValueEnum>> =
OnceLock::new();
ENUM_VALUE_PARSER
.get_or_init(clap::builder::EnumValueParser::<DynPlatformValueEnum>::new)
.possible_values()
}
}
impl clap::builder::ValueParserFactory for DynPlatform {
type Parser = DynPlatformValueParser;
fn value_parser() -> Self::Parser {
DynPlatformValueParser::default()
}
}
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = DynPlatform> {
crate::vendor::built_in_platforms()
}

View file

@ -0,0 +1,20 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::prelude::*;
use ordered_float::NotNan;
use serde::{Deserialize, Serialize};
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub struct ClockInputProperties {
pub frequency: NotNan<f64>,
}
type PhantomConstClockInputProperties = PhantomConst<ClockInputProperties>;
#[hdl(no_static)]
pub struct ClockInput {
pub clk: Clock,
pub properties: PhantomConstClockInputProperties,
}

View file

@ -33,7 +33,6 @@ pub use const_cmp::{
#[doc(inline)]
pub use scoped_ref::ScopedRef;
pub(crate) use misc::chain;
#[doc(inline)]
pub use misc::{
BitSliceWriteWithBase, DebugAsDisplay, DebugAsRawString, MakeMutSlice, RcWriter,
@ -42,6 +41,7 @@ pub use misc::{
os_str_strip_suffix, serialize_to_json_ascii, serialize_to_json_ascii_pretty,
serialize_to_json_ascii_pretty_with_indent, slice_range, try_slice_range,
};
pub(crate) use misc::{InternedStrCompareAsStr, chain};
pub mod job_server;
pub mod prefix_sum;

View file

@ -585,3 +585,30 @@ pub fn os_str_strip_suffix<'a>(os_str: &'a OsStr, suffix: impl AsRef<str>) -> Op
unsafe { OsStr::from_encoded_bytes_unchecked(bytes) }
})
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub(crate) struct InternedStrCompareAsStr(pub(crate) Interned<str>);
impl fmt::Debug for InternedStrCompareAsStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl Ord for InternedStrCompareAsStr {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
str::cmp(&self.0, &other.0)
}
}
impl PartialOrd for InternedStrCompareAsStr {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl std::borrow::Borrow<str> for InternedStrCompareAsStr {
fn borrow(&self) -> &str {
&self.0
}
}

View file

@ -6,3 +6,7 @@ pub mod xilinx;
pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = crate::build::DynJobKind> {
xilinx::built_in_job_kinds()
}
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = crate::platform::DynPlatform> {
xilinx::built_in_platforms()
}

View file

@ -1,8 +1,16 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{annotations::make_annotation_enum, intern::Interned};
use crate::{
annotations::make_annotation_enum,
build::{GlobalParams, ToArgs, WriteArgs},
intern::Interned,
};
use clap::ValueEnum;
use serde::{Deserialize, Serialize};
use std::fmt;
pub mod arty_a7;
pub mod yosys_nextpnr_prjxray;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@ -23,6 +31,157 @@ make_annotation_enum! {
}
}
pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = crate::build::DynJobKind> {
yosys_nextpnr_prjxray::built_in_job_kinds()
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
pub struct XilinxArgs {
#[arg(long)]
pub device: Option<Device>,
}
impl XilinxArgs {
pub fn require_device(&self, global_params: &GlobalParams) -> clap::error::Result<Device> {
self.device.ok_or_else(|| {
global_params.clap_error(
clap::error::ErrorKind::MissingRequiredArgument,
"missing --device option",
)
})
}
}
impl ToArgs for XilinxArgs {
fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) {
if let Some(device) = self.device {
args.write_long_option_eq("device", device.as_str());
}
}
}
macro_rules! make_device_enum {
($vis:vis enum $Device:ident {
$(
#[
name = $name:literal,
xray_part = $xray_part:literal,
xray_device = $xray_device:literal,
xray_family = $xray_family:literal,
]
$variant:ident,
)*
}) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, ValueEnum)]
$vis enum $Device {
$(
#[value(name = $name, alias = $xray_part)]
$variant,
)*
}
impl $Device {
$vis fn as_str(self) -> &'static str {
match self {
$(Self::$variant => $name,)*
}
}
$vis fn xray_part(self) -> &'static str {
match self {
$(Self::$variant => $xray_part,)*
}
}
$vis fn xray_device(self) -> &'static str {
match self {
$(Self::$variant => $xray_device,)*
}
}
$vis fn xray_family(self) -> &'static str {
match self {
$(Self::$variant => $xray_family,)*
}
}
}
struct DeviceVisitor;
impl<'de> serde::de::Visitor<'de> for DeviceVisitor {
type Value = $Device;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a Xilinx device string")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match $Device::from_str(v, false) {
Ok(v) => Ok(v),
Err(_) => Err(E::invalid_value(serde::de::Unexpected::Str(v), &self)),
}
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match str::from_utf8(v).ok().and_then(|v| $Device::from_str(v, false).ok()) {
Some(v) => Ok(v),
None => Err(E::invalid_value(serde::de::Unexpected::Bytes(v), &self)),
}
}
}
impl<'de> Deserialize<'de> for $Device {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_string(DeviceVisitor)
}
}
impl Serialize for $Device {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.as_str().serialize(serializer)
}
}
};
}
make_device_enum! {
pub enum Device {
#[
name = "xc7a35ticsg324-1L",
xray_part = "xc7a35tcsg324-1",
xray_device = "xc7a35t",
xray_family = "artix7",
]
Xc7a35ticsg324_1l,
#[
name = "xc7a100ticsg324-1L",
xray_part = "xc7a100tcsg324-1",
xray_device = "xc7a100t",
xray_family = "artix7",
]
Xc7a100ticsg324_1l,
}
}
impl fmt::Display for Device {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = crate::build::DynJobKind> {
arty_a7::built_in_job_kinds()
.into_iter()
.chain(yosys_nextpnr_prjxray::built_in_job_kinds())
}
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = crate::platform::DynPlatform> {
arty_a7::built_in_platforms()
.into_iter()
.chain(yosys_nextpnr_prjxray::built_in_platforms())
}

View file

@ -0,0 +1,81 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
intern::{Intern, Interned},
platform::{DynPlatform, PeripheralsBuilderFactory, PeripheralsBuilderFinished, Platform},
prelude::{ModuleBuilder, SourceLocation},
vendor::xilinx::Device,
};
macro_rules! arty_a7_platform {
(
$vis:vis enum $ArtyA7Platform:ident {
$(#[name = $name:literal, device = $device:ident]
$Variant:ident,)*
}
) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
$vis enum $ArtyA7Platform {
$($Variant,)*
}
impl $ArtyA7Platform {
$vis const VARIANTS: &'static [Self] = &[$(Self::$Variant,)*];
$vis fn device(self) -> Device {
match self {
$(Self::$Variant => Device::$device,)*
}
}
$vis const fn as_str(self) -> &'static str {
match self {
$(Self::$Variant => $name,)*
}
}
}
};
}
arty_a7_platform! {
pub enum ArtyA7Platform {
#[name = "arty-a7-35t", device = Xc7a35ticsg324_1l]
ArtyA7_35T,
#[name = "arty-a7-100t", device = Xc7a100ticsg324_1l]
ArtyA7_100T,
}
}
impl Platform for ArtyA7Platform {
type Peripherals = ();
fn name(&self) -> Interned<str> {
self.as_str().intern()
}
fn new_peripherals<'builder>(
&self,
builder_factory: PeripheralsBuilderFactory<'builder>,
) -> (Self::Peripherals, PeripheralsBuilderFinished<'builder>) {
let builder = builder_factory.builder();
(todo!(), builder.finish())
}
fn source_location(&self) -> SourceLocation {
SourceLocation::builtin()
}
fn add_peripherals_in_wrapper_module(&self, m: &ModuleBuilder, peripherals: Self::Peripherals) {
let () = peripherals;
}
}
pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = crate::build::DynJobKind> {
[]
}
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = DynPlatform> {
ArtyA7Platform::VARIANTS
.iter()
.map(|&v| DynPlatform::new(v))
}

View file

@ -4,8 +4,8 @@
use crate::{
annotations::Annotation,
build::{
BaseJob, CommandParams, DynJobKind, GetJobPositionDependencies, JobAndDependencies,
JobArgsAndDependencies, JobDependencies, JobItem, JobItemName, JobKind,
BaseJob, CommandParams, DynJobKind, GetJobPositionDependencies, GlobalParams,
JobAndDependencies, JobArgsAndDependencies, JobDependencies, JobItem, JobItemName, JobKind,
JobKindAndDependencies, ToArgs, WriteArgs,
external::{
ExternalCommand, ExternalCommandJob, ExternalCommandJobKind, ExternalProgramTrait,
@ -18,9 +18,10 @@ use crate::{
module::{Module, NameId},
prelude::JobParams,
util::job_server::AcquiredJob,
vendor::xilinx::{XdcIOStandardAnnotation, XdcLocationAnnotation, XilinxAnnotation},
vendor::xilinx::{
Device, XdcIOStandardAnnotation, XdcLocationAnnotation, XilinxAnnotation, XilinxArgs,
},
};
use clap::ValueEnum;
use eyre::Context;
use serde::{Deserialize, Serialize};
use std::{
@ -105,6 +106,7 @@ impl JobKind for YosysNextpnrXrayWriteYsFileJobKind {
fn args_to_jobs(
mut args: JobArgsAndDependencies<Self>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<JobAndDependencies<Self>> {
args.dependencies
.dependencies
@ -113,7 +115,7 @@ impl JobKind for YosysNextpnrXrayWriteYsFileJobKind {
.additional_args
.verilog_dialect
.get_or_insert(VerilogDialect::Yosys);
args.args_to_jobs_simple(params, |_kind, args, dependencies| {
args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| {
let YosysNextpnrXrayWriteYsFileArgs {} = args;
let base_job = dependencies.get_job::<BaseJob, _>();
let verilog_job = dependencies.get_job::<VerilogJob, _>();
@ -153,6 +155,7 @@ impl JobKind for YosysNextpnrXrayWriteYsFileJobKind {
job: &Self::Job,
inputs: &[JobItem],
params: &JobParams,
_global_params: &GlobalParams,
_acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>> {
assert!(inputs.iter().map(JobItem::name).eq(self.inputs(job)));
@ -260,11 +263,12 @@ impl ExternalCommand for YosysNextpnrXraySynth {
fn args_to_jobs(
args: JobArgsAndDependencies<ExternalCommandJobKind<Self>>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<(
Self::AdditionalJobData,
<Self::Dependencies as JobDependencies>::JobsAndKinds,
)> {
args.args_to_jobs_external_simple(params, |args, dependencies| {
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
let YosysNextpnrXraySynthArgs {} = args.additional_args;
Ok(Self {
write_ys_file: dependencies.job.job.clone(),
@ -429,6 +433,7 @@ impl JobKind for YosysNextpnrXrayWriteXdcFileJobKind {
fn args_to_jobs(
args: JobArgsAndDependencies<Self>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<JobAndDependencies<Self>> {
let firrtl_export_options = args
.dependencies
@ -439,7 +444,7 @@ impl JobKind for YosysNextpnrXrayWriteXdcFileJobKind {
.args
.args
.export_options;
args.args_to_jobs_simple(params, |_kind, args, dependencies| {
args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| {
let YosysNextpnrXrayWriteXdcFileArgs {} = args;
let base_job = dependencies.get_job::<BaseJob, _>();
Ok(YosysNextpnrXrayWriteXdcFile {
@ -474,6 +479,7 @@ impl JobKind for YosysNextpnrXrayWriteXdcFileJobKind {
job: &Self::Job,
inputs: &[JobItem],
params: &JobParams,
_global_params: &GlobalParams,
_acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>> {
assert!(inputs.iter().map(JobItem::name).eq(self.inputs(job)));
@ -508,130 +514,12 @@ impl ExternalProgramTrait for NextpnrXilinx {
}
}
macro_rules! make_device_enum {
($vis:vis enum $Device:ident {
$(
#[
name = $name:literal,
xray_part = $xray_part:literal,
xray_device = $xray_device:literal,
xray_family = $xray_family:literal,
]
$variant:ident,
)*
}) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, ValueEnum)]
$vis enum $Device {
$(
#[value(name = $name, alias = $xray_part)]
$variant,
)*
}
impl $Device {
$vis fn as_str(self) -> &'static str {
match self {
$(Self::$variant => $name,)*
}
}
$vis fn xray_part(self) -> &'static str {
match self {
$(Self::$variant => $xray_part,)*
}
}
$vis fn xray_device(self) -> &'static str {
match self {
$(Self::$variant => $xray_device,)*
}
}
$vis fn xray_family(self) -> &'static str {
match self {
$(Self::$variant => $xray_family,)*
}
}
}
struct DeviceVisitor;
impl<'de> serde::de::Visitor<'de> for DeviceVisitor {
type Value = $Device;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a Xilinx device string")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match $Device::from_str(v, false) {
Ok(v) => Ok(v),
Err(_) => Err(E::invalid_value(serde::de::Unexpected::Str(v), &self)),
}
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match str::from_utf8(v).ok().and_then(|v| $Device::from_str(v, false).ok()) {
Some(v) => Ok(v),
None => Err(E::invalid_value(serde::de::Unexpected::Bytes(v), &self)),
}
}
}
impl<'de> Deserialize<'de> for $Device {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_string(DeviceVisitor)
}
}
impl Serialize for $Device {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.as_str().serialize(serializer)
}
}
};
}
make_device_enum! {
pub enum Device {
#[
name = "xc7a35ticsg324-1L",
xray_part = "xc7a35tcsg324-1",
xray_device = "xc7a35t",
xray_family = "artix7",
]
Xc7a35ticsg324_1l,
#[
name = "xc7a100ticsg324-1L",
xray_part = "xc7a100tcsg324-1",
xray_device = "xc7a100t",
xray_family = "artix7",
]
Xc7a100ticsg324_1l,
}
}
impl fmt::Display for Device {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
pub struct YosysNextpnrXrayRunNextpnrArgs {
#[command(flatten)]
pub common: XilinxArgs,
#[arg(long, env = "CHIPDB_DIR", value_hint = clap::ValueHint::DirPath)]
pub nextpnr_xilinx_chipdb_dir: PathBuf,
#[arg(long)]
pub device: Device,
#[arg(long, default_value_t = 0)]
pub nextpnr_xilinx_seed: i32,
}
@ -639,12 +527,12 @@ pub struct YosysNextpnrXrayRunNextpnrArgs {
impl ToArgs for YosysNextpnrXrayRunNextpnrArgs {
fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) {
let Self {
common,
nextpnr_xilinx_chipdb_dir,
device,
nextpnr_xilinx_seed,
} = self;
common.to_args(args);
args.write_long_option_eq("nextpnr-xilinx-chipdb-dir", nextpnr_xilinx_chipdb_dir);
args.write_long_option_eq("device", device.as_str());
args.write_display_arg(format_args!("--nextpnr-xilinx-seed={nextpnr_xilinx_seed}"));
}
}
@ -690,14 +578,15 @@ impl ExternalCommand for YosysNextpnrXrayRunNextpnr {
fn args_to_jobs(
args: JobArgsAndDependencies<ExternalCommandJobKind<Self>>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<(
Self::AdditionalJobData,
<Self::Dependencies as JobDependencies>::JobsAndKinds,
)> {
args.args_to_jobs_external_simple(params, |args, dependencies| {
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
let YosysNextpnrXrayRunNextpnrArgs {
common,
nextpnr_xilinx_chipdb_dir,
device,
nextpnr_xilinx_seed,
} = args.additional_args;
let base_job = dependencies.get_job::<BaseJob, _>();
@ -707,7 +596,7 @@ impl ExternalCommand for YosysNextpnrXrayRunNextpnr {
let fasm_file = base_job.file_with_ext("fasm");
Ok(Self {
nextpnr_xilinx_chipdb_dir: nextpnr_xilinx_chipdb_dir.intern_deref(),
device,
device: common.require_device(global_params)?,
nextpnr_xilinx_seed,
xdc_file: write_xdc_file.xdc_file,
xdc_file_name: write_xdc_file
@ -842,11 +731,12 @@ impl ExternalCommand for YosysNextpnrXray {
fn args_to_jobs(
args: JobArgsAndDependencies<ExternalCommandJobKind<Self>>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<(
Self::AdditionalJobData,
<Self::Dependencies as JobDependencies>::JobsAndKinds,
)> {
args.args_to_jobs_external_simple(params, |args, dependencies| {
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
let YosysNextpnrXrayArgs { prjxray_db_dir } = args.additional_args;
let base_job = dependencies.get_job::<BaseJob, _>();
let frames_file = base_job.file_with_ext("frames");
@ -918,3 +808,7 @@ pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = DynJobKind> {
DynJobKind::new(ExternalCommandJobKind::<YosysNextpnrXray>::new()),
]
}
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = crate::platform::DynPlatform> {
[]
}