Lua wrapper for CPU
This commit is contained in:
Generated
+1
@@ -7,6 +7,7 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/vemu/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/vasm/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/vtest/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/vlua/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
|
||||
Generated
+63
@@ -82,6 +82,15 @@ dependencies = [
|
||||
"byte-tools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.9.1"
|
||||
@@ -573,6 +582,24 @@ dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lua-src"
|
||||
version = "544.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "708ba3c844d5e9d38def4a09dd871c17c370f519b3c4b7261fbabe4a613a814c"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "luajit-src"
|
||||
version = "210.3.4+resty073ac54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "640b09e99575a442b4da0ef406a78188a1a4313bb9ead7b5b20ec12cc480130f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
@@ -655,6 +682,34 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mlua"
|
||||
version = "0.8.0-beta.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea2403730bdaac13f5e84034a324b61723d5d540b85aebc0f237e0028eb58053"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"cc",
|
||||
"lua-src",
|
||||
"luajit-src",
|
||||
"mlua_derive",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"pkg-config",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mlua_derive"
|
||||
version = "0.8.0-beta.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd3dfb62b95873e3d7aa9a691905287992628e3c10cadce5ed88f15134e3b0ce"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "0.8.5"
|
||||
@@ -1229,6 +1284,14 @@ version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "vlua"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"mlua",
|
||||
"vcore",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vtest"
|
||||
version = "0.1.0"
|
||||
|
||||
+2
-1
@@ -4,5 +4,6 @@ members = [
|
||||
"vcore",
|
||||
"vemu",
|
||||
"vasm",
|
||||
"vtest"
|
||||
"vtest",
|
||||
"vlua"
|
||||
]
|
||||
+24
-10
@@ -64,6 +64,11 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_random() -> Self {
|
||||
let rng = rand::thread_rng();
|
||||
Self::new(Memory::from(rng))
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.pc = 1024.into();
|
||||
self.dp = 256.into();
|
||||
@@ -75,22 +80,22 @@ impl CPU {
|
||||
self.dp_btm = 0x100.into();
|
||||
}
|
||||
|
||||
fn push_data<A: Into<Word>>(&mut self, word: A) {
|
||||
pub fn push_data<A: Into<Word>>(&mut self, word: A) {
|
||||
self.memory.poke24(self.dp, word);
|
||||
self.dp += 3;
|
||||
}
|
||||
|
||||
fn push_call<A: Into<Word>>(&mut self, word: A) {
|
||||
pub fn push_call<A: Into<Word>>(&mut self, word: A) {
|
||||
self.sp -= 3;
|
||||
self.memory.poke24(self.sp, word);
|
||||
}
|
||||
|
||||
fn pop_data(&mut self) -> Word {
|
||||
pub fn pop_data(&mut self) -> Word {
|
||||
self.dp -= 3;
|
||||
self.memory.peek24(self.dp)
|
||||
}
|
||||
|
||||
fn pop_call(&mut self) -> Word {
|
||||
pub fn pop_call(&mut self) -> Word {
|
||||
let val = self.memory.peek24(self.sp);
|
||||
self.sp += 3;
|
||||
val
|
||||
@@ -150,8 +155,8 @@ impl CPU {
|
||||
Opcode::Add => self.push_data(x + y),
|
||||
Opcode::Sub => self.push_data(y - x),
|
||||
Opcode::Mul => self.push_data(y * x),
|
||||
Opcode::Div => self.push_data(y / x),
|
||||
Opcode::Mod => self.push_data(y % x),
|
||||
Opcode::Div => self.push_data(i32::from(y) / i32::from(x)),
|
||||
Opcode::Mod => self.push_data(i32::from(y) % i32::from(x)),
|
||||
Opcode::And => self.push_data(y & x),
|
||||
Opcode::Or => self.push_data(y | x),
|
||||
Opcode::Xor => self.push_data(y ^ x),
|
||||
@@ -412,9 +417,9 @@ impl CPU {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn interrupt(&mut self, int: usize, arg: Option<Word>) {
|
||||
if int >= self.iv.len() {
|
||||
panic!("Invalid interrupt: {}", int)
|
||||
pub fn interrupt(&mut self, irq: usize, arg: Option<Word>) {
|
||||
if irq >= self.iv.len() {
|
||||
panic!("Invalid interrupt: {}", irq)
|
||||
}
|
||||
if self.int_enabled {
|
||||
if self.halted {
|
||||
@@ -429,7 +434,7 @@ impl CPU {
|
||||
if let Some(val) = arg {
|
||||
self.push_data(val)
|
||||
}
|
||||
self.iv[int]
|
||||
self.iv[irq]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -472,6 +477,14 @@ impl CPU {
|
||||
pub fn sdp(&self) -> (Word, Word) {
|
||||
(self.sp, self.dp)
|
||||
}
|
||||
pub fn pc(&self) -> Word { self.pc }
|
||||
pub fn sp(&self) -> Word { self.sp }
|
||||
pub fn dp(&self) -> Word { self.dp }
|
||||
pub fn dp_btm(&self) -> Word { self.dp_btm }
|
||||
pub fn sp_top(&self) -> Word { self.sp_top }
|
||||
pub fn set_pc(&mut self, new_pc: Word) { self.pc = new_pc; }
|
||||
pub fn halted(&self) -> bool { self.halted }
|
||||
pub fn int_enabled(&self) -> bool { self.int_enabled }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -592,6 +605,7 @@ mod tests {
|
||||
simple_opcode_test(vec![5, 3], Mul, vec![15]);
|
||||
simple_opcode_test(vec![8, 3], Div, vec![2]);
|
||||
simple_opcode_test(vec![10, 3], Mod, vec![1]);
|
||||
simple_opcode_test(vec![12, to_word(-3)], Div, vec![to_word(-4)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "vlua"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
vcore = { path = "../vcore" }
|
||||
mlua = { version = "0.8.0-beta.4", features = ["lua54", "vendored", "module"] }
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
use mlua::prelude::*;
|
||||
use vcore::{ CPU, Word };
|
||||
use mlua::{UserData, UserDataMethods};
|
||||
use vcore::memory::{PeekPoke, PeekPokeExt};
|
||||
use std::iter::FromIterator;
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn libvlua(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let exports = lua.create_table()?;
|
||||
let cpu_constructor = lua.create_function(|_, _: ()| Ok(LuaCPU(CPU::new_random())))?;
|
||||
exports.set("new", cpu_constructor)?;
|
||||
Ok(exports)
|
||||
}
|
||||
|
||||
struct LuaCPU(CPU);
|
||||
|
||||
impl UserData for LuaCPU {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_method_mut("reset", |_, lcpu, ()| {
|
||||
lcpu.0.reset();
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method_mut("push_data", |_, lcpu, num: i32| {
|
||||
lcpu.0.push_data(Word::from(num));
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method_mut("pop_data", |_, lcpu, ()| {
|
||||
let d = lcpu.0.pop_data();
|
||||
Ok(u32::from(d))
|
||||
});
|
||||
|
||||
methods.add_method_mut("push_call", |_, lcpu, num: i32| {
|
||||
lcpu.0.push_call(Word::from(num));
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method_mut("pop_call", |_, lcpu, ()| {
|
||||
let d = lcpu.0.pop_call();
|
||||
Ok(u32::from(d))
|
||||
});
|
||||
|
||||
methods.add_method_mut("poke", |_, lcpu, (addr, val): (u32, u8)| {
|
||||
lcpu.0.poke(Word::from(addr), val);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method("peek", |_, lcpu, addr: u32| {
|
||||
let b = lcpu.0.peek(Word::from(addr));
|
||||
Ok(b)
|
||||
});
|
||||
|
||||
methods.add_method_mut("poke24", |_, lcpu, (addr, val): (u32, i32)| {
|
||||
lcpu.0.poke24(Word::from(addr), Word::from(val));
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method("peek24", |_, lcpu, addr: u32| {
|
||||
let b = lcpu.0.peek24(Word::from(addr));
|
||||
Ok(u32::from(b))
|
||||
});
|
||||
|
||||
methods.add_method("pc", |_, lcpu, ()| {
|
||||
Ok(u32::from(lcpu.0.pc()))
|
||||
});
|
||||
|
||||
methods.add_method("sp", |_, lcpu, ()| {
|
||||
Ok(u32::from(lcpu.0.sp()))
|
||||
});
|
||||
|
||||
methods.add_method("dp", |_, lcpu, ()| {
|
||||
Ok(u32::from(lcpu.0.dp()))
|
||||
});
|
||||
|
||||
methods.add_method_mut("set_pc", |_, lcpu, val: u32| {
|
||||
lcpu.0.set_pc(Word::from(val));
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method("print_stack", |_, lcpu, ()| {
|
||||
let (btm, dp) = (lcpu.0.dp_btm(), lcpu.0.dp());
|
||||
if dp == btm {
|
||||
println!("<stack empty>")
|
||||
} else {
|
||||
let mut curr = btm;
|
||||
while curr < dp {
|
||||
let w = lcpu.0.peek24(curr);
|
||||
println!("{:#08x}:\t{:#08x} {}", u32::from(curr), u32::from(w), i32::from(w));
|
||||
curr += 3;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method("print_r_stack", |_, lcpu, ()| {
|
||||
let (top, sp) = (lcpu.0.sp_top(), lcpu.0.sp());
|
||||
if sp == top {
|
||||
println!("<stack empty>")
|
||||
} else {
|
||||
let mut curr = top - 3;
|
||||
while curr >= sp {
|
||||
let w = lcpu.0.peek24(curr);
|
||||
println!("{:#08x}:\t{:#08x} {}", u32::from(curr), u32::from(w), i32::from(w));
|
||||
curr -= 3;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method("stack", |_, lcpu, ()| {
|
||||
Ok(Vec::from_iter(lcpu.0.get_stack().into_iter().map(|w| u32::from(w))))
|
||||
});
|
||||
|
||||
methods.add_method("r_stack", |_, lcpu, ()| {
|
||||
Ok(Vec::from_iter(lcpu.0.get_call().into_iter().map(|w| u32::from(w))))
|
||||
});
|
||||
|
||||
methods.add_method_mut("run", |_, lcpu, ()| {
|
||||
lcpu.0.run_to_halt();
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method("flags", |_, lcpu, ()| {
|
||||
Ok((lcpu.0.halted(), lcpu.0.int_enabled()))
|
||||
});
|
||||
|
||||
methods.add_method_mut("interrupt", |_, lcpu, (irq, arg): (u8, Option<i32>)| {
|
||||
lcpu.0.interrupt(irq as usize, arg.map(|n| Word::from(n)));
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user