3 个不稳定版本
0.3.0 | 2019 年 3 月 19 日 |
---|---|
0.2.1 | 2019 年 3 月 18 日 |
0.2.0 | 2019 年 2 月 28 日 |
在 模拟器 中排名 #115
每月下载量 48 次
27KB
586 行
ModVM-Rust
ModVM 为在 Rust 中构建虚拟机提供了一个简单的框架。ModVM 中的虚拟机是模块化的,并且为此目的由两种不同类型的组件组成:处理器和外围设备。
执行模型
虚拟机初始化时带有处理器向量和外设向量,并自动构建每个处理器和外设之间的通信通道。处理器在其 exe_ins()
函数中向下发送请求,该函数在循环中被调用。当任何外围设备通过通道接收数据时,它的 handle(request)
函数被调用,并返回供处理器使用的数据。
初始化后,虚拟机返回一个 MachineHandle
结构体,它可以用来加入虚拟机的线程。
用法
双向通道结构体
modVM
包实现了 TwoWayChannel<I, O>
结构体,以便在虚拟机组件之间进行轻松通信。
TwoWayChannel
总是成对实例化,并且每一对 ('end') 包含两个通道,用于通过通道进行双向通信。它接受以下方法:
send
- 通过通道发送数据。recv
- 等待下一个项目,然后返回它。try_recv
- 测试在通道队列中找到项目;如果找到它,则返回它。iter
-recv
的循环版本。try_iter
-try_recv
的循环版本。query
- 通过通道发送数据,然后等待直到收到回复,然后返回它。
在内部,处理器使用类型 modVM::Query
发出请求,而外设则使用 modVM::Response
进行响应。
处理器特质
Processor<BASE>
特质要求在结构体上实现 exe_ins()
函数。此函数必须接受一个 FrontEnd<BASE>
(TwoWayChannel<Query<BASE>>
的包装器)的向量以及 &mut self
,并返回 Result<(), BASE>
。如果处理器中的任何函数返回 Err
,则处理器会终止。
一个简单的实现可能是
impl Processor<u8> for ProcessorEightBit {
fn exe_ins(&mut self, channels: &Vec<FrontEnd<u16>>) -> Result<(), u8> {
// get instruction:
let ins = channels[0].query(LoadRequest(self.counter)).unwrap();
match ins {
/* snip */
// instruction didn't match:
_ => Err(0),
}
}
}
外设特质
Peripheral<BASE>
特质与网络服务器的操作类似:其主要目的是发送和接收数据请求。这是通过 handle()
函数实现的,该函数接受一个 Query
枚举请求并输出一个 Result<Response<BASE>, BASE>
,如果为 Ok
,则解包并沿通道发送回。这种灵活性为 ModVM 快速创建不同的虚拟机组件提供了广阔的天地。每次外设收到请求时都会调用 handle()
函数。
一个简单的实现可能是
impl Peripheral<u8> for MemEightBit {
fn handle(&mut self, incoming: Query<u16>) -> Result<Response<u16>, u16> {
Ok(match incoming {
LoadRequest(x) => {
match self.mem.get(x as usize) {
Some(y) => {
Data(*y)
},
None => Fail(0),
}
},
SaveRequest(x, y) => {
match self.mem.get_mut(x as usize) {
Some(z) => {
*z = y;
Good
},
None => Fail(0),
}
},
})
}
}
然而,Peripheral
不仅限于内存。例如,您可以配置一个作为 GPU,或处理 I/O。为此,可以使用可选的 cycle
函数来运行每个周期都需要活跃的过程。但是,此函数只能修改组件的状态。
共享函数
上述所有特质都共享某些函数:metadata
、boot
和 halt
。元数据 metadata
指定了虚拟机的数据,并返回一个 Metadata
结构体。这用于线程的标识。 boot
和 halt
比较直观;它们在启动和终止后运行,在 Processor
中,函数可以访问通道,因此可以发出数据请求。然而,在这些函数中,只有 metadata
函数是编译所必需的。
以下是在 Processor
上实现所有这些函数的示例
impl Processor<u8> for ProcessorEightBit {
fn boot(&mut self, channels: &Vec<FrontEnd<u8>>) -> Result<(), BASE> {
channels[0].query(SaveRequest(PRINT, self.bootcode)).unwrap(); // print the bootcode
Ok(())
}
fn halt(&mut self, channels: &Vec<FrontEnd<u8>>) -> Result<(), BASE> {
channels[0].query(SaveRequest(PRINT, self.error)).unwrap(); // print the error message
for i in channels {
i.send(LoadRequest(HALT)); // halt all peripherals
}
}
}
以及在外设上的实现
impl Peripheral<u8> for MemEightBit {
fn boot(&mut self) -> Result<(), BASE> {
/* initialise things */
Ok(())
}
fn halt(&mut self) -> Result<(), BASE> {
/* halt processes */
Ok(())
}
}