diff --git a/Cargo.lock b/Cargo.lock index 4cd6d8ea..abe9a78e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" + [[package]] name = "cfg-if" version = "1.0.0" @@ -23,6 +29,12 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" name = "compiler" version = "0.1.0" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "hashbrown" version = "0.13.2" @@ -32,11 +44,25 @@ dependencies = [ "ahash", ] +[[package]] +name = "hbasm" +version = "0.1.0" +dependencies = [ + "hbbytecode", + "logos", + "paste", +] + +[[package]] +name = "hbbytecode" +version = "0.1.0" + [[package]] name = "hbvm" version = "0.1.0" dependencies = [ "hashbrown", + "hbbytecode", "log", "static_assertions", ] @@ -50,18 +76,97 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "logos" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1" +dependencies = [ + "logos-derive", +] + +[[package]] +name = "logos-codegen" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" +dependencies = [ + "beef", + "fnv", + "proc-macro2", + "quote", + "regex-syntax", + "syn", +] + +[[package]] +name = "logos-derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e" +dependencies = [ + "logos-codegen", +] + [[package]] name = "once_cell" version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + +[[package]] +name = "proc-macro2" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index 2d921c2b..6903387d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["hbvm", "compiler"] +members = ["hbasm", "hbbytecode", "hbvm", "compiler"] diff --git a/hbasm/Cargo.toml b/hbasm/Cargo.toml new file mode 100644 index 00000000..c9add3ca --- /dev/null +++ b/hbasm/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "hbasm" +version = "0.1.0" +edition = "2021" + +[dependencies] +hbbytecode = { path = "../hbbytecode" } +paste = "1.0" + +[dependencies.logos] +version = "0.13" +default-features = false +features = ["export_derive"] diff --git a/hbasm/src/lib.rs b/hbasm/src/lib.rs new file mode 100644 index 00000000..c73feff8 --- /dev/null +++ b/hbasm/src/lib.rs @@ -0,0 +1,182 @@ +use { + logos::{Lexer, Logos, Span}, + std::{ops::Range, str::FromStr}, +}; + +macro_rules! tokendef { + ($($opcode:literal),* $(,)?) => { + paste::paste! { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Logos)] + #[logos(skip r"[ \t\f]+")] + pub enum Token { + $(#[token($opcode, |_| hbbytecode::opcode::[<$opcode:upper>])])* + OpCode(u8), + + #[regex("[0-9]+", |l| l.slice().parse().ok())] + #[regex( + "-[0-9]+", + |lexer| { + Some(u64::from_ne_bytes(lexer.slice().parse::().ok()?.to_ne_bytes())) + }, + )] Integer(u64), + + #[regex( + "r[0-9]+", + |lexer| match lexer.slice()[1..].parse() { + Ok(n) if n <= 59 => Some(n), + _ => None + }, + )] Register(u8), + + #[token("\n")] + #[token(";")] ISep, + + #[token(",")] PSep, + } + } + }; +} + +#[rustfmt::skip] +tokendef![ + "nop", "add", "sub", "mul", "rem", "and", "or", "xor", "not", + "addf", "subf", "mulf", "divf", "cp", "li", "lb", "ld", "lq", + "lo", "sb", "sd", "sq", "so", "pagemap", "pageunmap", "pagemp", + "jmp", "jmpcond", "ret", "ecall", +]; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ErrorKind { + UnexpectedToken, + InvalidToken, + UnexpectedEnd, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Error { + kind: ErrorKind, + span: Span, +} + +macro_rules! expect_matches { + ($self:expr, $($pat:pat),* $(,)?) => {$( + let $pat = $self.next()? + else { return Err(ErrorKind::UnexpectedToken) }; + )*} +} + +pub fn assembly(code: &str, buf: &mut Vec) -> Result<(), Error> { + struct Assembler<'a> { + lexer: Lexer<'a, Token>, + buf: &'a mut Vec, + } + + impl<'a> Assembler<'a> { + fn next(&mut self) -> Result { + match self.lexer.next() { + Some(Ok(t)) => Ok(t), + Some(Err(())) => Err(ErrorKind::InvalidToken), + None => Err(ErrorKind::UnexpectedEnd), + } + } + + fn assemble(&mut self) -> Result<(), ErrorKind> { + use hbbytecode::opcode::*; + loop { + match self.lexer.next() { + Some(Ok(Token::OpCode(op))) => { + self.buf.push(op); + match op { + NOP | RET | ECALL => Ok(()), + ADD..=XOR | ADDF..=DIVF => self.rrr(), + NOT | CP => self.rr(), + LI => self.ri(), + LB..=SO => self.rri(), + JMP => self.i(), + _ => unreachable!(), + }?; + match self.next() { + Ok(Token::ISep) => (), + Ok(_) => return Err(ErrorKind::UnexpectedToken), + Err(ErrorKind::UnexpectedEnd) => return Ok(()), + Err(e) => return Err(e), + } + } + Some(Ok(_)) => return Err(ErrorKind::UnexpectedToken), + Some(Err(())) => return Err(ErrorKind::InvalidToken), + None => return Ok(()), + } + } + } + + fn rrr(&mut self) -> Result<(), ErrorKind> { + expect_matches!( + self, + Token::Register(r0), + Token::PSep, + Token::Register(r1), + Token::PSep, + Token::Register(r2) + ); + self.buf.extend([r0, r1, r2]); + Ok(()) + } + + fn rr(&mut self) -> Result<(), ErrorKind> { + expect_matches!( + self, + Token::Register(r0), + Token::PSep, + Token::Register(r1), + ); + self.buf.extend([r0, r1]); + Ok(()) + } + + fn ri(&mut self) -> Result<(), ErrorKind> { + expect_matches!( + self, + Token::Register(r0), + Token::PSep, + Token::Integer(r1), + ); + + self.buf.push(r0); + self.buf.extend(r1.to_le_bytes()); + Ok(()) + } + + fn rri(&mut self) -> Result<(), ErrorKind> { + expect_matches!( + self, + Token::Register(r0), + Token::PSep, + Token::Register(r1), + Token::PSep, + Token::Integer(imm), + ); + self.buf.extend([r0, r1]); + self.buf.extend(imm.to_le_bytes()); + Ok(()) + } + + fn i(&mut self) -> Result<(), ErrorKind> { + expect_matches!( + self, + Token::Integer(imm), + ); + self.buf.extend(imm.to_le_bytes()); + Ok(()) + } + } + + let mut asm = Assembler { + lexer: Token::lexer(code), + buf, + }; + + asm.assemble().map_err(|kind| Error { + kind, + span: asm.lexer.span() + }) +} diff --git a/hbasm/src/main.rs b/hbasm/src/main.rs new file mode 100644 index 00000000..171cfe28 --- /dev/null +++ b/hbasm/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + // TODO +} diff --git a/hbbytecode/Cargo.toml b/hbbytecode/Cargo.toml new file mode 100644 index 00000000..fa9f9707 --- /dev/null +++ b/hbbytecode/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hbbytecode" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/hbvm/src/bytecode.rs b/hbbytecode/src/lib.rs similarity index 90% rename from hbvm/src/bytecode.rs rename to hbbytecode/src/lib.rs index 3c2014f3..dd1552f7 100644 --- a/hbvm/src/bytecode.rs +++ b/hbbytecode/src/lib.rs @@ -1,4 +1,4 @@ -pub const REG_COUNT: usize = 60; +#![no_std] macro_rules! constmod { ($vis:vis $mname:ident($repr:ty) { $($cname:ident = $val:expr),* $(,)? }) => { @@ -43,10 +43,10 @@ constmod!(pub opcode(u8) { PAGEUNMAP = 25, // ?; Unmap a page PAGEMP = 26, // ?; Page modify protection flags - JMP = 100, // I; Unconditional jump - JMPCOND = 101, // ?; Conditional jump - RET = 103, // N; Return - ECALL = 255, // N; Issue system call + JMP = 27, // I; Unconditional jump + JMPCOND = 28, // ?; Conditional jump + RET = 29, // N; Return + ECALL = 30, // N; Issue system call }); #[repr(packed)] pub struct ParamRRR(pub u8, pub u8, pub u8); diff --git a/hbvm/Cargo.toml b/hbvm/Cargo.toml index 5c0f1dc0..be2d47a0 100644 --- a/hbvm/Cargo.toml +++ b/hbvm/Cargo.toml @@ -10,3 +10,4 @@ lto = true log = "*" hashbrown = "0.13.2" static_assertions = "1.0" +hbbytecode = { path = "../hbbytecode" } diff --git a/hbvm/src/lib.rs b/hbvm/src/lib.rs index ffdbdbc3..013fdb24 100644 --- a/hbvm/src/lib.rs +++ b/hbvm/src/lib.rs @@ -1,7 +1,6 @@ #![no_std] extern crate alloc; -pub mod bytecode; pub mod validate; pub mod vm; diff --git a/hbvm/src/validate.rs b/hbvm/src/validate.rs index 7a1c2675..086a4dc0 100644 --- a/hbvm/src/validate.rs +++ b/hbvm/src/validate.rs @@ -24,7 +24,7 @@ pub struct Error { } pub fn validate(mut program: &[u8]) -> Result<(), Error> { - use crate::bytecode::opcode::*; + use hbbytecode::opcode::*; #[inline] fn reg(regs: &[u8]) -> Option { diff --git a/hbvm/src/vm/mod.rs b/hbvm/src/vm/mod.rs index 57db9f57..67654ac4 100644 --- a/hbvm/src/vm/mod.rs +++ b/hbvm/src/vm/mod.rs @@ -3,8 +3,8 @@ use crate::validate; mod value; use { - crate::bytecode::{OpParam, ParamRI, ParamRR, ParamRRR}, core::ops, + hbbytecode::{OpParam, ParamRI, ParamRR, ParamRRR}, static_assertions::assert_impl_one, value::Value, }; @@ -51,7 +51,7 @@ impl<'a> Vm<'a> { } pub fn run(&mut self) { - use crate::bytecode::opcode::*; + use hbbytecode::opcode::*; loop { let Some(&opcode) = self.program.get(self.pc) else { return };