pub mod dslx;
pub mod dslx_bridge;
pub mod ir_package;
pub mod ir_value;
mod lib_support;
pub mod vast;
pub mod xlsynth_error;
pub mod rust_bridge_builder;
pub mod sv_bridge_builder;
use std::ffi::CString;
use ir_package::ScheduleAndCodegenResult;
pub use ir_value::{IrBits, IrSBits, IrUBits};
use lib_support::xls_schedule_and_codegen_package;
use lib_support::{c_str_to_rust, xls_mangle_dslx_name, xls_optimize_ir};
pub use ir_package::IrFunction;
pub use ir_package::IrPackage;
pub use ir_value::IrValue;
pub use xlsynth_error::XlsynthError;
use xlsynth_sys::CIrValue;
pub fn dslx_path_to_module_name(path: &std::path::Path) -> Result<&str, XlsynthError> {
let stem = path.file_stem();
match stem {
None => {
return Err(XlsynthError(
"Failed to extract module name from path".to_string(),
));
}
Some(stem) => {
return Ok(stem.to_str().unwrap());
}
}
}
pub struct DslxConvertOptions<'a> {
pub dslx_stdlib_path: Option<&'a std::path::Path>,
pub additional_search_paths: Vec<&'a std::path::Path>,
}
impl<'a> Default for DslxConvertOptions<'a> {
fn default() -> Self {
DslxConvertOptions {
dslx_stdlib_path: None,
additional_search_paths: vec![],
}
}
}
pub fn convert_dslx_to_ir_text(
dslx: &str,
path: &std::path::Path,
options: &DslxConvertOptions,
) -> Result<String, XlsynthError> {
let module_name = dslx_path_to_module_name(path)?;
let path_str = path.to_str().unwrap();
let stdlib_path = options
.dslx_stdlib_path
.unwrap_or_else(|| std::path::Path::new(xlsynth_sys::DSLX_STDLIB_PATH));
let stdlib_path = stdlib_path.to_str().unwrap();
let search_paths = options
.additional_search_paths
.iter()
.map(|p| p.to_str().unwrap())
.collect::<Vec<&str>>();
let mut search_paths_cstrs = vec![];
for p in search_paths {
search_paths_cstrs.push(CString::new(p).unwrap());
}
let dslx = CString::new(dslx).unwrap();
let c_path = CString::new(path_str).unwrap();
let c_module_name = CString::new(module_name).unwrap();
let dslx_stdlib_path = CString::new(stdlib_path).unwrap();
eprintln!("dslx_stdlib_path: {:?}", dslx_stdlib_path);
unsafe {
let additional_search_paths_ptrs: Vec<*const std::os::raw::c_char> = search_paths_cstrs
.iter()
.map(|cstr| cstr.as_ptr())
.collect();
let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
let mut ir_out: *mut std::os::raw::c_char = std::ptr::null_mut();
let success = xlsynth_sys::xls_convert_dslx_to_ir(
dslx.as_ptr(),
c_path.as_ptr(),
c_module_name.as_ptr(),
dslx_stdlib_path.as_ptr(),
additional_search_paths_ptrs.as_ptr(),
additional_search_paths_ptrs.len(),
&mut error_out,
&mut ir_out,
);
if success {
return Ok(c_str_to_rust(ir_out));
} else {
let error_out_str = c_str_to_rust(error_out);
return Err(XlsynthError(error_out_str));
}
}
}
pub fn xls_parse_typed_value(s: &str) -> Result<IrValue, XlsynthError> {
unsafe {
let c_str = CString::new(s).unwrap();
let mut ir_value_out: *mut CIrValue = std::ptr::null_mut();
let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
let success =
xlsynth_sys::xls_parse_typed_value(c_str.as_ptr(), &mut error_out, &mut ir_value_out);
if success {
return Ok(IrValue { ptr: ir_value_out });
} else {
let error_out_str: String = c_str_to_rust(error_out);
return Err(XlsynthError(error_out_str));
}
}
}
pub fn convert_dslx_to_ir(
dslx: &str,
path: &std::path::Path,
options: &DslxConvertOptions,
) -> Result<IrPackage, XlsynthError> {
let ir_text = convert_dslx_to_ir_text(dslx, path, options)?;
let filename = path.file_name().and_then(|s| s.to_str());
IrPackage::parse_ir(&ir_text, filename)
}
pub fn optimize_ir(ir: &IrPackage, top: &str) -> Result<IrPackage, XlsynthError> {
let ir_text = xls_optimize_ir(&ir.to_string(), top)?;
IrPackage::parse_ir(&ir_text, ir.filename())
}
pub fn schedule_and_codegen(
ir: &IrPackage,
scheduling_options_flags_proto: &str,
codegen_flags_proto: &str,
) -> Result<ScheduleAndCodegenResult, XlsynthError> {
let guard = ir.ptr.write().unwrap();
xls_schedule_and_codegen_package(
&ir.ptr,
guard,
scheduling_options_flags_proto,
codegen_flags_proto,
false,
)
}
pub fn mangle_dslx_name(module: &str, name: &str) -> Result<String, XlsynthError> {
xls_mangle_dslx_name(module, name)
}
fn x_path_to_rs_filename(path: &std::path::Path) -> String {
let mut out = path.file_stem().unwrap().to_str().unwrap().to_string();
out.push_str(".rs");
out
}
pub fn x_path_to_rs_bridge(
relpath: &str,
out_dir: &std::path::Path,
root_dir: &std::path::Path,
) -> std::path::PathBuf {
let mut import_data = dslx::ImportData::new(None, &[root_dir]);
let path = std::path::PathBuf::from(relpath);
let dslx =
std::fs::read_to_string(&path).expect(&format!("DSLX file should be readable: {path:?}"));
let mut builder = rust_bridge_builder::RustBridgeBuilder::new();
dslx_bridge::convert_leaf_module(&mut import_data, &dslx, &path, &mut builder)
.expect("expect bridge building success");
let rs = builder.build();
let out_path = out_dir.join(x_path_to_rs_filename(&path));
std::fs::write(&out_path, rs).unwrap();
out_path
}
pub fn x_path_to_rs_bridge_via_env(relpath: &str) -> std::path::PathBuf {
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR should be set");
let metadata = cargo_metadata::MetadataCommand::new()
.exec()
.expect("cargo metadata should be available");
let root_dir = metadata.workspace_root.as_path().as_std_path();
x_path_to_rs_bridge(relpath, std::path::Path::new(&out_dir), root_dir)
}
#[cfg(test)]
mod tests {
use lib_support::xls_format_preference_from_string;
use xlsynth_sys::XlsFormatPreference;
use super::*;
#[test]
fn test_convert_dslx_to_ir() {
let ir = convert_dslx_to_ir_text(
"fn f(x: u32) -> u32 { x }",
std::path::Path::new("/memfile/test_mod.x"),
&DslxConvertOptions::default(),
)
.expect("ir conversion should succeed");
assert_eq!(
ir,
"package test_mod
file_number 0 \"/memfile/test_mod.x\"
fn __test_mod__f(x: bits[32] id=1) -> bits[32] {
ret x: bits[32] = param(name=x, id=1)
}
"
);
}
#[test]
fn test_parse_typed_value_garbage() {
let e: XlsynthError = xls_parse_typed_value("asdf").expect_err("should not parse");
assert_eq!(
e.0,
"INVALID_ARGUMENT: Expected token of type \"(\" @ 1:1, but found: Token(\"ident\", value=\"asdf\") @ 1:1"
);
}
#[test]
fn test_parse_typed_value_bits32_42() {
let v: IrValue = xls_parse_typed_value("bits[32]:42").expect("should parse ok");
assert_eq!(v.to_string(), "bits[32]:42");
}
#[test]
fn test_xls_format_preference_from_string() {
let fmt: XlsFormatPreference = xls_format_preference_from_string("default")
.expect("should convert to format preference");
assert_eq!(fmt, 0);
let fmt: XlsFormatPreference =
xls_format_preference_from_string("hex").expect("should convert to format preference");
assert_eq!(fmt, 4);
xls_format_preference_from_string("blah")
.expect_err("should not convert to format preference");
}
}