From ca79642e433eec519e3e069ccd5aeab1a1c05ae3 Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Sat, 9 Dec 2023 13:12:38 -0600 Subject: [PATCH] Splitting vweb into multiple modules --- Cargo.lock | 1 + forge_core/src/compiler/ast_nodes/global.rs | 4 +- vweb/Cargo.toml | 1 + vweb/src/display.rs | 23 +++ vweb/src/error.rs | 31 ++++ vweb/src/lib.rs | 175 +------------------- vweb/src/nova_forth.rs | 16 ++ vweb/src/wasm_cpu.rs | 113 +++++++++++++ 8 files changed, 193 insertions(+), 171 deletions(-) create mode 100644 vweb/src/display.rs create mode 100644 vweb/src/error.rs create mode 100644 vweb/src/nova_forth.rs create mode 100644 vweb/src/wasm_cpu.rs diff --git a/Cargo.lock b/Cargo.lock index 43e9e05..dbd78d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1513,6 +1513,7 @@ dependencies = [ name = "vweb" version = "0.1.0" dependencies = [ + "forge_core", "serde", "serde-wasm-bindgen", "vasm_core", diff --git a/forge_core/src/compiler/ast_nodes/global.rs b/forge_core/src/compiler/ast_nodes/global.rs index 05c65e5..59aa85a 100644 --- a/forge_core/src/compiler/ast_nodes/global.rs +++ b/forge_core/src/compiler/ast_nodes/global.rs @@ -18,7 +18,7 @@ impl Compilable for Global { state.init.emit_arg("storew", label.clone()); } - state.add_global(&self.name, |s| Variable::IndirectLabel(label.clone())) + state.add_global(&self.name, |_| Variable::IndirectLabel(label.clone())) } } @@ -52,7 +52,7 @@ mod test { #[test] fn test_init() { - let mut state = state_for("global a = 5 + 3;"); + let state = state_for("global a = 5 + 3;"); assert_eq!( state.init.0.join("\n"), vec![ diff --git a/vweb/Cargo.toml b/vweb/Cargo.toml index 5cb5aea..0642808 100644 --- a/vweb/Cargo.toml +++ b/vweb/Cargo.toml @@ -12,6 +12,7 @@ crate-type = ["cdylib"] vcore = { path = "../vcore" } vgfx = { path = "../vgfx" } vasm_core = { path = "../vasm_core" } +forge_core = { path = "../forge_core" } wasm-bindgen = "0.2" serde = { version = "1.0", features = ["derive"] } serde-wasm-bindgen = "0.4" diff --git a/vweb/src/display.rs b/vweb/src/display.rs new file mode 100644 index 0000000..0d6d1a3 --- /dev/null +++ b/vweb/src/display.rs @@ -0,0 +1,23 @@ +use wasm_bindgen::{Clamped, JsValue}; +use wasm_bindgen::prelude::wasm_bindgen; +use web_sys::{CanvasRenderingContext2d, ImageData}; +use vgfx::display; +use crate::wasm_cpu::WasmCPU; + +// This has to contain a Box or else it'll use up all the wasm_bindgen stack space +#[wasm_bindgen] +pub struct Display(Box<[u8; 640 * 480 * 4]>); + +#[wasm_bindgen] +impl Display { + #[wasm_bindgen(constructor)] + pub fn new() -> Display { + Display([0u8; 640 * 480 * 4].into()) + } + + pub fn draw(&mut self, cpu: &WasmCPU, ctx: &CanvasRenderingContext2d) -> Result<(), JsValue> { + display::draw(cpu.cpu(), self.0.as_mut()); + let image_data = ImageData::new_with_u8_clamped_array(Clamped(self.0.as_mut()), 640)?; + ctx.put_image_data(&image_data, 0.0, 0.0) + } +} diff --git a/vweb/src/error.rs b/vweb/src/error.rs new file mode 100644 index 0000000..440b7b2 --- /dev/null +++ b/vweb/src/error.rs @@ -0,0 +1,31 @@ +use serde::{Deserialize, Serialize}; +use wasm_bindgen::prelude::wasm_bindgen; +use vasm_core::parse_error::AssembleError; + +#[wasm_bindgen(inspectable, getter_with_clone)] +#[derive(Serialize, Deserialize)] +pub struct JsVasmError { + pub line_number: usize, + pub message: String +} + +impl From for JsVasmError { + fn from(value: AssembleError) -> Self { + let line = match value.clone() { + AssembleError::ParseError(loc, _) => loc.line_num, + AssembleError::EquResolveError(loc, _, _) => loc.line_num, + AssembleError::EquDuplicateError(loc, _) => loc.line_num, + AssembleError::OrgResolveError(loc, _) => loc.line_num, + AssembleError::ArgError(loc, _) => loc.line_num, + AssembleError::NoCode => 0, + AssembleError::IncludeError(loc, _) => loc.line_num, + AssembleError::FileError(_) => 0, + AssembleError::MacroError(loc) => loc.line_num, + }; + + return JsVasmError { + line_number: line, + message: value.message() + } + } +} diff --git a/vweb/src/lib.rs b/vweb/src/lib.rs index 59ffb6e..c010c7e 100644 --- a/vweb/src/lib.rs +++ b/vweb/src/lib.rs @@ -1,61 +1,12 @@ +mod display; +mod wasm_cpu; +mod nova_forth; +mod error; + use wasm_bindgen::prelude::*; -use vcore::{CPU, Word}; use vcore::memory::{PeekPoke, PeekPokeExt}; -use vasm_core::parse_error::AssembleError; -use vgfx::display; use serde::{ Deserialize, Serialize }; -use wasm_bindgen::Clamped; -use web_sys::{CanvasRenderingContext2d, ImageData}; - -#[wasm_bindgen] -pub struct NovaForth; - -#[wasm_bindgen] -impl NovaForth { - pub fn rom() -> Vec { - Vec::from(*include_bytes!("../4th/4th.rom")) - } - - pub fn symbols() -> String { - include_str!("../4th/4th.rom.sym").into() - } - pub fn prelude() -> String { include_str!("../4th/prelude.f").into() } -} - -#[wasm_bindgen] -pub struct WasmCPU(CPU); - -// This has to contain a Box or else it'll use up all the wasm_bindgen stack space -#[wasm_bindgen] -pub struct Display(Box<[u8; 640 * 480 * 4]>); - -#[wasm_bindgen(inspectable, getter_with_clone)] -#[derive(Serialize, Deserialize)] -pub struct JsVasmError { - pub line_number: usize, - pub message: String -} - -impl From for JsVasmError { - fn from(value: AssembleError) -> Self { - let line = match value.clone() { - AssembleError::ParseError(loc, _) => loc.line_num, - AssembleError::EquResolveError(loc, _, _) => loc.line_num, - AssembleError::EquDuplicateError(loc, _) => loc.line_num, - AssembleError::OrgResolveError(loc, _) => loc.line_num, - AssembleError::ArgError(loc, _) => loc.line_num, - AssembleError::NoCode => 0, - AssembleError::IncludeError(loc, _) => loc.line_num, - AssembleError::FileError(_) => 0, - AssembleError::MacroError(loc) => loc.line_num, - }; - - return JsVasmError { - line_number: line, - message: value.message() - } - } -} +use crate::error::JsVasmError; #[wasm_bindgen] pub fn assemble_snippet(snippet: String) -> Result, JsVasmError> { @@ -67,117 +18,3 @@ pub fn source_map(snippet: String) -> JsValue { let source_map = vasm_core::snippet_source_map(snippet.lines().map(String::from)).map_err(|err| JsVasmError::from(err)); serde_wasm_bindgen::to_value(&source_map).unwrap() } - -#[wasm_bindgen] -impl WasmCPU { - #[wasm_bindgen(constructor)] - pub fn new() -> WasmCPU { - let mut cpu = CPU::new_random(); - display::init_gfx(&mut cpu); - WasmCPU(cpu) - } - - pub fn push_data(&mut self, data: i32) { - self.0.push_data(data) - } - - pub fn pop_data(&mut self) -> i32 { - self.0.pop_data().into() - } - - pub fn push_call(&mut self, data: i32) { - self.0.push_call(data) - } - - pub fn pop_call(&mut self) -> i32 { - self.0.pop_call().into() - } - - pub fn poke(&mut self, addr: u32, val: u8) { - self.0.poke(addr.into(), val.into()) - } - - pub fn peek(&self, addr: u32) -> u8 { - self.0.peek(addr.into()).into() - } - - pub fn poke24(&mut self, addr: u32, val: i32) { - self.0.poke24(Word::from(addr), Word::from(val)) - } - - pub fn peek24(&self, addr: u32) -> i32 { - self.0.peek24(Word::from(addr)).into() - } - - pub fn pc(&self) -> u32 { - self.0.pc().into() - } - - pub fn sp(&self) -> u32 { - self.0.sp().into() - } - - pub fn dp(&self) -> u32 { - self.0.dp().into() - } - - pub fn halted(&self) -> bool { self.0.halted() } - - pub fn get_stack(&self) -> Vec { - self.0.get_stack().into_iter().map(i32::from).collect() - } - - pub fn get_call(&self) -> Vec { - self.0.get_call().into_iter().map(i32::from).collect() - } - - pub fn set_pc(&mut self, val: u32) { - self.0.set_pc(Word::from(val)) - } - - pub fn run(&mut self) { - self.0.run_to_halt() - } - - pub fn safe_run(&mut self, max_ticks: usize) { - let mut current = 0; - while !self.0.halted() && current < max_ticks { - current += 1; - self.tick() - } - } - - pub fn load(&mut self, rom: Vec) { - for (i, b) in rom.iter().enumerate() { - self.poke(0x400 + i as u32, *b) - } - - self.set_pc(0x400) - } - - pub fn reset(&mut self) { - self.0.reset() - } - - pub fn start(&mut self) { - self.0.start() - } - - pub fn tick(&mut self) { - self.0.tick() - } -} - -#[wasm_bindgen] -impl Display { - #[wasm_bindgen(constructor)] - pub fn new() -> Display { - Display([0u8; 640 * 480 * 4].into()) - } - - pub fn draw(&mut self, cpu: &WasmCPU, ctx: &CanvasRenderingContext2d) -> Result<(), JsValue> { - display::draw(&cpu.0, self.0.as_mut()); - let image_data = ImageData::new_with_u8_clamped_array(Clamped(self.0.as_mut()), 640)?; - ctx.put_image_data(&image_data, 0.0, 0.0) - } -} \ No newline at end of file diff --git a/vweb/src/nova_forth.rs b/vweb/src/nova_forth.rs new file mode 100644 index 0000000..cf2d14f --- /dev/null +++ b/vweb/src/nova_forth.rs @@ -0,0 +1,16 @@ +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct NovaForth; + +#[wasm_bindgen] +impl NovaForth { + pub fn rom() -> Vec { + Vec::from(*include_bytes!("../4th/4th.rom")) + } + + pub fn symbols() -> String { + include_str!("../4th/4th.rom.sym").into() + } + pub fn prelude() -> String { include_str!("../4th/prelude.f").into() } +} diff --git a/vweb/src/wasm_cpu.rs b/vweb/src/wasm_cpu.rs new file mode 100644 index 0000000..6cb0286 --- /dev/null +++ b/vweb/src/wasm_cpu.rs @@ -0,0 +1,113 @@ +use wasm_bindgen::prelude::wasm_bindgen; +use vcore::{CPU, Word}; +use vcore::memory::{PeekPoke, PeekPokeExt}; +use vgfx::display; + +#[wasm_bindgen] +pub struct WasmCPU(CPU); + +#[wasm_bindgen] +impl WasmCPU { + #[wasm_bindgen(constructor)] + pub fn new() -> WasmCPU { + let mut cpu = CPU::new_random(); + display::init_gfx(&mut cpu); + WasmCPU(cpu) + } + + pub fn push_data(&mut self, data: i32) { + self.0.push_data(data) + } + + pub fn pop_data(&mut self) -> i32 { + self.0.pop_data().into() + } + + pub fn push_call(&mut self, data: i32) { + self.0.push_call(data) + } + + pub fn pop_call(&mut self) -> i32 { + self.0.pop_call().into() + } + + pub fn poke(&mut self, addr: u32, val: u8) { + self.0.poke(addr.into(), val.into()) + } + + pub fn peek(&self, addr: u32) -> u8 { + self.0.peek(addr.into()).into() + } + + pub fn poke24(&mut self, addr: u32, val: i32) { + self.0.poke24(Word::from(addr), Word::from(val)) + } + + pub fn peek24(&self, addr: u32) -> i32 { + self.0.peek24(Word::from(addr)).into() + } + + pub fn pc(&self) -> u32 { + self.0.pc().into() + } + + pub fn sp(&self) -> u32 { + self.0.sp().into() + } + + pub fn dp(&self) -> u32 { + self.0.dp().into() + } + + pub fn halted(&self) -> bool { self.0.halted() } + + pub fn get_stack(&self) -> Vec { + self.0.get_stack().into_iter().map(i32::from).collect() + } + + pub fn get_call(&self) -> Vec { + self.0.get_call().into_iter().map(i32::from).collect() + } + + pub fn set_pc(&mut self, val: u32) { + self.0.set_pc(Word::from(val)) + } + + pub fn run(&mut self) { + self.0.run_to_halt() + } + + pub fn safe_run(&mut self, max_ticks: usize) { + let mut current = 0; + while !self.0.halted() && current < max_ticks { + current += 1; + self.tick() + } + } + + pub fn load(&mut self, rom: Vec) { + for (i, b) in rom.iter().enumerate() { + self.poke(0x400 + i as u32, *b) + } + + self.set_pc(0x400) + } + + pub fn reset(&mut self) { + self.0.reset() + } + + pub fn start(&mut self) { + self.0.start() + } + + pub fn tick(&mut self) { + self.0.tick() + } +} + +impl WasmCPU { + pub fn cpu(&self) -> &CPU { + &self.0 + } +} \ No newline at end of file