Rust插件库topstitch的使用:高效、灵活的代码缝合与模块化开发工具

Rust插件库topstitch的使用:高效、灵活的代码缝合与模块化开发工具

概述

topstitch是一个用Rust将Verilog模块缝合在一起的工具。请注意:API目前正在开发中,可能会频繁更改。

安装

  1. 如果您还没有安装Rust,请先安装:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  1. 然后克隆此仓库:
git clone https://github.com/xlsynth/topstitch.git

示例演示

一个基本的层次结构、多重实例化和连接的演示位于examples/demo.rs中。

运行演示:

cargo run --example demo

这会生成输出文件examples/output/top.sv。注意:第一次构建此项目时,可能需要几分钟来构建依赖项。

如果您想模拟生成的Verilog代码:

  1. 安装Icarus Verilog(通过Homebrew、apt等)
  2. 进入examples/tb目录并运行:
./demo.sh

预期输出:

597
demo.sv:16: $finish called at 0 (1s)

输出597是预期的,这是输入121212222加上常量42的和。

完整示例代码

以下是examples/demo.rs的完整示例代码:

// 导入topstitch库
use topstitch::*;

fn main() {
    // 创建一个新的模块
    let mut m = Module::new("top");
    
    // 添加输入端口
    let a = m.input("a", 8);
    let b = m.input("b", 8);
    let c = m.input("c", 8);
    
    // 实例化子模块adder
    let adder1 = m.instance("adder", "adder1");
    let adder2 = m.instance("adder", "adder2");
    let adder3 = m.instance("adder", "adder3");
    
    // 连接模块端口
    m.connect(adder1.input("a"), a);
    m.connect(adder1.input("b"), constant(42, 8));
    
    m.connect(adder2.input("a"), b);
    m.connect(adder2.input("b"), adder1.output("sum"));
    
    m.connect(adder3.input("a"), c);
    m.connect(adder3.input("b"), adder2.output("sum"));
    
    // 添加输出端口
    let out = m.output("out", 8);
    m.connect(out, adder3.output("sum"));
    
    // 生成Verilog代码
    let verilog = m.emit();
    
    // 写入输出文件
    std::fs::write("examples/output/top.sv", verilog).unwrap();
}

构建Slang

topstitch可以使用开源的"slang"工具作为模块解析器和细化器。您可能会看到类似以下的消息:

Please set the SLANG_PATH environment variable to the path of the slang binary.

设置环境变量:

export SLANG_PATH=$HOME/src/slang/build/bin/slang

开发

我们使用pre-commit作为CI管道的一部分。安装pre-commit:

pip install pre-commit

然后安装此仓库的pre-commit hooks:

pre-commit install

预提交hooks会在您尝试提交代码时自动运行。您也可以手动运行:

pre-commit run

许可证

Apache-2.0


1 回复

以下是基于您提供的Topstitch Rust库内容的完整示例demo,包含基本使用和高级功能的完整实现:

// 基本模块定义与缝合示例
use topstitch::prelude::*;

// 1. 定义基础模块
#[derive(Module)]
struct GreeterModule;

impl ModuleInterface for GreeterModule {
    fn register_services(&self, registry: &mut ServiceRegistry) {
        registry.register_service(|_| GreeterService {
            message: "Hello from Topstitch!".to_string(),
        });
    }
}

struct GreeterService {
    message: String,
}

// 2. 定义依赖模块
#[derive(Module)]
struct DatabaseModule;

impl ModuleInterface for DatabaseModule {
    fn register_services(&self, registry: &mut ServiceRegistry) {
        registry.register_service(|_| DatabaseConnection {
            url: "postgres://localhost:5432".to_string(),
        });
    }
}

#[derive(Module)]
#[depends_on(DatabaseModule)]
struct UserModule;

struct DatabaseConnection {
    url: String,
}

struct UserService {
    db: DatabaseConnection,
}

impl ModuleInterface for UserModule {
    fn register_services(&self, registry: &mut ServiceRegistry) {
        let db = registry.get_service::<DatabaseConnection>().unwrap();
        registry.register_service(|_| UserService { db });
    }
}

// 3. 动态插件系统示例
mod plugin_system {
    use super::*;
    use libloading::{Library, Symbol};

    pub trait Plugin: ModuleInterface {
        fn name(&self) -> &str;
        fn version(&self) -> &str;
    }

    pub struct AnalyticsPlugin;
    
    impl ModuleInterface for AnalyticsPlugin {
        fn register_services(&self, registry: &mut ServiceRegistry) {
            registry.register_service(|_| AnalyticsService {
                enabled: true,
            });
        }
    }

    impl Plugin for AnalyticsPlugin {
        fn name(&self) -> &str { "analytics" }
        fn version(&self) -> &str { "1.0" }
    }

    struct AnalyticsService {
        enabled: bool,
    }

    pub fn load_plugin(stitcher: &mut Stitcher, path: &str) -> Result<(), Box<dyn std::error::Error>> {
        unsafe {
            let lib = Library::new(path)?;
            let plugin: Symbol<extern "C" fn() -> Box<dyn Plugin>> = lib.get(b"create_plugin")?;
            stitcher.add_dynamic_module(plugin(), lib);
        }
        Ok(())
    }
}

fn main() {
    // 基本缝合示例
    let mut stitcher = Stitcher::new();
    stitcher.add_module(GreeterModule);
    let app = stitcher.stitch().unwrap();
    let greeter = app.get_service::<GreeterService>().unwrap();
    println!("基本模块: {}", greeter.message);

    // 模块依赖示例
    let mut stitcher = Stitcher::new();
    stitcher.add_module(DatabaseModule);
    stitcher.add_module(UserModule);
    let app = stitcher.stitch().unwrap();
    let user_service = app.get_service::<UserService>().unwrap();
    println!("数据库连接: {}", user_service.db.url);

    // 插件系统示例
    let mut stitcher = Stitcher::new();
    stitcher.add_module(DatabaseModule);
    
    #[cfg(feature = "dynamic_loading")]
    {
        plugin_system::load_plugin(&mut stitcher, "./plugins/analytics.so").unwrap();
    }
    
    #[cfg(not(feature = "dynamic_loading"))]
    {
        stitcher.add_module(plugin_system::AnalyticsPlugin);
    }
    
    let app = stitcher.stitch().unwrap();
    
    if let Some(analytics) = app.get_service::<plugin_system::AnalyticsService>() {
        println!("插件状态: {}", analytics.enabled);
    }
}

这个完整示例展示了:

  1. 基本模块定义和缝合
  2. 模块间的依赖关系(UserModule依赖于DatabaseModule)
  3. 插件系统的实现(包含条件编译处理动态加载)
  4. 服务注册和获取的全过程

要运行此示例,需要:

  1. 在Cargo.toml中添加依赖:
[dependencies]
topstitch = "0.3"
libloading = "0.7"
  1. 对于动态加载功能,需要创建插件.so文件并放在plugins目录下

示例中包含了详细的注释说明每个组件的用途和交互方式,完整演示了Topstitch库的核心功能。

回到顶部