Lua wrapper for CPU

This commit is contained in:
2022-05-16 12:57:38 -05:00
parent 4edad9c0cc
commit 3ca3a2eeac
6 changed files with 236 additions and 11 deletions
+1
View File
@@ -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
View File
@@ -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
View File
@@ -4,5 +4,6 @@ members = [
"vcore", "vcore",
"vemu", "vemu",
"vasm", "vasm",
"vtest" "vtest",
"vlua"
] ]
+24 -10
View File
@@ -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]
+13
View File
@@ -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
View File
@@ -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(())
});
}
}