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(()) + }); + } +}