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$/vemu/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/vasm/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$/vtest/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/vlua/src" isTestSource="false" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
|||||||
Generated
+63
@@ -82,6 +82,15 @@ dependencies = [
|
|||||||
"byte-tools",
|
"byte-tools",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bstr"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.9.1"
|
version = "3.9.1"
|
||||||
@@ -573,6 +582,24 @@ dependencies = [
|
|||||||
"cfg-if 1.0.0",
|
"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]]
|
[[package]]
|
||||||
name = "malloc_buf"
|
name = "malloc_buf"
|
||||||
version = "0.0.6"
|
version = "0.0.6"
|
||||||
@@ -655,6 +682,34 @@ dependencies = [
|
|||||||
"winapi",
|
"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]]
|
[[package]]
|
||||||
name = "naga"
|
name = "naga"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
@@ -1229,6 +1284,14 @@ version = "0.9.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vlua"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"mlua",
|
||||||
|
"vcore",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vtest"
|
name = "vtest"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|||||||
+2
-1
@@ -4,5 +4,6 @@ members = [
|
|||||||
"vcore",
|
"vcore",
|
||||||
"vemu",
|
"vemu",
|
||||||
"vasm",
|
"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) {
|
pub fn reset(&mut self) {
|
||||||
self.pc = 1024.into();
|
self.pc = 1024.into();
|
||||||
self.dp = 256.into();
|
self.dp = 256.into();
|
||||||
@@ -75,22 +80,22 @@ impl CPU {
|
|||||||
self.dp_btm = 0x100.into();
|
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.memory.poke24(self.dp, word);
|
||||||
self.dp += 3;
|
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.sp -= 3;
|
||||||
self.memory.poke24(self.sp, word);
|
self.memory.poke24(self.sp, word);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_data(&mut self) -> Word {
|
pub fn pop_data(&mut self) -> Word {
|
||||||
self.dp -= 3;
|
self.dp -= 3;
|
||||||
self.memory.peek24(self.dp)
|
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);
|
let val = self.memory.peek24(self.sp);
|
||||||
self.sp += 3;
|
self.sp += 3;
|
||||||
val
|
val
|
||||||
@@ -150,8 +155,8 @@ impl CPU {
|
|||||||
Opcode::Add => self.push_data(x + y),
|
Opcode::Add => self.push_data(x + y),
|
||||||
Opcode::Sub => self.push_data(y - x),
|
Opcode::Sub => self.push_data(y - x),
|
||||||
Opcode::Mul => self.push_data(y * x),
|
Opcode::Mul => self.push_data(y * x),
|
||||||
Opcode::Div => self.push_data(y / x),
|
Opcode::Div => self.push_data(i32::from(y) / i32::from(x)),
|
||||||
Opcode::Mod => self.push_data(y % x),
|
Opcode::Mod => self.push_data(i32::from(y) % i32::from(x)),
|
||||||
Opcode::And => self.push_data(y & x),
|
Opcode::And => self.push_data(y & x),
|
||||||
Opcode::Or => self.push_data(y | x),
|
Opcode::Or => self.push_data(y | x),
|
||||||
Opcode::Xor => 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>) {
|
pub fn interrupt(&mut self, irq: usize, arg: Option<Word>) {
|
||||||
if int >= self.iv.len() {
|
if irq >= self.iv.len() {
|
||||||
panic!("Invalid interrupt: {}", int)
|
panic!("Invalid interrupt: {}", irq)
|
||||||
}
|
}
|
||||||
if self.int_enabled {
|
if self.int_enabled {
|
||||||
if self.halted {
|
if self.halted {
|
||||||
@@ -429,7 +434,7 @@ impl CPU {
|
|||||||
if let Some(val) = arg {
|
if let Some(val) = arg {
|
||||||
self.push_data(val)
|
self.push_data(val)
|
||||||
}
|
}
|
||||||
self.iv[int]
|
self.iv[irq]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -472,6 +477,14 @@ impl CPU {
|
|||||||
pub fn sdp(&self) -> (Word, Word) {
|
pub fn sdp(&self) -> (Word, Word) {
|
||||||
(self.sp, self.dp)
|
(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)]
|
#[cfg(test)]
|
||||||
@@ -592,6 +605,7 @@ mod tests {
|
|||||||
simple_opcode_test(vec![5, 3], Mul, vec![15]);
|
simple_opcode_test(vec![5, 3], Mul, vec![15]);
|
||||||
simple_opcode_test(vec![8, 3], Div, vec![2]);
|
simple_opcode_test(vec![8, 3], Div, vec![2]);
|
||||||
simple_opcode_test(vec![10, 3], Mod, vec![1]);
|
simple_opcode_test(vec![10, 3], Mod, vec![1]);
|
||||||
|
simple_opcode_test(vec![12, to_word(-3)], Div, vec![to_word(-4)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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