Skip to content

Commit 245e303

Browse files
committed
feat(script): add Xcelium script format support
Add `bender script xcelium` command that generates a flat .f file for Cadence Xcelium/xrun. Per-group incdirs, defines, and source files are emitted directly — consistent with the vsim and vcs templates. Also adds a global `--incdir` / `-I` flag to inject user-provided include directories into both the global incdir list and each per-source-group's incdirs. Other changes: - Add `name` field to TplSrcStruct (from src.package) - Add `root_package` to template context - Support `--relative-path` for $ROOT-relative output - Sanitize library names (hyphens to underscores) in group names
1 parent 8c98d8b commit 245e303

2 files changed

Lines changed: 38 additions & 1 deletion

File tree

src/cmd/script.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ pub struct ScriptArgs {
3434
#[arg(short = 'D', long, action = ArgAction::Append, global = true, help_heading = "General Script Options")]
3535
pub define: Vec<String>,
3636

37+
/// Add an include directory
38+
#[arg(short = 'I', long, action = ArgAction::Append, global = true, help_heading = "General Script Options")]
39+
pub incdir: Vec<String>,
40+
3741
/// Remove source annotations from the generated script
3842
#[arg(long, help_heading = "General Script Options")]
3943
pub no_source_annotations: bool,
@@ -179,6 +183,12 @@ pub enum ScriptFormat {
179183
#[arg(long, action = ArgAction::Append, alias = "vcom-arg")]
180184
vcom_args: Vec<String>,
181185
},
186+
/// Cadence Xcelium script
187+
Xcelium {
188+
/// Use relative paths
189+
#[arg(long)]
190+
relative_path: bool,
191+
},
182192
/// Cadence Genus script
183193
Genus,
184194
/// Xilinx Vivado synthesis script
@@ -246,6 +256,7 @@ pub fn run(sess: &Session, args: &ScriptArgs) -> Result<()> {
246256
ScriptFormat::Synopsys { .. } => vec!["synopsys", "synthesis"],
247257
ScriptFormat::Formality => vec!["synopsys", "synthesis", "formality"],
248258
ScriptFormat::Riviera { .. } => vec!["riviera", "simulation"],
259+
ScriptFormat::Xcelium { .. } => vec!["xcelium", "simulation"],
249260
ScriptFormat::Genus => vec!["genus", "synthesis"],
250261
ScriptFormat::Vivado { .. } => concat(vivado_targets, &["synthesis"]),
251262
ScriptFormat::VivadoSim { .. } => concat(vivado_targets, &["simulation"]),
@@ -366,6 +377,10 @@ pub fn run(sess: &Session, args: &ScriptArgs) -> Result<()> {
366377
tera_context.insert("vcom_args", vcom_args);
367378
include_str!("../script_fmt/riviera_tcl.tera")
368379
}
380+
ScriptFormat::Xcelium { relative_path } => {
381+
tera_context.insert("relativize_path", relative_path);
382+
include_str!("../script_fmt/xcelium_f.tera")
383+
}
369384
ScriptFormat::Genus => include_str!("../script_fmt/genus_tcl.tera"),
370385
ScriptFormat::Vivado { no_simset, only } | ScriptFormat::VivadoSim { no_simset, only } => {
371386
only_args = only.clone();
@@ -439,6 +454,7 @@ fn emit_template(
439454
) -> Result<()> {
440455
tera_context.insert("HEADER_AUTOGEN", HEADER_AUTOGEN);
441456
tera_context.insert("root", sess.root);
457+
tera_context.insert("root_package", &sess.manifest.package.name);
442458
// tera_context.insert("srcs", &srcs);
443459
tera_context.insert("abort_on_error", &!args.no_abort_on_error);
444460

@@ -478,8 +494,13 @@ fn emit_template(
478494
tera_context.insert("all_defines", &all_defines);
479495

480496
all_incdirs.sort();
497+
let user_incdirs: Vec<PathBuf> = args.incdir.iter().map(PathBuf::from).collect();
481498
let all_incdirs: IndexSet<PathBuf> = if emit_incdirs {
482-
all_incdirs.into_iter().map(|p| p.to_path_buf()).collect()
499+
all_incdirs
500+
.into_iter()
501+
.map(|p| p.to_path_buf())
502+
.chain(user_incdirs.iter().cloned())
503+
.collect()
483504
} else {
484505
IndexSet::new()
485506
};
@@ -507,6 +528,7 @@ fn emit_template(
507528
},
508529
|src, ty, files| {
509530
split_srcs.push(TplSrcStruct {
531+
name: src.package.map(|s| s.to_string()),
510532
metadata: {
511533
let package = src.package.unwrap_or("None");
512534
let target = src.target.reduce().to_string();
@@ -530,6 +552,7 @@ fn emit_template(
530552
.iter()
531553
.map(|p| p.to_path_buf())
532554
.collect::<IndexSet<_>>();
555+
incdirs.extend(user_incdirs.iter().cloned());
533556
incdirs.sort();
534557
incdirs
535558
},
@@ -597,6 +620,7 @@ fn emit_template(
597620

598621
#[derive(Debug, Serialize)]
599622
struct TplSrcStruct {
623+
name: Option<String>,
600624
metadata: String,
601625
defines: IndexSet<(String, Option<String>)>,
602626
incdirs: IndexSet<PathBuf>,

src/script_fmt/xcelium_f.tera

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# {{ HEADER_AUTOGEN }}
2+
{%- for group in srcs %}
3+
{% if source_annotations %}# {{ group.metadata }}{% endif %}
4+
{%- for incdir in group.incdirs %}
5+
+incdir+{% if relativize_path and incdir is starting_with(root) %}{{ incdir | replace(from=root, to='$ROOT') }}{% else %}{{ incdir }}{% endif %}
6+
{%- endfor %}
7+
{%- for define in group.defines %}
8+
+define+{{ define.0 }}{% if define.1 %}={{ define.1 }}{% endif %}
9+
{%- endfor %}
10+
{%- for file in group.files %}
11+
{% if relativize_path and file is starting_with(root) %}{{ file | replace(from=root, to='$ROOT') }}{% else %}{{ file }}{% endif %}
12+
{%- endfor %}
13+
{%- endfor %}

0 commit comments

Comments
 (0)