Rust插件库topstitch的使用:高效、灵活的代码缝合与模块化开发工具
Rust插件库topstitch的使用:高效、灵活的代码缝合与模块化开发工具
概述
topstitch是一个用Rust将Verilog模块缝合在一起的工具。请注意:API目前正在开发中,可能会频繁更改。
安装
- 如果您还没有安装Rust,请先安装:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
- 然后克隆此仓库:
git clone https://github.com/xlsynth/topstitch.git
示例演示
一个基本的层次结构、多重实例化和连接的演示位于examples/demo.rs
中。
运行演示:
cargo run --example demo
这会生成输出文件examples/output/top.sv
。注意:第一次构建此项目时,可能需要几分钟来构建依赖项。
如果您想模拟生成的Verilog代码:
- 安装Icarus Verilog(通过Homebrew、apt等)
- 进入
examples/tb
目录并运行:
./demo.sh
预期输出:
597
demo.sv:16: $finish called at 0 (1s)
输出597
是预期的,这是输入121
、212
和222
加上常量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);
}
}
这个完整示例展示了:
- 基本模块定义和缝合
- 模块间的依赖关系(UserModule依赖于DatabaseModule)
- 插件系统的实现(包含条件编译处理动态加载)
- 服务注册和获取的全过程
要运行此示例,需要:
- 在Cargo.toml中添加依赖:
[dependencies]
topstitch = "0.3"
libloading = "0.7"
- 对于动态加载功能,需要创建插件.so文件并放在plugins目录下
示例中包含了详细的注释说明每个组件的用途和交互方式,完整演示了Topstitch库的核心功能。