diff --git a/.idea/vulcan-emu.iml b/.idea/vulcan-emu.iml
index a4bc6b2..6279895 100644
--- a/.idea/vulcan-emu.iml
+++ b/.idea/vulcan-emu.iml
@@ -7,6 +7,7 @@
+
diff --git a/Cargo.lock b/Cargo.lock
index e5b360f..68fc157 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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"
diff --git a/Cargo.toml b/Cargo.toml
index 14c1ea2..a13218a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,5 +4,6 @@ members = [
"vcore",
"vemu",
"vasm",
- "vtest"
+ "vtest",
+ "vlua"
]
\ No newline at end of file
diff --git a/vcore/src/cpu.rs b/vcore/src/cpu.rs
index 0d7ed2f..2a6e5f6 100644
--- a/vcore/src/cpu.rs
+++ b/vcore/src/cpu.rs
@@ -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>(&mut self, word: A) {
+ pub fn push_data>(&mut self, word: A) {
self.memory.poke24(self.dp, word);
self.dp += 3;
}
- fn push_call>(&mut self, word: A) {
+ pub fn push_call>(&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) {
- if int >= self.iv.len() {
- panic!("Invalid interrupt: {}", int)
+ pub fn interrupt(&mut self, irq: usize, arg: Option) {
+ 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]
diff --git a/vlua/Cargo.toml b/vlua/Cargo.toml
new file mode 100644
index 0000000..1a341b4
--- /dev/null
+++ b/vlua/Cargo.toml
@@ -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"] }
diff --git a/vlua/src/lib.rs b/vlua/src/lib.rs
new file mode 100644
index 0000000..0e8ed77
--- /dev/null
+++ b/vlua/src/lib.rs
@@ -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 {
+ 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!("")
+ } 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!("")
+ } 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)| {
+ lcpu.0.interrupt(irq as usize, arg.map(|n| Word::from(n)));
+ Ok(())
+ });
+ }
+}